]> Pileus Git - ~andy/linux/commitdiff
Merge master.kernel.org:/home/rmk/linux-2.6-mmc
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 9 Jan 2006 23:08:33 +0000 (15:08 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 9 Jan 2006 23:08:33 +0000 (15:08 -0800)
1128 files changed:
CREDITS
Documentation/Changes
Documentation/CodingStyle
Documentation/RCU/rcuref.txt
Documentation/SubmittingDrivers
Documentation/SubmittingPatches
Documentation/applying-patches.txt
Documentation/block/stat.txt [new file with mode: 0644]
Documentation/cpu-hotplug.txt [new file with mode: 0644]
Documentation/cpusets.txt
Documentation/dvb/avermedia.txt
Documentation/dvb/get_dvb_firmware
Documentation/dvb/ttusb-dec.txt
Documentation/fb/cyblafb/bugs
Documentation/fb/cyblafb/fb.modes
Documentation/fb/cyblafb/performance
Documentation/fb/cyblafb/todo
Documentation/fb/cyblafb/usage
Documentation/fb/cyblafb/whatsnew [new file with mode: 0644]
Documentation/filesystems/ext3.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/ramfs-rootfs-initramfs.txt
Documentation/filesystems/relayfs.txt
Documentation/filesystems/spufs.txt [new file with mode: 0644]
Documentation/keys-request-key.txt
Documentation/keys.txt
Documentation/kprobes.txt
Documentation/networking/bonding.txt
Documentation/powerpc/00-INDEX
Documentation/sysctl/vm.txt
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
MAINTAINERS
README
arch/alpha/Kconfig
arch/alpha/kernel/process.c
arch/alpha/kernel/ptrace.c
arch/arm/Kconfig
arch/arm/common/scoop.c
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/irq.c
arch/arm/mach-footbridge/netwinder-hw.c
arch/arm/mach-integrator/time.c
arch/arm/mach-omap1/serial.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-realview/localtimer.c
arch/arm/mach-s3c2410/usb-simtec.c
arch/arm26/Kconfig
arch/arm26/kernel/asm-offsets.c
arch/cris/Kconfig
arch/frv/Kconfig
arch/frv/Kconfig.debug
arch/frv/Makefile
arch/frv/kernel/Makefile
arch/frv/kernel/frv_ksyms.c
arch/frv/kernel/irq.c
arch/frv/kernel/module.c [new file with mode: 0644]
arch/frv/kernel/pm.c
arch/frv/kernel/setup.c
arch/frv/kernel/time.c
arch/frv/kernel/traps.c
arch/frv/kernel/uaccess.c
arch/frv/kernel/vmlinux.lds.S
arch/frv/lib/Makefile
arch/frv/lib/__ucmpdi2.S [new file with mode: 0644]
arch/frv/lib/atomic-ops.S
arch/frv/lib/checksum.c
arch/frv/mb93090-mb00/Makefile
arch/frv/mb93090-mb00/pci-dma-nommu.c
arch/frv/mb93090-mb00/pci-dma.c
arch/frv/mb93090-mb00/pci-iomap.c [new file with mode: 0644]
arch/frv/mm/cache-page.c
arch/frv/mm/extable.c
arch/frv/mm/highmem.c
arch/h8300/Kconfig
arch/i386/Kconfig
arch/i386/Makefile
arch/i386/Makefile.cpu
arch/i386/boot/compressed/misc.c
arch/i386/kernel/Makefile
arch/i386/kernel/apm.c
arch/i386/kernel/cpu/common.c
arch/i386/kernel/entry.S
arch/i386/kernel/init_task.c
arch/i386/kernel/irq.c
arch/i386/kernel/process.c
arch/i386/kernel/syscall_table.S
arch/i386/kernel/time_hpet.c
arch/ia64/Makefile
arch/ia64/ia32/sys_ia32.c
arch/ia64/kernel/efi.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/head.S
arch/ia64/kernel/ia64_ksyms.c
arch/ia64/kernel/ptrace.c
arch/ia64/oprofile/backtrace.c
arch/m32r/kernel/process.c
arch/m32r/kernel/ptrace.c
arch/m68k/Kconfig
arch/m68knommu/Kconfig
arch/mips/kernel/ptrace32.c
arch/mips/kernel/vpe.c
arch/mips/sgi-ip27/ip27-berr.c
arch/parisc/Kconfig
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/configs/pmac32_defconfig [new file with mode: 0644]
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/btext.c
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/crash.c [new file with mode: 0644]
arch/powerpc/kernel/crash_dump.c [new file with mode: 0644]
arch/powerpc/kernel/dma_64.c
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/ibmebus.c [new file with mode: 0644]
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/legacy_serial.c [new file with mode: 0644]
arch/powerpc/kernel/lparmap.c
arch/powerpc/kernel/machine_kexec.c [new file with mode: 0644]
arch/powerpc/kernel/machine_kexec_32.c [new file with mode: 0644]
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/nvram_64.c
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/pmc.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/prom_parse.c [new file with mode: 0644]
arch/powerpc/kernel/ptrace32.c
arch/powerpc/kernel/rtas_pci.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/syscalls.c
arch/powerpc/kernel/systbl.S
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/udbg.c
arch/powerpc/kernel/udbg_16550.c
arch/powerpc/mm/fault.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/imalloc.c
arch/powerpc/mm/init_32.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/slb.c
arch/powerpc/mm/slb_low.S
arch/powerpc/mm/stab.c
arch/powerpc/mm/tlb_64.c
arch/powerpc/oprofile/Makefile
arch/powerpc/oprofile/common.c
arch/powerpc/oprofile/op_model_7450.c [new file with mode: 0644]
arch/powerpc/oprofile/op_model_power4.c
arch/powerpc/oprofile/op_model_rs64.c
arch/powerpc/platforms/cell/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/cell/Makefile
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/interrupt.h
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/pervasive.c [new file with mode: 0644]
arch/powerpc/platforms/cell/pervasive.h [new file with mode: 0644]
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/cell/spu_base.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spu_priv1.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spu_syscalls.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/Makefile [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/backing_ops.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/context.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/file.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/hw_ops.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/inode.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/run.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/sched.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/spu_restore.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/spu_save.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/spu_save_crt0.S [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/spu_utils.h [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/spufs.h [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/switch.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/syscalls.c [new file with mode: 0644]
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/iseries/irq.h
arch/powerpc/platforms/iseries/lpardata.c
arch/powerpc/platforms/iseries/setup.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/powermac/Makefile
arch/powerpc/platforms/powermac/bootx_init.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/cpufreq_64.c
arch/powerpc/platforms/powermac/feature.c
arch/powerpc/platforms/powermac/low_i2c.c
arch/powerpc/platforms/powermac/nvram.c
arch/powerpc/platforms/powermac/pci.c
arch/powerpc/platforms/powermac/pfunc_base.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/pfunc_core.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/pmac.h
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/powermac/time.c
arch/powerpc/platforms/powermac/udbg_adb.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/udbg_scc.c [moved from arch/powerpc/kernel/udbg_scc.c with 66% similarity]
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/pci_dlpar.c [new file with mode: 0644]
arch/powerpc/platforms/pseries/ras.c
arch/powerpc/platforms/pseries/ras.h [new file with mode: 0644]
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/dart.h
arch/powerpc/sysdev/dart_iommu.c [moved from arch/powerpc/sysdev/u3_iommu.c with 65% similarity]
arch/powerpc/sysdev/ipic.c [moved from arch/ppc/syslib/ipic.c with 100% similarity]
arch/powerpc/sysdev/ipic.h [moved from arch/ppc/syslib/ipic.h with 100% similarity]
arch/powerpc/sysdev/mpic.c
arch/powerpc/xmon/Makefile
arch/powerpc/xmon/start.c [moved from arch/powerpc/xmon/start_64.c with 100% similarity]
arch/powerpc/xmon/start_32.c [deleted file]
arch/powerpc/xmon/start_8xx.c [deleted file]
arch/powerpc/xmon/xmon.c
arch/ppc/Kconfig
arch/ppc/boot/common/util.S
arch/ppc/boot/images/Makefile
arch/ppc/configs/TQM8540_defconfig [new file with mode: 0644]
arch/ppc/configs/TQM8541_defconfig [new file with mode: 0644]
arch/ppc/configs/TQM8555_defconfig [new file with mode: 0644]
arch/ppc/configs/TQM8560_defconfig [new file with mode: 0644]
arch/ppc/kernel/Makefile
arch/ppc/kernel/asm-offsets.c
arch/ppc/kernel/entry.S
arch/ppc/kernel/misc.S
arch/ppc/kernel/pci.c
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/setup.c
arch/ppc/platforms/85xx/Kconfig
arch/ppc/platforms/85xx/Makefile
arch/ppc/platforms/85xx/tqm85xx.c [new file with mode: 0644]
arch/ppc/platforms/85xx/tqm85xx.h [new file with mode: 0644]
arch/ppc/platforms/chrp_setup.c
arch/ppc/platforms/prep_setup.c
arch/ppc/syslib/Makefile
arch/ppc/syslib/m8xx_setup.c
arch/ppc/syslib/m8xx_wdt.c
arch/ppc/syslib/m8xx_wdt.h
arch/s390/kernel/ptrace.c
arch/sh/Kconfig
arch/sh64/kernel/time.c
arch/sparc/Kconfig
arch/sparc/kernel/ptrace.c
arch/sparc64/Kconfig
arch/sparc64/kernel/ptrace.c
arch/um/Kconfig
arch/um/drivers/ubd_kern.c
arch/um/include/kern_util.h
arch/um/include/os.h
arch/um/include/signal_user.h [deleted file]
arch/um/include/user_util.h
arch/um/kernel/Makefile
arch/um/kernel/irq_user.c
arch/um/kernel/process_kern.c
arch/um/kernel/reboot.c
arch/um/kernel/signal_kern.c
arch/um/kernel/signal_user.c [deleted file]
arch/um/kernel/skas/Makefile
arch/um/kernel/skas/include/skas.h
arch/um/kernel/skas/process.c
arch/um/kernel/skas/process_kern.c
arch/um/kernel/time.c
arch/um/kernel/trap_kern.c
arch/um/kernel/trap_user.c [deleted file]
arch/um/kernel/tt/exec_kern.c
arch/um/kernel/tt/process_kern.c
arch/um/kernel/tt/tracer.c
arch/um/kernel/tt/trap_user.c
arch/um/kernel/um_arch.c
arch/um/os-Linux/Makefile
arch/um/os-Linux/main.c
arch/um/os-Linux/process.c
arch/um/os-Linux/signal.c
arch/um/os-Linux/skas/Makefile [new file with mode: 0644]
arch/um/os-Linux/skas/trap.c [moved from arch/um/kernel/skas/trap_user.c with 53% similarity]
arch/um/os-Linux/start_up.c
arch/um/os-Linux/trap.c [new file with mode: 0644]
arch/um/os-Linux/tt.c
arch/um/sys-i386/signal.c
arch/v850/Kconfig
arch/x86_64/Kconfig
arch/x86_64/boot/compressed/misc.c
arch/x86_64/boot/compressed/miscsetup.h [deleted file]
arch/x86_64/ia32/ia32entry.S
arch/x86_64/ia32/ptrace32.c
arch/x86_64/kernel/init_task.c
arch/x86_64/kernel/time.c
block/elevator.c
block/ioctl.c
block/ll_rw_blk.c
block/scsi_ioctl.c
drivers/acorn/block/mfmhd.c
drivers/acpi/osl.c
drivers/atm/nicstar.c
drivers/block/DAC960.c
drivers/block/acsi.c
drivers/block/amiflop.c
drivers/block/aoe/aoeblk.c
drivers/block/ataflop.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_scsi.c
drivers/block/cpqarray.c
drivers/block/floppy.c
drivers/block/nbd.c
drivers/block/paride/pd.c
drivers/block/paride/pf.c
drivers/block/pktcdvd.c
drivers/block/ps2esdi.c
drivers/block/swim3.c
drivers/block/sx8.c
drivers/block/umem.c
drivers/block/viodasd.c
drivers/block/xd.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/agp/sworks-agp.c
drivers/char/hw_random.c
drivers/char/mem.c
drivers/char/sonypi.c
drivers/char/synclink_gt.c [new file with mode: 0644]
drivers/char/tpm/Makefile
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_bios.c [new file with mode: 0644]
drivers/char/vr41xx_giu.c
drivers/char/watchdog/mpc8xx_wdt.c
drivers/char/watchdog/wdt977.c
drivers/connector/cn_proc.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-keywest.c [deleted file]
drivers/i2c/busses/i2c-keywest.h [deleted file]
drivers/i2c/busses/i2c-pmac-smu.c [deleted file]
drivers/i2c/busses/i2c-powermac.c [new file with mode: 0644]
drivers/i2c/chips/tps65010.c
drivers/ide/ide-cd.c
drivers/ide/ide-disk.c
drivers/ide/ide-floppy.c
drivers/ide/ide-io.c
drivers/ide/ide-probe.c
drivers/ide/ide.c
drivers/ide/legacy/hd.c
drivers/ide/pci/serverworks.c
drivers/ide/ppc/pmac.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/mthca/mthca_cmd.c
drivers/infiniband/hw/mthca/mthca_cq.c
drivers/infiniband/hw/mthca/mthca_dev.h
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/mthca/mthca_mcg.c
drivers/infiniband/hw/mthca/mthca_memfree.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/keyboard/corgikbd.c
drivers/input/keyboard/spitzkbd.c
drivers/input/misc/hp_sdc_rtc.c
drivers/isdn/act2000/act2000.h
drivers/isdn/act2000/capi.h
drivers/isdn/capi/capifs.c
drivers/isdn/hardware/eicon/os_4bri.c
drivers/isdn/hardware/eicon/os_bri.c
drivers/isdn/hardware/eicon/os_pri.c
drivers/isdn/hisax/Kconfig
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hisax_fcpcipnp.h
drivers/isdn/sc/command.c
drivers/macintosh/Kconfig
drivers/macintosh/macio_asic.c
drivers/macintosh/mediabay.c
drivers/macintosh/smu.c
drivers/macintosh/via-cuda.c
drivers/macintosh/via-pmu.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_smu_controls.c
drivers/macintosh/windfarm_smu_sensors.c
drivers/md/md.c
drivers/md/raid0.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_hlp.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-reg.h
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dst_ca.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/cinergyT2/Kconfig
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-core/Kconfig
drivers/media/dvb/dvb-core/Makefile
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_filter.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvb_ringbuffer.c
drivers/media/dvb/dvb-core/dvb_ringbuffer.h
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/cxusb.h
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u.c
drivers/media/dvb/dvb-usb/dtt200u.h
drivers/media/dvb/dvb-usb/dvb-usb-common.h
drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
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-init.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/vp702x-fe.c
drivers/media/dvb/dvb-usb/vp702x.h
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/bcm3510.c
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx24110.c
drivers/media/dvb/frontends/cx24123.c [new file with mode: 0644]
drivers/media/dvb/frontends/cx24123.h [new file with mode: 0644]
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/lgdt330x.c
drivers/media/dvb/frontends/mt312.c
drivers/media/dvb/frontends/nxt2002.c
drivers/media/dvb/frontends/nxt6000.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/sp8870.c
drivers/media/dvb/frontends/sp887x.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/stv0299.h
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/pluto2/Kconfig
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_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-core.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttpci/ttpci-eeprom.c
drivers/media/dvb/ttusb-budget/Kconfig
drivers/media/dvb/ttusb-dec/Kconfig
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/dvb/ttusb-dec/ttusbdecfe.c
drivers/media/radio/miropcm20-radio.c
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-maestro.c
drivers/media/radio/radio-maxiradio.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/radio/radio-zoltrix.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/bt832.c
drivers/media/video/bttv-cards.c
drivers/media/video/bttv-driver.c
drivers/media/video/bttv-gpio.c
drivers/media/video/bttv-i2c.c
drivers/media/video/bttv-input.c [moved from drivers/media/video/ir-kbd-gpio.c with 73% similarity]
drivers/media/video/bttv-vbi.c
drivers/media/video/bttv.h
drivers/media/video/bttvp.h
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/compat_ioctl32.c [new file with mode: 0644]
drivers/media/video/cpia.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-firmware.c
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx25840/cx25840.h
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/Makefile
drivers/media/video/cx88/cx88-alsa.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.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-tvaudio.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88-vp3054-i2c.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-vp3054-i2c.h [new file with mode: 0644]
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/meye.c
drivers/media/video/msp3400-driver.c [new file with mode: 0644]
drivers/media/video/msp3400-kthreads.c [new file with mode: 0644]
drivers/media/video/msp3400.c [deleted file]
drivers/media/video/msp3400.h
drivers/media/video/mt20xx.c
drivers/media/video/mxb.c
drivers/media/video/pms.c
drivers/media/video/saa5249.c
drivers/media/video/saa6588.c
drivers/media/video/saa7115.c
drivers/media/video/saa711x.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-oss.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/stradis.c
drivers/media/video/tda7432.c
drivers/media/video/tda8290.c
drivers/media/video/tda9875.c
drivers/media/video/tda9887.c
drivers/media/video/tea5767.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-simple.c
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/tvmixer.c
drivers/media/video/tvp5150.c
drivers/media/video/v4l1-compat.c
drivers/media/video/v4l2-common.c
drivers/media/video/videodev.c
drivers/media/video/w9966.c
drivers/media/video/wm8775.c
drivers/media/video/zoran_driver.c
drivers/media/video/zr36120.c
drivers/message/i2o/i2o_block.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/ucb1x00-ts.c
drivers/mmc/mmc_block.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/onenand/generic.c
drivers/mtd/rfd_ftl.c
drivers/net/3c503.c
drivers/net/3c527.h
drivers/net/Kconfig
drivers/net/ac3200.c
drivers/net/bonding/bonding.h
drivers/net/cs89x0.c
drivers/net/cs89x0.h
drivers/net/e1000/e1000_param.c
drivers/net/e2100.c
drivers/net/es3210.c
drivers/net/forcedeth.c
drivers/net/gianfar.h
drivers/net/hamradio/mkiss.c
drivers/net/hp-plus.c
drivers/net/hp.c
drivers/net/ibm_emac/ibm_emac.h
drivers/net/ibm_emac/ibm_emac_core.c
drivers/net/irda/vlsi_ir.h
drivers/net/lance.c
drivers/net/lne390.c
drivers/net/mv643xx_eth.c
drivers/net/ne.c
drivers/net/ne2.c
drivers/net/sk98lin/skge.c
drivers/net/smc-ultra.c
drivers/net/smc91x.c
drivers/net/smc91x.h
drivers/net/tulip/tulip_core.c
drivers/net/wan/sdla.c
drivers/net/wd.c
drivers/net/wireless/ipw2100.c
drivers/oprofile/buffer_sync.c
drivers/oprofile/cpu_buffer.c
drivers/parport/Kconfig
drivers/parport/parport_pc.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_hpc.c
drivers/rapidio/rio-scan.c
drivers/rapidio/rio-sysfs.c
drivers/rapidio/rio.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/xpram.c
drivers/scsi/mac53c94.c
drivers/scsi/mesh.c
drivers/scsi/sata_nv.c
drivers/scsi/scsi.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/pmac_zilog.c
drivers/usb/core/inode.c
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/ohci-lh7a404.c
drivers/usb/host/ohci-ppc-soc.c
drivers/usb/media/dsbr100.c
drivers/usb/media/ov511.c
drivers/usb/media/pwc/pwc-if.c
drivers/usb/media/se401.c
drivers/usb/media/stv680.c
drivers/usb/media/usbvideo.c
drivers/usb/media/vicam.c
drivers/usb/media/w9968cf.c
drivers/video/Kconfig
drivers/video/console/Kconfig
drivers/video/console/vgacon.c
drivers/video/controlfb.c
drivers/video/cyblafb.c
drivers/video/offb.c
drivers/video/platinumfb.c
drivers/video/platinumfb.h
drivers/video/valkyriefb.c
fs/9p/9p.c
fs/9p/9p.h
fs/9p/Makefile
fs/9p/conv.c
fs/9p/conv.h
fs/9p/debug.h
fs/9p/error.c
fs/9p/error.h
fs/9p/fid.c
fs/9p/mux.c
fs/9p/mux.h
fs/9p/trans_fd.c
fs/9p/trans_sock.c
fs/9p/transport.h
fs/9p/v9fs.c
fs/9p/v9fs.h
fs/9p/v9fs_vfs.h
fs/9p/vfs_dentry.c
fs/9p/vfs_dir.c
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/Kconfig.binfmt
fs/Makefile
fs/afs/dir.c
fs/afs/volume.h
fs/aio.c
fs/attr.c
fs/autofs4/autofs_i.h
fs/autofs4/expire.c
fs/autofs4/inode.c
fs/autofs4/root.c
fs/binfmt_elf.c
fs/bio.c
fs/buffer.c
fs/cifs/file.c
fs/cifs/inode.c
fs/coda/cache.c
fs/compat.c
fs/compat_ioctl.c
fs/dcache.c
fs/drop_caches.c [new file with mode: 0644]
fs/exec.c
fs/ext3/ialloc.c
fs/ext3/namei.c
fs/ext3/resize.c
fs/ext3/super.c
fs/fat/cache.c
fs/fat/dir.c
fs/fat/fatent.c
fs/fat/file.c
fs/fat/inode.c
fs/fat/misc.c
fs/fcntl.c
fs/file_table.c
fs/freevxfs/vxfs_immed.c
fs/inode.c
fs/jffs/inode-v23.c
fs/jfs/jfs_dmap.c
fs/jfs/jfs_imap.c
fs/jfs/jfs_txnmgr.c
fs/jfs/jfs_umount.c
fs/jfs/resize.c
fs/jfs/super.c
fs/libfs.c
fs/locks.c
fs/mpage.c
fs/namei.c
fs/namespace.c
fs/ncpfs/dir.c
fs/ncpfs/ncplib_kernel.h
fs/nfs/inode.c
fs/nfs/nfsroot.c
fs/ocfs2/cluster/masklog.h
fs/open.c
fs/pnode.c
fs/proc/generic.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/proc_misc.c
fs/proc/root.c
fs/proc/task_mmu.c
fs/relayfs/buffers.c
fs/relayfs/inode.c
fs/relayfs/relay.c
fs/relayfs/relay.h
fs/romfs/inode.c
fs/smbfs/cache.c
fs/smbfs/file.c
fs/smbfs/inode.c
fs/smbfs/proc.c
fs/super.c
fs/sysv/dir.c
fs/udf/balloc.c
fs/udf/inode.c
fs/ufs/super.c
fs/xfs/linux-2.6/xfs_fs_subr.c
fs/xfs/xfs_log.h
include/asm-alpha/cache.h
include/asm-alpha/compiler.h
include/asm-alpha/futex.h
include/asm-alpha/processor.h
include/asm-arm/cache.h
include/asm-arm/futex.h
include/asm-arm/irq.h
include/asm-arm26/futex.h
include/asm-cris/arch-v10/cache.h
include/asm-cris/arch-v32/cache.h
include/asm-cris/dma-mapping.h
include/asm-cris/futex.h
include/asm-frv/atomic.h
include/asm-frv/bug.h
include/asm-frv/dma-mapping.h
include/asm-frv/io.h
include/asm-frv/mb-regs.h
include/asm-frv/mc146818rtc.h [new file with mode: 0644]
include/asm-frv/module.h
include/asm-frv/pci.h
include/asm-frv/pgtable.h
include/asm-frv/types.h
include/asm-frv/uaccess.h
include/asm-frv/unistd.h
include/asm-frv/vga.h [new file with mode: 0644]
include/asm-frv/xor.h [new file with mode: 0644]
include/asm-generic/atomic.h
include/asm-generic/dma-mapping.h
include/asm-generic/futex.h [new file with mode: 0644]
include/asm-h8300/futex.h
include/asm-i386/cache.h
include/asm-i386/dma-mapping.h
include/asm-i386/irq.h
include/asm-i386/ptrace.h
include/asm-i386/unistd.h
include/asm-i386/vm86.h
include/asm-ia64/bug.h
include/asm-ia64/cache.h
include/asm-ia64/futex.h
include/asm-ia64/io.h
include/asm-ia64/spinlock.h
include/asm-ia64/unistd.h
include/asm-m32r/cache.h
include/asm-m32r/futex.h
include/asm-m68k/cache.h
include/asm-m68k/futex.h
include/asm-m68knommu/futex.h
include/asm-mips/cache.h
include/asm-parisc/cache.h
include/asm-parisc/futex.h
include/asm-powerpc/abs_addr.h
include/asm-powerpc/agp.h
include/asm-powerpc/asm-compat.h
include/asm-powerpc/bootx.h [new file with mode: 0644]
include/asm-powerpc/btext.h
include/asm-powerpc/bug.h
include/asm-powerpc/cache.h
include/asm-powerpc/checksum.h
include/asm-powerpc/compat.h
include/asm-powerpc/cputable.h
include/asm-powerpc/current.h
include/asm-powerpc/delay.h
include/asm-powerpc/dma-mapping.h
include/asm-powerpc/dma.h
include/asm-powerpc/eeh.h
include/asm-powerpc/eeh_event.h
include/asm-powerpc/elf.h
include/asm-powerpc/firmware.h
include/asm-powerpc/floppy.h
include/asm-powerpc/grackle.h
include/asm-powerpc/hardirq.h
include/asm-powerpc/heathrow.h
include/asm-powerpc/hvcall.h
include/asm-powerpc/hvconsole.h
include/asm-powerpc/hvcserver.h
include/asm-powerpc/i8259.h
include/asm-powerpc/ibmebus.h [new file with mode: 0644]
include/asm-powerpc/io.h
include/asm-powerpc/iommu.h
include/asm-powerpc/ipic.h [moved from include/asm-ppc/ipic.h with 100% similarity]
include/asm-powerpc/iseries/it_lp_reg_save.h
include/asm-powerpc/kdebug.h
include/asm-powerpc/kdump.h [new file with mode: 0644]
include/asm-powerpc/kexec.h
include/asm-powerpc/keylargo.h
include/asm-powerpc/kprobes.h
include/asm-powerpc/lmb.h
include/asm-powerpc/lppaca.h
include/asm-powerpc/machdep.h
include/asm-powerpc/macio.h
include/asm-powerpc/mmu.h
include/asm-powerpc/mmu_context.h
include/asm-powerpc/mmzone.h
include/asm-powerpc/module.h
include/asm-powerpc/mpic.h
include/asm-powerpc/numnodes.h
include/asm-powerpc/nvram.h
include/asm-powerpc/of_device.h
include/asm-powerpc/ohare.h
include/asm-powerpc/oprofile_impl.h
include/asm-powerpc/pSeries_reconfig.h
include/asm-powerpc/paca.h
include/asm-powerpc/page.h
include/asm-powerpc/page_32.h
include/asm-powerpc/page_64.h
include/asm-powerpc/param.h
include/asm-powerpc/parport.h
include/asm-powerpc/pci-bridge.h
include/asm-powerpc/pci.h
include/asm-powerpc/pgalloc.h
include/asm-powerpc/pgtable-64k.h
include/asm-powerpc/pgtable.h
include/asm-powerpc/pmac_feature.h
include/asm-powerpc/pmac_low_i2c.h
include/asm-powerpc/pmac_pfunc.h [new file with mode: 0644]
include/asm-powerpc/pmc.h
include/asm-powerpc/ppc-pci.h
include/asm-powerpc/ppc_asm.h
include/asm-powerpc/processor.h
include/asm-powerpc/prom.h
include/asm-powerpc/ptrace.h
include/asm-powerpc/reg.h
include/asm-powerpc/rtas.h
include/asm-powerpc/seccomp.h
include/asm-powerpc/sections.h
include/asm-powerpc/serial.h
include/asm-powerpc/signal.h
include/asm-powerpc/smu.h
include/asm-powerpc/sparsemem.h
include/asm-powerpc/spinlock.h
include/asm-powerpc/spu.h [new file with mode: 0644]
include/asm-powerpc/spu_csa.h [new file with mode: 0644]
include/asm-powerpc/synch.h
include/asm-powerpc/system.h
include/asm-powerpc/tce.h
include/asm-powerpc/thread_info.h
include/asm-powerpc/tlb.h
include/asm-powerpc/topology.h
include/asm-powerpc/udbg.h
include/asm-powerpc/unistd.h
include/asm-powerpc/vdso_datapage.h
include/asm-powerpc/vio.h
include/asm-ppc/bseip.h [deleted file]
include/asm-ppc/btext.h
include/asm-ppc/machdep.h
include/asm-ppc/mpc85xx.h
include/asm-ppc/pci-bridge.h
include/asm-ppc/prom.h
include/asm-s390/cache.h
include/asm-s390/futex.h
include/asm-sh/cache.h
include/asm-sh/futex.h
include/asm-sh64/cache.h
include/asm-sh64/futex.h
include/asm-sparc/cache.h
include/asm-sparc/futex.h
include/asm-sparc64/cache.h
include/asm-sparc64/futex.h
include/asm-sparc64/system.h
include/asm-um/cache.h
include/asm-um/futex.h
include/asm-um/rwsem.h
include/asm-v850/cache.h
include/asm-v850/futex.h
include/asm-v850/unistd.h
include/asm-x86_64/cache.h
include/asm-x86_64/ia32_unistd.h
include/asm-x86_64/unistd.h
include/linux/aio.h
include/linux/atalk.h
include/linux/blkdev.h
include/linux/buffer_head.h
include/linux/byteorder/generic.h
include/linux/byteorder/swab.h
include/linux/byteorder/swabb.h
include/linux/cache.h
include/linux/compat_ioctl.h
include/linux/compiler-gcc.h
include/linux/compiler-gcc2.h [deleted file]
include/linux/compiler-gcc3.h
include/linux/compiler-gcc4.h
include/linux/compiler.h
include/linux/cpuset.h
include/linux/cycx_x25.h
include/linux/dcache.h
include/linux/dvb/frontend.h
include/linux/elevator.h
include/linux/elf.h
include/linux/fs.h
include/linux/i2c-id.h
include/linux/ide.h
include/linux/if_frad.h
include/linux/interrupt.h
include/linux/ipv6.h
include/linux/isdnif.h
include/linux/kernel.h
include/linux/key.h
include/linux/keyctl.h
include/linux/memory.h
include/linux/mempolicy.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/mmzone.h
include/linux/mount.h
include/linux/msdos_fs.h
include/linux/ncp.h
include/linux/netfilter.h
include/linux/netfilter_ipv4/ipt_policy.h [new file with mode: 0644]
include/linux/netfilter_ipv6/ip6t_policy.h [new file with mode: 0644]
include/linux/pagevec.h
include/linux/parport.h
include/linux/pci_regs.h
include/linux/percpu.h
include/linux/pmu.h
include/linux/ptrace.h
include/linux/radix-tree.h
include/linux/rcupdate.h
include/linux/rcuref.h [deleted file]
include/linux/relayfs_fs.h
include/linux/rio_drv.h
include/linux/rtc.h
include/linux/sched.h
include/linux/screen_info.h [new file with mode: 0644]
include/linux/sdla.h
include/linux/seccomp.h
include/linux/signal.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/spinlock_types_up.h
include/linux/swap.h
include/linux/synclink.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/tty.h
include/linux/video_decoder.h
include/linux/videodev2.h
include/linux/wavefront.h
include/linux/workqueue.h
include/linux/writeback.h
include/media/audiochip.h
include/media/saa7146_vv.h
include/media/tuner.h
include/media/v4l2-common.h
include/net/dn_dev.h
include/net/dn_nsp.h
include/net/dst.h
include/net/ip.h
include/net/ipv6.h
include/net/protocol.h
include/net/xfrm.h
include/sound/wavefront.h
include/video/cyblafb.h
init/Kconfig
init/main.c
ipc/shm.c
kernel/audit.c
kernel/cpuset.c
kernel/crash_dump.c
kernel/exit.c
kernel/fork.c
kernel/irq/proc.c
kernel/module.c
kernel/pid.c
kernel/printk.c
kernel/ptrace.c
kernel/rcupdate.c
kernel/rcutorture.c
kernel/sched.c
kernel/signal.c
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/timer.c
kernel/workqueue.c
lib/Kconfig.debug
lib/bitmap.c
lib/dec_and_lock.c
lib/find_next_bit.c
lib/radix-tree.c
mm/Kconfig
mm/Makefile
mm/fadvise.c
mm/filemap.c
mm/hugetlb.c
mm/memory.c
mm/mempolicy.c
mm/oom_kill.c
mm/page_alloc.c
mm/pdflush.c
mm/rmap.c
mm/slab.c
mm/slob.c [new file with mode: 0644]
mm/sparse.c
mm/swap_state.c
mm/swapfile.c
mm/truncate.c
mm/util.c [new file with mode: 0644]
mm/vmscan.c
net/802/Makefile
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ieee80211/ieee80211_crypt_wep.c
net/ieee80211/ieee80211_tx.c
net/ieee80211/ieee80211_wx.c
net/ipv4/ip_gre.c
net/ipv4/ip_input.c
net/ipv4/ip_output.c
net/ipv4/ipip.c
net/ipv4/netfilter.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ip_conntrack_proto_sctp.c
net/ipv4/netfilter/ip_nat_standalone.c
net/ipv4/netfilter/ipt_policy.c [new file with mode: 0644]
net/ipv4/raw.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv4/xfrm4_input.c
net/ipv4/xfrm4_output.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/exthdrs.c
net/ipv6/icmp.c
net/ipv6/inet6_connection_sock.c
net/ipv6/ip6_input.c
net/ipv6/ip6_tunnel.c
net/ipv6/netfilter.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/ip6t_policy.c [new file with mode: 0644]
net/ipv6/reassembly.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_input.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_tunnel.c
net/netlink/af_netlink.c
net/sctp/input.c
net/sctp/ipv6.c
net/sunrpc/rpc_pipe.c
net/xfrm/xfrm_policy.c
scripts/bloat-o-meter [new file with mode: 0644]
scripts/kconfig/conf.c
scripts/kconfig/qconf.h
security/keys/compat.c
security/keys/internal.h
security/keys/keyctl.c
security/keys/keyring.c
security/keys/permission.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/selinux/hooks.c
security/selinux/selinuxfs.c
security/selinux/xfrm.c
sound/isa/wavefront/wavefront_synth.c
sound/oss/dmasound/dmasound_awacs.c
sound/oss/i810_audio.c
sound/ppc/pmac.c
sound/ppc/pmac.h

diff --git a/CREDITS b/CREDITS
index 521f00d1b549f5bd4e3a83a0d5b1b4fab142f6b0..8e577ce4abeb4f44ffcb83a894c66130aebb6a58 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -3203,7 +3203,7 @@ N: Eugene Surovegin
 E: ebs@ebshome.net
 W: http://kernel.ebshome.net/
 P: 1024D/AE5467F1 FF22 39F1 6728 89F6 6E6C  2365 7602 F33D AE54 67F1
-D: Embedded PowerPC 4xx: I2C, PIC and random hacks/fixes
+D: Embedded PowerPC 4xx: EMAC, I2C, PIC and random hacks/fixes
 S: Sunnyvale, California 94085
 S: USA
 
index 86b86399d61d7237aab919f87867bd984dddaa25..fe5ae0f550202f1692ab9dc1e45ba5735e867b1d 100644 (file)
@@ -31,8 +31,6 @@ al espa
 Eine deutsche Version dieser Datei finden Sie unter
 <http://www.stefan-winter.de/Changes-2.4.0.txt>.
 
-Last updated: October 29th, 2002
-
 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
 
 Current Minimal Requirements
@@ -48,7 +46,7 @@ necessary on all systems; obviously, if you don't have any ISDN
 hardware, for example, you probably needn't concern yourself with
 isdn4k-utils.
 
-o  Gnu C                  2.95.3                  # gcc --version
+o  Gnu C                  3.2                     # gcc --version
 o  Gnu make               3.79.1                  # make --version
 o  binutils               2.12                    # ld -v
 o  util-linux             2.10o                   # fdformat --version
@@ -74,26 +72,7 @@ GCC
 ---
 
 The gcc version requirements may vary depending on the type of CPU in your
-computer. The next paragraph applies to users of x86 CPUs, but not
-necessarily to users of other CPUs. Users of other CPUs should obtain
-information about their gcc version requirements from another source.
-
-The recommended compiler for the kernel is gcc 2.95.x (x >= 3), and it
-should be used when you need absolute stability. You may use gcc 3.0.x
-instead if you wish, although it may cause problems. Later versions of gcc 
-have not received much testing for Linux kernel compilation, and there are 
-almost certainly bugs (mainly, but not exclusively, in the kernel) that
-will need to be fixed in order to use these compilers. In any case, using
-pgcc instead of plain gcc is just asking for trouble.
-
-The Red Hat gcc 2.96 compiler subtree can also be used to build this tree.
-You should ensure you use gcc-2.96-74 or later. gcc-2.96-54 will not build
-the kernel correctly.
-
-In addition, please pay attention to compiler optimization.  Anything
-greater than -O2 may not be wise.  Similarly, if you choose to use gcc-2.95.x
-or derivatives, be sure not to use -fstrict-aliasing (which, depending on
-your version of gcc 2.95.x, may necessitate using -fno-strict-aliasing).
+computer.
 
 Make
 ----
@@ -322,9 +301,9 @@ Getting updated software
 Kernel compilation
 ******************
 
-gcc 2.95.3
-----------
-o  <ftp://ftp.gnu.org/gnu/gcc/gcc-2.95.3.tar.gz>
+gcc
+---
+o  <ftp://ftp.gnu.org/gnu/gcc/>
 
 Make
 ----
index eb7db3c192273aa7b7b5d9244593c4add69bc863..ce780ef648f1d5c5e0504f8f290add2b5e738876 100644 (file)
@@ -344,7 +344,7 @@ Remember: if another thread can find your data structure, and you don't
 have a reference count on it, you almost certainly have a bug.
 
 
-               Chapter 11: Macros, Enums, Inline functions and RTL
+               Chapter 11: Macros, Enums and RTL
 
 Names of macros defining constants and labels in enums are capitalized.
 
@@ -429,7 +429,35 @@ from void pointer to any other pointer type is guaranteed by the C programming
 language.
 
 
-               Chapter 14: References
+               Chapter 14: The inline disease
+
+There appears to be a common misperception that gcc has a magic "make me
+faster" speedup option called "inline". While the use of inlines can be
+appropriate (for example as a means of replacing macros, see Chapter 11), it
+very often is not. Abundant use of the inline keyword leads to a much bigger
+kernel, which in turn slows the system as a whole down, due to a bigger
+icache footprint for the CPU and simply because there is less memory
+available for the pagecache. Just think about it; a pagecache miss causes a
+disk seek, which easily takes 5 miliseconds. There are a LOT of cpu cycles
+that can go into these 5 miliseconds.
+
+A reasonable rule of thumb is to not put inline at functions that have more
+than 3 lines of code in them. An exception to this rule are the cases where
+a parameter is known to be a compiletime constant, and as a result of this
+constantness you *know* the compiler will be able to optimize most of your
+function away at compile time. For a good example of this later case, see
+the kmalloc() inline function.
+
+Often people argue that adding inline to functions that are static and used
+only once is always a win since there is no space tradeoff. While this is
+technically correct, gcc is capable of inlining these automatically without
+help, and the maintenance issue of removing the inline when a second user
+appears outweighs the potential value of the hint that tells gcc to do
+something it would have done anyway.
+
+
+
+               Chapter 15: References
 
 The C Programming Language, Second Edition
 by Brian W. Kernighan and Dennis M. Ritchie.
@@ -444,10 +472,13 @@ ISBN 0-201-61586-X.
 URL: http://cm.bell-labs.com/cm/cs/tpop/
 
 GNU manuals - where in compliance with K&R and this text - for cpp, gcc,
-gcc internals and indent, all available from http://www.gnu.org
+gcc internals and indent, all available from http://www.gnu.org/manual/
 
 WG14 is the international standardization working group for the programming
-language C, URL: http://std.dkuug.dk/JTC1/SC22/WG14/
+language C, URL: http://www.open-std.org/JTC1/SC22/WG14/
+
+Kernel CodingStyle, by greg@kroah.com at OLS 2002:
+http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
 
 --
-Last updated on 16 February 2004 by a community effort on LKML.
+Last updated on 30 December 2005 by a community effort on LKML.
index a23fee66064df4ff6770e9be02f79af4a0397745..3f60db41b2f0fdce0f6944cf527b3594f2ff8e8e 100644 (file)
@@ -1,74 +1,67 @@
-Refcounter framework for elements of lists/arrays protected by
-RCU.
+Refcounter design for elements of lists/arrays protected by RCU.
 
 Refcounting on elements of  lists which are protected by traditional
 reader/writer spinlocks or semaphores are straight forward as in:
 
-1.                                     2.
-add()                                  search_and_reference()
-{                                      {
-       alloc_object                            read_lock(&list_lock);
-       ...                                     search_for_element
-       atomic_set(&el->rc, 1);                 atomic_inc(&el->rc);
-       write_lock(&list_lock);                 ...
-       add_element                             read_unlock(&list_lock);
-       ...                                     ...
-       write_unlock(&list_lock);       }
+1.                             2.
+add()                          search_and_reference()
+{                              {
+    alloc_object                   read_lock(&list_lock);
+    ...                                    search_for_element
+    atomic_set(&el->rc, 1);        atomic_inc(&el->rc);
+    write_lock(&list_lock);         ...
+    add_element                            read_unlock(&list_lock);
+    ...                                    ...
+    write_unlock(&list_lock);  }
 }
 
 3.                                     4.
 release_referenced()                   delete()
 {                                      {
-       ...                             write_lock(&list_lock);
-       atomic_dec(&el->rc, relfunc)    ...
-       ...                             delete_element
-}                                      write_unlock(&list_lock);
-                                       ...
-                                       if (atomic_dec_and_test(&el->rc))
-                                               kfree(el);
-                                       ...
+    ...                                            write_lock(&list_lock);
+    atomic_dec(&el->rc, relfunc)           ...
+    ...                                            delete_element
+}                                          write_unlock(&list_lock);
+                                           ...
+                                           if (atomic_dec_and_test(&el->rc))
+                                               kfree(el);
+                                           ...
                                        }
 
 If this list/array is made lock free using rcu as in changing the
 write_lock in add() and delete() to spin_lock and changing read_lock
-in search_and_reference to rcu_read_lock(), the rcuref_get in
+in search_and_reference to rcu_read_lock(), the atomic_get in
 search_and_reference could potentially hold reference to an element which
-has already been deleted from the list/array.  rcuref_lf_get_rcu takes
+has already been deleted from the list/array.  atomic_inc_not_zero takes
 care of this scenario. search_and_reference should look as;
 
 1.                                     2.
 add()                                  search_and_reference()
 {                                      {
-       alloc_object                            rcu_read_lock();
-       ...                                     search_for_element
-       atomic_set(&el->rc, 1);                 if (rcuref_inc_lf(&el->rc)) {
-       write_lock(&list_lock);                         rcu_read_unlock();
-                                                       return FAIL;
-       add_element                             }
-       ...                                     ...
-       write_unlock(&list_lock);               rcu_read_unlock();
+    alloc_object                           rcu_read_lock();
+    ...                                            search_for_element
+    atomic_set(&el->rc, 1);                if (atomic_inc_not_zero(&el->rc)) {
+    write_lock(&list_lock);                    rcu_read_unlock();
+                                               return FAIL;
+    add_element                                    }
+    ...                                            ...
+    write_unlock(&list_lock);              rcu_read_unlock();
 }                                      }
 3.                                     4.
 release_referenced()                   delete()
 {                                      {
-       ...                             write_lock(&list_lock);
-       rcuref_dec(&el->rc, relfunc)    ...
-       ...                             delete_element
-}                                      write_unlock(&list_lock);
-                                       ...
-                                       if (rcuref_dec_and_test(&el->rc))
-                                               call_rcu(&el->head, el_free);
-                                       ...
+    ...                                            write_lock(&list_lock);
+    atomic_dec(&el->rc, relfunc)           ...
+    ...                                            delete_element
+}                                          write_unlock(&list_lock);
+                                           ...
+                                           if (atomic_dec_and_test(&el->rc))
+                                               call_rcu(&el->head, el_free);
+                                           ...
                                        }
 
 Sometimes, reference to the element need to be obtained in the
-update (write) stream.  In such cases, rcuref_inc_lf might be an overkill
-since the spinlock serialising list updates are held. rcuref_inc
+update (write) stream.  In such cases, atomic_inc_not_zero might be an
+overkill since the spinlock serialising list updates are held. atomic_inc
 is to be used in such cases.
-For arches which do not have cmpxchg rcuref_inc_lf
-api uses a hashed spinlock implementation and the same hashed spinlock
-is acquired in all rcuref_xxx primitives to preserve atomicity.
-Note: Use rcuref_inc api only if you need to use rcuref_inc_lf on the
-refcounter atleast at one place.  Mixing rcuref_inc and atomic_xxx api
-might lead to races. rcuref_inc_lf() must be used in lockfree
-RCU critical sections only.
+
index c3cca924e94b4accf6848e9338d12c1ca863bb36..dd311cff1cc30b78ebb1dbe8593fb47866e0a78b 100644 (file)
@@ -27,18 +27,17 @@ Who To Submit Drivers To
 ------------------------
 
 Linux 2.0:
-       No new drivers are accepted for this kernel tree
+       No new drivers are accepted for this kernel tree.
 
 Linux 2.2:
+       No new drivers are accepted for this kernel tree.
+
+Linux 2.4:
        If the code area has a general maintainer then please submit it to
        the maintainer listed in MAINTAINERS in the kernel file. If the
        maintainer does not respond or you cannot find the appropriate
-       maintainer then please contact the 2.2 kernel maintainer:
-       Marc-Christian Petersen <m.c.p@wolk-project.de>.
-
-Linux 2.4:
-       The same rules apply as 2.2. The final contact point for Linux 2.4
-       submissions is Marcelo Tosatti <marcelo.tosatti@cyclades.com>.
+       maintainer then please contact Marcelo Tosatti
+       <marcelo.tosatti@cyclades.com>.
 
 Linux 2.6:
        The same rules apply as 2.4 except that you should follow linux-kernel
@@ -53,6 +52,7 @@ Licensing:    The code must be released to us under the
                of exclusive GPL licensing, and if you wish the driver
                to be useful to other communities such as BSD you may well
                wish to release under multiple licenses.
+               See accepted licenses at include/linux/module.h
 
 Copyright:     The copyright owner must agree to use of GPL.
                It's best if the submitter and copyright owner
@@ -143,5 +143,13 @@ KernelNewbies:
        http://kernelnewbies.org/
 
 Linux USB project:
-       http://sourceforge.net/projects/linux-usb/
+       http://linux-usb.sourceforge.net/
+
+How to NOT write kernel driver by arjanv@redhat.com
+       http://people.redhat.com/arjanv/olspaper.pdf
+
+Kernel Janitor:
+       http://janitor.kernelnewbies.org/
 
+--
+Last updated on 17 Nov 2005.
index 1d47e6c09dc60c7a1c2330c09b458b5af0871852..6198e5ebcf65be906f801acd1f5df836c3d4d93c 100644 (file)
@@ -78,7 +78,9 @@ Randy Dunlap's patch scripts:
 http://www.xenotime.net/linux/scripts/patching-scripts-002.tar.gz
 
 Andrew Morton's patch scripts:
-http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.20
+http://www.zip.com.au/~akpm/linux/patches/
+Instead of these scripts, quilt is the recommended patch management
+tool (see above).
 
 
 
@@ -97,7 +99,7 @@ need to split up your patch.  See #3, next.
 
 3) Separate your changes.
 
-Separate each logical change into its own patch.
+Separate _logical changes_ into a single patch file.
 
 For example, if your changes include both bug fixes and performance
 enhancements for a single driver, separate those changes into two
@@ -112,6 +114,10 @@ If one patch depends on another patch in order for a change to be
 complete, that is OK.  Simply note "this patch depends on patch X"
 in your patch description.
 
+If you cannot condense your patch set into a smaller set of patches,
+then only post say 15 or so at a time and wait for review and integration.
+
+
 
 4) Select e-mail destination.
 
@@ -124,6 +130,10 @@ your patch to the primary Linux kernel developer's mailing list,
 linux-kernel@vger.kernel.org.  Most kernel developers monitor this
 e-mail list, and can comment on your changes.
 
+
+Do not send more than 15 patches at once to the vger mailing lists!!!
+
+
 Linus Torvalds is the final arbiter of all changes accepted into the
 Linux kernel.  His e-mail address is <torvalds@osdl.org>.  He gets
 a lot of e-mail, so typically you should do your best to -avoid- sending
@@ -149,6 +159,9 @@ USB, framebuffer devices, the VFS, the SCSI subsystem, etc.  See the
 MAINTAINERS file for a mailing list that relates specifically to
 your change.
 
+Majordomo lists of VGER.KERNEL.ORG at:
+       <http://vger.kernel.org/vger-lists.html>
+
 If changes affect userland-kernel interfaces, please send
 the MAN-PAGES maintainer (as listed in the MAINTAINERS file)
 a man-pages patch, or at least a notification of the change,
@@ -373,27 +386,14 @@ a diffstat, to show what files have changed, and the number of inserted
 and deleted lines per file.  A diffstat is especially useful on bigger
 patches.  Other comments relevant only to the moment or the maintainer,
 not suitable for the permanent changelog, should also go here.
+Use diffstat options "-p 1 -w 70" so that filenames are listed from the
+top of the kernel source tree and don't use too much horizontal space
+(easily fit in 80 columns, maybe with some indentation).
 
 See more details on the proper patch format in the following
 references.
 
 
-13) More references for submitting patches
-
-Andrew Morton, "The perfect patch" (tpp).
-  <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
-
-Jeff Garzik, "Linux kernel patch submission format."
-  <http://linux.yyz.us/patch-format.html>
-
-Greg KH, "How to piss off a kernel subsystem maintainer"
-  <http://www.kroah.com/log/2005/03/31/>
-
-Kernel Documentation/CodingStyle
-  <http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
-
-Linus Torvald's mail on the canonical patch format:
-  <http://lkml.org/lkml/2005/4/7/183>
 
 
 -----------------------------------
@@ -466,3 +466,30 @@ and 'extern __inline__'.
 Don't try to anticipate nebulous future cases which may or may not
 be useful:  "Make it as simple as you can, and no simpler."
 
+
+
+----------------------
+SECTION 3 - REFERENCES
+----------------------
+
+Andrew Morton, "The perfect patch" (tpp).
+  <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+
+Jeff Garzik, "Linux kernel patch submission format."
+  <http://linux.yyz.us/patch-format.html>
+
+Greg Kroah, "How to piss off a kernel subsystem maintainer".
+  <http://www.kroah.com/log/2005/03/31/>
+  <http://www.kroah.com/log/2005/07/08/>
+  <http://www.kroah.com/log/2005/10/19/>
+
+NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!.
+  <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+
+Kernel Documentation/CodingStyle
+  <http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
+
+Linus Torvald's mail on the canonical patch format:
+  <http://lkml.org/lkml/2005/4/7/183>
+--
+Last updated on 17 Nov 2005.
index 681e426e24821043301d549f25401d4c3f6b48e8..05a08c2c18897d0125c488671bf5da6616c0aee0 100644 (file)
@@ -2,7 +2,8 @@
        Applying Patches To The Linux Kernel
        ------------------------------------
 
-       (Written by Jesper Juhl, August 2005)
+       Original by: Jesper Juhl, August 2005
+       Last update: 2005-12-02
 
 
 
@@ -118,7 +119,7 @@ wrong.
 
 When patch encounters a change that it can't fix up with fuzz it rejects it
 outright and leaves a file with a .rej extension (a reject file). You can
-read this file to see exactely what change couldn't be applied, so you can
+read this file to see exactly what change couldn't be applied, so you can
 go fix it up by hand if you wish.
 
 If you don't have any third party patches applied to your kernel source, but
@@ -127,7 +128,7 @@ and have made no modifications yourself to the source files, then you should
 never see a fuzz or reject message from patch. If you do see such messages
 anyway, then there's a high risk that either your local source tree or the
 patch file is corrupted in some way. In that case you should probably try
-redownloading the patch and if things are still not OK then you'd be advised
+re-downloading the patch and if things are still not OK then you'd be advised
 to start with a fresh tree downloaded in full from kernel.org.
 
 Let's look a bit more at some of the messages patch can produce.
@@ -180,9 +181,11 @@ wish to apply.
 
 Are there any alternatives to `patch'?
 ---
- Yes there are alternatives. You can use the `interdiff' program
-(http://cyberelk.net/tim/patchutils/) to generate a patch representing the
-differences between two patches and then apply the result.
+ Yes there are alternatives.
+
+ You can use the `interdiff' program (http://cyberelk.net/tim/patchutils/) to
+generate a patch representing the differences between two patches and then
+apply the result.
 This will let you move from something like 2.6.12.2 to 2.6.12.3 in a single
 step. The -z flag to interdiff will even let you feed it patches in gzip or
 bzip2 compressed form directly without the use of zcat or bzcat or manual
@@ -197,7 +200,7 @@ do the additional steps since interdiff can get things wrong in some cases.
  Another alternative is `ketchup', which is a python script for automatic
 downloading and applying of patches (http://www.selenic.com/ketchup/).
 
-Other nice tools are diffstat which shows a summary of changes made by a
+ Other nice tools are diffstat which shows a summary of changes made by a
 patch, lsdiff which displays a short listing of affected files in a patch
 file, along with (optionally) the line numbers of the start of each patch
 and grepdiff which displays a list of the files modified by a patch where
@@ -258,7 +261,7 @@ $ patch -p1 -R < ../patch-2.6.11.1  # revert the 2.6.11.1 patch
                                        # source dir is now 2.6.11
 $ patch -p1 < ../patch-2.6.12          # apply new 2.6.12 patch
 $ cd ..
-$ mv linux-2.6.11.1 inux-2.6.12                # rename source dir
+$ mv linux-2.6.11.1 linux-2.6.12               # rename source dir
 
 
 The 2.6.x.y kernels
@@ -433,7 +436,11 @@ $ cd ..
 $ mv linux-2.6.12-mm1 linux-2.6.13-rc3-mm3     # rename the source dir
 
 
-This concludes this list of explanations of the various kernel trees and I
-hope you are now crystal clear on how to apply the various patches and help
-testing the kernel.
+This concludes this list of explanations of the various kernel trees.
+I hope you are now clear on how to apply the various patches and help testing
+the kernel.
+
+Thank you's to Randy Dunlap, Rolf Eike Beer, Linus Torvalds, Bodo Eggert,
+Johannes Stezenbach, Grant Coady, Pavel Machek and others that I may have
+forgotten for their reviews and contributions to this document.
 
diff --git a/Documentation/block/stat.txt b/Documentation/block/stat.txt
new file mode 100644 (file)
index 0000000..0dbc946
--- /dev/null
@@ -0,0 +1,82 @@
+Block layer statistics in /sys/block/<dev>/stat
+===============================================
+
+This file documents the contents of the /sys/block/<dev>/stat file.
+
+The stat file provides several statistics about the state of block
+device <dev>.
+
+Q. Why are there multiple statistics in a single file?  Doesn't sysfs
+   normally contain a single value per file?
+A. By having a single file, the kernel can guarantee that the statistics
+   represent a consistent snapshot of the state of the device.  If the
+   statistics were exported as multiple files containing one statistic
+   each, it would be impossible to guarantee that a set of readings
+   represent a single point in time.
+
+The stat file consists of a single line of text containing 11 decimal
+values separated by whitespace.  The fields are summarized in the
+following table, and described in more detail below.
+
+Name            units         description
+----            -----         -----------
+read I/Os       requests      number of read I/Os processed
+read merges     requests      number of read I/Os merged with in-queue I/O
+read sectors    sectors       number of sectors read
+read ticks      milliseconds  total wait time for read requests
+write I/Os      requests      number of write I/Os processed
+write merges    requests      number of write I/Os merged with in-queue I/O
+write sectors   sectors       number of sectors written
+write ticks     milliseconds  total wait time for write requests
+in_flight       requests      number of I/Os currently in flight
+io_ticks        milliseconds  total time this block device has been active
+time_in_queue   milliseconds  total wait time for all requests
+
+read I/Os, write I/Os
+=====================
+
+These values increment when an I/O request completes.
+
+read merges, write merges
+=========================
+
+These values increment when an I/O request is merged with an
+already-queued I/O request.
+
+read sectors, write sectors
+===========================
+
+These values count the number of sectors read from or written to this
+block device.  The "sectors" in question are the standard UNIX 512-byte
+sectors, not any device- or filesystem-specific block size.  The
+counters are incremented when the I/O completes.
+
+read ticks, write ticks
+=======================
+
+These values count the number of milliseconds that I/O requests have
+waited on this block device.  If there are multiple I/O requests waiting,
+these values will increase at a rate greater than 1000/second; for
+example, if 60 read requests wait for an average of 30 ms, the read_ticks
+field will increase by 60*30 = 1800.
+
+in_flight
+=========
+
+This value counts the number of I/O requests that have been issued to
+the device driver but have not yet completed.  It does not include I/O
+requests that are in the queue but not yet issued to the device driver.
+
+io_ticks
+========
+
+This value counts the number of milliseconds during which the device has
+had I/O requests queued.
+
+time_in_queue
+=============
+
+This value counts the number of milliseconds that I/O requests have waited
+on this block device.  If there are multiple I/O requests waiting, this
+value will increase as the product of the number of milliseconds times the
+number of requests waiting (see "read ticks" above for an example).
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
new file mode 100644 (file)
index 0000000..08c5d04
--- /dev/null
@@ -0,0 +1,357 @@
+               CPU hotplug Support in Linux(tm) Kernel
+
+               Maintainers:
+               CPU Hotplug Core:
+                       Rusty Russell <rusty@rustycorp.com.au>
+                       Srivatsa Vaddagiri <vatsa@in.ibm.com>
+               i386:
+                       Zwane Mwaikambo <zwane@arm.linux.org.uk>
+               ppc64:
+                       Nathan Lynch <nathanl@austin.ibm.com>
+                       Joel Schopp <jschopp@austin.ibm.com>
+               ia64/x86_64:
+                       Ashok Raj <ashok.raj@intel.com>
+
+Authors: Ashok Raj <ashok.raj@intel.com>
+Lots of feedback: Nathan Lynch <nathanl@austin.ibm.com>,
+            Joel Schopp <jschopp@austin.ibm.com>
+
+Introduction
+
+Modern advances in system architectures have introduced advanced error
+reporting and correction capabilities in processors. CPU architectures permit
+partitioning support, where compute resources of a single CPU could be made
+available to virtual machine environments. There are couple OEMS that
+support NUMA hardware which are hot pluggable as well, where physical
+node insertion and removal require support for CPU hotplug.
+
+Such advances require CPUs available to a kernel to be removed either for
+provisioning reasons, or for RAS purposes to keep an offending CPU off
+system execution path. Hence the need for CPU hotplug support in the
+Linux kernel.
+
+A more novel use of CPU-hotplug support is its use today in suspend
+resume support for SMP. Dual-core and HT support makes even
+a laptop run SMP kernels which didn't support these methods. SMP support
+for suspend/resume is a work in progress.
+
+General Stuff about CPU Hotplug
+--------------------------------
+
+Command Line Switches
+---------------------
+maxcpus=n    Restrict boot time cpus to n. Say if you have 4 cpus, using
+             maxcpus=2 will only boot 2. You can choose to bring the
+             other cpus later online, read FAQ's for more info.
+
+additional_cpus=n      [x86_64 only] use this to limit hotpluggable cpus.
+                        This option sets
+                       cpu_possible_map = cpu_present_map + additional_cpus
+
+CPU maps and such
+-----------------
+[More on cpumaps and primitive to manipulate, please check
+include/linux/cpumask.h that has more descriptive text.]
+
+cpu_possible_map: Bitmap of possible CPUs that can ever be available in the
+system. This is used to allocate some boot time memory for per_cpu variables
+that aren't designed to grow/shrink as CPUs are made available or removed.
+Once set during boot time discovery phase, the map is static, i.e no bits
+are added or removed anytime.  Trimming it accurately for your system needs
+upfront can save some boot time memory. See below for how we use heuristics
+in x86_64 case to keep this under check.
+
+cpu_online_map: Bitmap of all CPUs currently online. Its set in __cpu_up()
+after a cpu is available for kernel scheduling and ready to receive
+interrupts from devices. Its cleared when a cpu is brought down using
+__cpu_disable(), before which all OS services including interrupts are
+migrated to another target CPU.
+
+cpu_present_map: Bitmap of CPUs currently present in the system. Not all
+of them may be online. When physical hotplug is processed by the relevant
+subsystem (e.g ACPI) can change and new bit either be added or removed
+from the map depending on the event is hot-add/hot-remove. There are currently
+no locking rules as of now. Typical usage is to init topology during boot,
+at which time hotplug is disabled.
+
+You really dont need to manipulate any of the system cpu maps. They should
+be read-only for most use. When setting up per-cpu resources almost always use
+cpu_possible_map/for_each_cpu() to iterate.
+
+Never use anything other than cpumask_t to represent bitmap of CPUs.
+
+#include <linux/cpumask.h>
+
+for_each_cpu              - Iterate over cpu_possible_map
+for_each_online_cpu       - Iterate over cpu_online_map
+for_each_present_cpu      - Iterate over cpu_present_map
+for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask.
+
+#include <linux/cpu.h>
+lock_cpu_hotplug() and unlock_cpu_hotplug():
+
+The above calls are used to inhibit cpu hotplug operations. While holding the
+cpucontrol mutex, cpu_online_map will not change. If you merely need to avoid
+cpus going away, you could also use preempt_disable() and preempt_enable()
+for those sections. Just remember the critical section cannot call any
+function that can sleep or schedule this process away. The preempt_disable()
+will work as long as stop_machine_run() is used to take a cpu down.
+
+CPU Hotplug - Frequently Asked Questions.
+
+Q: How to i enable my kernel to support CPU hotplug?
+A: When doing make defconfig, Enable CPU hotplug support
+
+   "Processor type and Features" -> Support for Hotpluggable CPUs
+
+Make sure that you have CONFIG_HOTPLUG, and CONFIG_SMP turned on as well.
+
+You would need to enable CONFIG_HOTPLUG_CPU for SMP suspend/resume support
+as well.
+
+Q: What architectures support CPU hotplug?
+A: As of 2.6.14, the following architectures support CPU hotplug.
+
+i386 (Intel), ppc, ppc64, parisc, s390, ia64 and x86_64
+
+Q: How to test if hotplug is supported on the newly built kernel?
+A: You should now notice an entry in sysfs.
+
+Check if sysfs is mounted, using the "mount" command. You should notice
+an entry as shown below in the output.
+
+....
+none on /sys type sysfs (rw)
+....
+
+if this is not mounted, do the following.
+
+#mkdir /sysfs
+#mount -t sysfs sys /sys
+
+now you should see entries for all present cpu, the following is an example
+in a 8-way system.
+
+#pwd
+#/sys/devices/system/cpu
+#ls -l
+total 0
+drwxr-xr-x  10 root root 0 Sep 19 07:44 .
+drwxr-xr-x  13 root root 0 Sep 19 07:45 ..
+drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu0
+drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu1
+drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu2
+drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu3
+drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu4
+drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu5
+drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu6
+drwxr-xr-x   3 root root 0 Sep 19 07:48 cpu7
+
+Under each directory you would find an "online" file which is the control
+file to logically online/offline a processor.
+
+Q: Does hot-add/hot-remove refer to physical add/remove of cpus?
+A: The usage of hot-add/remove may not be very consistently used in the code.
+CONFIG_CPU_HOTPLUG enables logical online/offline capability in the kernel.
+To support physical addition/removal, one would need some BIOS hooks and
+the platform should have something like an attention button in PCI hotplug.
+CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs.
+
+Q: How do i logically offline a CPU?
+A: Do the following.
+
+#echo 0 > /sys/devices/system/cpu/cpuX/online
+
+once the logical offline is successful, check
+
+#cat /proc/interrupts
+
+you should now not see the CPU that you removed. Also online file will report
+the state as 0 when a cpu if offline and 1 when its online.
+
+#To display the current cpu state.
+#cat /sys/devices/system/cpu/cpuX/online
+
+Q: Why cant i remove CPU0 on some systems?
+A: Some architectures may have some special dependency on a certain CPU.
+
+For e.g in IA64 platforms we have ability to sent platform interrupts to the
+OS. a.k.a Corrected Platform Error Interrupts (CPEI). In current ACPI
+specifications, we didn't have a way to change the target CPU. Hence if the
+current ACPI version doesn't support such re-direction, we disable that CPU
+by making it not-removable.
+
+In such cases you will also notice that the online file is missing under cpu0.
+
+Q: How do i find out if a particular CPU is not removable?
+A: Depending on the implementation, some architectures may show this by the
+absence of the "online" file. This is done if it can be determined ahead of
+time that this CPU cannot be removed.
+
+In some situations, this can be a run time check, i.e if you try to remove the
+last CPU, this will not be permitted. You can find such failures by
+investigating the return value of the "echo" command.
+
+Q: What happens when a CPU is being logically offlined?
+A: The following happen, listed in no particular order :-)
+
+- A notification is sent to in-kernel registered modules by sending an event
+  CPU_DOWN_PREPARE
+- All process is migrated away from this outgoing CPU to a new CPU
+- All interrupts targeted to this CPU is migrated to a new CPU
+- timers/bottom half/task lets are also migrated to a new CPU
+- Once all services are migrated, kernel calls an arch specific routine
+  __cpu_disable() to perform arch specific cleanup.
+- Once this is successful, an event for successful cleanup is sent by an event
+  CPU_DEAD.
+
+  "It is expected that each service cleans up when the CPU_DOWN_PREPARE
+  notifier is called, when CPU_DEAD is called its expected there is nothing
+  running on behalf of this CPU that was offlined"
+
+Q: If i have some kernel code that needs to be aware of CPU arrival and
+   departure, how to i arrange for proper notification?
+A: This is what you would need in your kernel code to receive notifications.
+
+    #include <linux/cpu.h>
+    static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb,
+                                           unsigned long action, void *hcpu)
+       {
+               unsigned int cpu = (unsigned long)hcpu;
+
+               switch (action) {
+               case CPU_ONLINE:
+                       foobar_online_action(cpu);
+                       break;
+               case CPU_DEAD:
+                       foobar_dead_action(cpu);
+                       break;
+               }
+               return NOTIFY_OK;
+       }
+
+       static struct notifier_block foobar_cpu_notifer =
+       {
+          .notifier_call = foobar_cpu_callback,
+       };
+
+
+In your init function,
+
+       register_cpu_notifier(&foobar_cpu_notifier);
+
+You can fail PREPARE notifiers if something doesn't work to prepare resources.
+This will stop the activity and send a following CANCELED event back.
+
+CPU_DEAD should not be failed, its just a goodness indication, but bad
+things will happen if a notifier in path sent a BAD notify code.
+
+Q: I don't see my action being called for all CPUs already up and running?
+A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined.
+   If you need to perform some action for each cpu already in the system, then
+
+  for_each_online_cpu(i) {
+               foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i);
+               foobar_cpu_callback(&foobar-cpu_notifier, CPU_ONLINE, i);
+  }
+
+Q: If i would like to develop cpu hotplug support for a new architecture,
+   what do i need at a minimum?
+A: The following are what is required for CPU hotplug infrastructure to work
+   correctly.
+
+    - Make sure you have an entry in Kconfig to enable CONFIG_HOTPLUG_CPU
+    - __cpu_up()        - Arch interface to bring up a CPU
+    - __cpu_disable()   - Arch interface to shutdown a CPU, no more interrupts
+                          can be handled by the kernel after the routine
+                          returns. Including local APIC timers etc are
+                          shutdown.
+     - __cpu_die()      - This actually supposed to ensure death of the CPU.
+                          Actually look at some example code in other arch
+                          that implement CPU hotplug. The processor is taken
+                          down from the idle() loop for that specific
+                          architecture. __cpu_die() typically waits for some
+                          per_cpu state to be set, to ensure the processor
+                          dead routine is called to be sure positively.
+
+Q: I need to ensure that a particular cpu is not removed when there is some
+   work specific to this cpu is in progress.
+A: First switch the current thread context to preferred cpu
+
+   int my_func_on_cpu(int cpu)
+   {
+       cpumask_t saved_mask, new_mask = CPU_MASK_NONE;
+       int curr_cpu, err = 0;
+
+       saved_mask = current->cpus_allowed;
+       cpu_set(cpu, new_mask);
+       err = set_cpus_allowed(current, new_mask);
+
+       if (err)
+           return err;
+
+       /*
+        * If we got scheduled out just after the return from
+        * set_cpus_allowed() before running the work, this ensures
+        * we stay locked.
+        */
+       curr_cpu = get_cpu();
+
+       if (curr_cpu != cpu) {
+          err = -EAGAIN;
+           goto ret;
+       } else {
+                  /*
+           * Do work : But cant sleep, since get_cpu() disables preempt
+           */
+       }
+    ret:
+       put_cpu();
+       set_cpus_allowed(current, saved_mask);
+       return err;
+    }
+
+
+Q: How do we determine how many CPUs are available for hotplug.
+A: There is no clear spec defined way from ACPI that can give us that
+   information today. Based on some input from Natalie of Unisys,
+   that the ACPI MADT (Multiple APIC Description Tables) marks those possible
+   CPUs in a system with disabled status.
+
+   Andi implemented some simple heuristics that count the number of disabled
+   CPUs in MADT as hotpluggable CPUS.  In the case there are no disabled CPUS
+   we assume 1/2 the number of CPUs currently present can be hotplugged.
+
+   Caveat: Today's ACPI MADT can only provide 256 entries since the apicid field
+   in MADT is only 8 bits.
+
+User Space Notification
+
+Hotplug support for devices is common in Linux today. Its being used today to
+support automatic configuration of network, usb and pci devices. A hotplug
+event can be used to invoke an agent script to perform the configuration task.
+
+You can add /etc/hotplug/cpu.agent to handle hotplug notification user space
+scripts.
+
+       #!/bin/bash
+       # $Id: cpu.agent
+       # Kernel hotplug params include:
+       #ACTION=%s [online or offline]
+       #DEVPATH=%s
+       #
+       cd /etc/hotplug
+       . ./hotplug.functions
+
+       case $ACTION in
+               online)
+                       echo `date` ":cpu.agent" add cpu >> /tmp/hotplug.txt
+                       ;;
+               offline)
+                       echo `date` ":cpu.agent" remove cpu >>/tmp/hotplug.txt
+                       ;;
+               *)
+                       debug_mesg CPU $ACTION event not supported
+        exit 1
+        ;;
+       esac
index a09a8eb80665ed5d1eadc4eee0cf935d4e689c5d..9e49b1c3572961f8ba31ecb561755e3036fbc206 100644 (file)
@@ -14,7 +14,10 @@ CONTENTS:
   1.1 What are cpusets ?
   1.2 Why are cpusets needed ?
   1.3 How are cpusets implemented ?
-  1.4 How do I use cpusets ?
+  1.4 What are exclusive cpusets ?
+  1.5 What does notify_on_release do ?
+  1.6 What is memory_pressure ?
+  1.7 How do I use cpusets ?
 2. Usage Examples and Syntax
   2.1 Basic Usage
   2.2 Adding/removing cpus
@@ -49,29 +52,6 @@ its cpus_allowed vector, and the kernel page allocator will not
 allocate a page on a node that is not allowed in the requesting tasks
 mems_allowed vector.
 
-If a cpuset is cpu or mem exclusive, no other cpuset, other than a direct
-ancestor or descendent, may share any of the same CPUs or Memory Nodes.
-A cpuset that is cpu exclusive has a sched domain associated with it.
-The sched domain consists of all cpus in the current cpuset that are not
-part of any exclusive child cpusets.
-This ensures that the scheduler load balacing code only balances
-against the cpus that are in the sched domain as defined above and not
-all of the cpus in the system. This removes any overhead due to
-load balancing code trying to pull tasks outside of the cpu exclusive
-cpuset only to be prevented by the tasks' cpus_allowed mask.
-
-A cpuset that is mem_exclusive restricts kernel allocations for
-page, buffer and other data commonly shared by the kernel across
-multiple users.  All cpusets, whether mem_exclusive or not, restrict
-allocations of memory for user space.  This enables configuring a
-system so that several independent jobs can share common kernel
-data, such as file system pages, while isolating each jobs user
-allocation in its own cpuset.  To do this, construct a large
-mem_exclusive cpuset to hold all the jobs, and construct child,
-non-mem_exclusive cpusets for each individual job.  Only a small
-amount of typical kernel memory, such as requests from interrupt
-handlers, is allowed to be taken outside even a mem_exclusive cpuset.
-
 User level code may create and destroy cpusets by name in the cpuset
 virtual file system, manage the attributes and permissions of these
 cpusets and which CPUs and Memory Nodes are assigned to each cpuset,
@@ -192,9 +172,15 @@ containing the following files describing that cpuset:
 
  - cpus: list of CPUs in that cpuset
  - mems: list of Memory Nodes in that cpuset
+ - memory_migrate flag: if set, move pages to cpusets nodes
  - cpu_exclusive flag: is cpu placement exclusive?
  - mem_exclusive flag: is memory placement exclusive?
  - tasks: list of tasks (by pid) attached to that cpuset
+ - notify_on_release flag: run /sbin/cpuset_release_agent on exit?
+ - memory_pressure: measure of how much paging pressure in cpuset
+
+In addition, the root cpuset only has the following file:
+ - memory_pressure_enabled flag: compute memory_pressure?
 
 New cpusets are created using the mkdir system call or shell
 command.  The properties of a cpuset, such as its flags, allowed
@@ -228,7 +214,108 @@ exclusive cpuset.  Also, the use of a Linux virtual file system (vfs)
 to represent the cpuset hierarchy provides for a familiar permission
 and name space for cpusets, with a minimum of additional kernel code.
 
-1.4 How do I use cpusets ?
+
+1.4 What are exclusive cpusets ?
+--------------------------------
+
+If a cpuset is cpu or mem exclusive, no other cpuset, other than
+a direct ancestor or descendent, may share any of the same CPUs or
+Memory Nodes.
+
+A cpuset that is cpu_exclusive has a scheduler (sched) domain
+associated with it.  The sched domain consists of all CPUs in the
+current cpuset that are not part of any exclusive child cpusets.
+This ensures that the scheduler load balancing code only balances
+against the CPUs that are in the sched domain as defined above and
+not all of the CPUs in the system. This removes any overhead due to
+load balancing code trying to pull tasks outside of the cpu_exclusive
+cpuset only to be prevented by the tasks' cpus_allowed mask.
+
+A cpuset that is mem_exclusive restricts kernel allocations for
+page, buffer and other data commonly shared by the kernel across
+multiple users.  All cpusets, whether mem_exclusive or not, restrict
+allocations of memory for user space.  This enables configuring a
+system so that several independent jobs can share common kernel data,
+such as file system pages, while isolating each jobs user allocation in
+its own cpuset.  To do this, construct a large mem_exclusive cpuset to
+hold all the jobs, and construct child, non-mem_exclusive cpusets for
+each individual job.  Only a small amount of typical kernel memory,
+such as requests from interrupt handlers, is allowed to be taken
+outside even a mem_exclusive cpuset.
+
+
+1.5 What does notify_on_release do ?
+------------------------------------
+
+If the notify_on_release flag is enabled (1) in a cpuset, then whenever
+the last task in the cpuset leaves (exits or attaches to some other
+cpuset) and the last child cpuset of that cpuset is removed, then
+the kernel runs the command /sbin/cpuset_release_agent, supplying the
+pathname (relative to the mount point of the cpuset file system) of the
+abandoned cpuset.  This enables automatic removal of abandoned cpusets.
+The default value of notify_on_release in the root cpuset at system
+boot is disabled (0).  The default value of other cpusets at creation
+is the current value of their parents notify_on_release setting.
+
+
+1.6 What is memory_pressure ?
+-----------------------------
+The memory_pressure of a cpuset provides a simple per-cpuset metric
+of the rate that the tasks in a cpuset are attempting to free up in
+use memory on the nodes of the cpuset to satisfy additional memory
+requests.
+
+This enables batch managers monitoring jobs running in dedicated
+cpusets to efficiently detect what level of memory pressure that job
+is causing.
+
+This is useful both on tightly managed systems running a wide mix of
+submitted jobs, which may choose to terminate or re-prioritize jobs that
+are trying to use more memory than allowed on the nodes assigned them,
+and with tightly coupled, long running, massively parallel scientific
+computing jobs that will dramatically fail to meet required performance
+goals if they start to use more memory than allowed to them.
+
+This mechanism provides a very economical way for the batch manager
+to monitor a cpuset for signs of memory pressure.  It's up to the
+batch manager or other user code to decide what to do about it and
+take action.
+
+==> Unless this feature is enabled by writing "1" to the special file
+    /dev/cpuset/memory_pressure_enabled, the hook in the rebalance
+    code of __alloc_pages() for this metric reduces to simply noticing
+    that the cpuset_memory_pressure_enabled flag is zero.  So only
+    systems that enable this feature will compute the metric.
+
+Why a per-cpuset, running average:
+
+    Because this meter is per-cpuset, rather than per-task or mm,
+    the system load imposed by a batch scheduler monitoring this
+    metric is sharply reduced on large systems, because a scan of
+    the tasklist can be avoided on each set of queries.
+
+    Because this meter is a running average, instead of an accumulating
+    counter, a batch scheduler can detect memory pressure with a
+    single read, instead of having to read and accumulate results
+    for a period of time.
+
+    Because this meter is per-cpuset rather than per-task or mm,
+    the batch scheduler can obtain the key information, memory
+    pressure in a cpuset, with a single read, rather than having to
+    query and accumulate results over all the (dynamically changing)
+    set of tasks in the cpuset.
+
+A per-cpuset simple digital filter (requires a spinlock and 3 words
+of data per-cpuset) is kept, and updated by any task attached to that
+cpuset, if it enters the synchronous (direct) page reclaim code.
+
+A per-cpuset file provides an integer number representing the recent
+(half-life of 10 seconds) rate of direct page reclaims caused by
+the tasks in the cpuset, in units of reclaims attempted per second,
+times 1000.
+
+
+1.7 How do I use cpusets ?
 --------------------------
 
 In order to minimize the impact of cpusets on critical kernel
@@ -277,6 +364,30 @@ rewritten to the 'tasks' file of its cpuset.  This is done to avoid
 impacting the scheduler code in the kernel with a check for changes
 in a tasks processor placement.
 
+Normally, once a page is allocated (given a physical page
+of main memory) then that page stays on whatever node it
+was allocated, so long as it remains allocated, even if the
+cpusets memory placement policy 'mems' subsequently changes.
+If the cpuset flag file 'memory_migrate' is set true, then when
+tasks are attached to that cpuset, any pages that task had
+allocated to it on nodes in its previous cpuset are migrated
+to the tasks new cpuset.  Depending on the implementation,
+this migration may either be done by swapping the page out,
+so that the next time the page is referenced, it will be paged
+into the tasks new cpuset, usually on the node where it was
+referenced, or this migration may be done by directly copying
+the pages from the tasks previous cpuset to the new cpuset,
+where possible to the same node, relative to the new cpuset,
+as the node that held the page, relative to the old cpuset.
+Also if 'memory_migrate' is set true, then if that cpusets
+'mems' file is modified, pages allocated to tasks in that
+cpuset, that were on nodes in the previous setting of 'mems',
+will be moved to nodes in the new setting of 'mems.'  Again,
+depending on the implementation, this might be done by swapping,
+or by direct copying.  In either case, pages that were not in
+the tasks prior cpuset, or in the cpusets prior 'mems' setting,
+will not be moved.
+
 There is an exception to the above.  If hotplug functionality is used
 to remove all the CPUs that are currently assigned to a cpuset,
 then the kernel will automatically update the cpus_allowed of all
index 2dc260b2b0a4a417c0e489b4713037373d1b0dd5..068070ff13cd0a4673d9333341b39ea5b77daf41 100644 (file)
@@ -150,7 +150,8 @@ Getting the card going
 
    The frontend module sp887x.o, requires an external   firmware.
    Please use  the  command "get_dvb_firmware sp887x" to download
-   it. Then copy it to /usr/lib/hotplug/firmware.
+   it. Then copy it to /usr/lib/hotplug/firmware or /lib/firmware/
+   (depending on configuration of firmware hotplug).
 
 Receiving DVB-T in Australia
 
index be6eb4c759915ff4c56db77c8448e14da3b3aaca..75c28a174092f5236e9dddc98444fff4b84e9183 100644 (file)
@@ -23,7 +23,7 @@ use IO::Handle;
 
 @components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
                "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
-               "or51211", "or51132_qam", "or51132_vsb");
+               "or51211", "or51132_qam", "or51132_vsb", "bluebird");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -34,7 +34,11 @@ for ($i=0; $i < scalar(@components); $i++) {
     if ($cid eq $components[$i]) {
        $outfile = eval($cid);
        die $@ if $@;
-       print STDERR "Firmware $outfile extracted successfully. Now copy it to either /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version).\n";
+       print STDERR <<EOF;
+Firmware $outfile extracted successfully.
+Now copy it to either /usr/lib/hotplug/firmware or /lib/firmware
+(depending on configuration of firmware hotplug).
+EOF
        exit(0);
     }
 }
@@ -243,7 +247,7 @@ sub nxt2002 {
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
 
     checkstandard();
-    
+
     wgetfile($sourcefile, $url);
     unzip($sourcefile, $tmpdir);
     verify("$tmpdir/SkyNETU.sys", $hash);
@@ -308,6 +312,19 @@ sub or51132_vsb {
     $fwfile;
 }
 
+sub bluebird {
+       my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
+       my $outfile = "dvb-usb-bluebird-01.fw";
+       my $hash = "658397cb9eba9101af9031302671f49d";
+
+       checkstandard();
+
+       wgetfile($outfile, $url);
+       verify($outfile,$hash);
+
+       $outfile;
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
index 5c1e984c26a76827e27a5b2bed80ce35666bc060..b2f271cd784bc5ce41100ce123a6d1bf9a4f0a64 100644 (file)
@@ -41,4 +41,5 @@ Hotplug Firmware Loading for 2.6 kernels
 For 2.6 kernels the firmware is loaded at the point that the driver module is
 loaded.  See linux/Documentation/dvb/firmware.txt for more information.
 
-Copy the three files downloaded above into the /usr/lib/hotplug/firmware directory.
+Copy the three files downloaded above into the /usr/lib/hotplug/firmware or
+/lib/firmware directory (depending on configuration of firmware hotplug).
index f90cc66ea9197243c45326fdb034f3b947dd5870..9443a6d72cdd2a3884b04440d56451d03ab1f620 100644 (file)
@@ -11,4 +11,3 @@ Untested features
 
 All LCD stuff is untested. If it worked in tridentfb, it should work in
 cyblafb. Please test and report the results to Knut_Petersen@t-online.de.
-
index cf4351fc32ff691e0048159ee66a12a13fbb0e17..fe0e5223ba86cd9b3eb0920c4be0c56227f25204 100644 (file)
 #
 
 mode "640x480-50"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 47619 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-60"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 39682 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-70"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 34013 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-72"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 33068 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-75"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 31746 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-80"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 29761 4294967256 24 17 0 216 3
 endmode
 
 mode "640x480-85"
-    geometry 640 480 640 3756 8
+    geometry 640 480 2048 4096 8
     timings 28011 4294967256 24 17 0 216 3
 endmode
 
 mode "800x600-50"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 30303 96 24 14 0 136 11
 endmode
 
 mode "800x600-60"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 25252 96 24 14 0 136 11
 endmode
 
 mode "800x600-70"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 21645 96 24 14 0 136 11
 endmode
 
 mode "800x600-72"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 21043 96 24 14 0 136 11
 endmode
 
 mode "800x600-75"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 20202 96 24 14 0 136 11
 endmode
 
 mode "800x600-80"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 18939 96 24 14 0 136 11
 endmode
 
 mode "800x600-85"
-    geometry 800 600 800 3221 8
+    geometry 800 600 2048 4096 8
     timings 17825 96 24 14 0 136 11
 endmode
 
 mode "1024x768-50"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 19054 144 24 29 0 120 3
 endmode
 
 mode "1024x768-60"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 15880 144 24 29 0 120 3
 endmode
 
 mode "1024x768-70"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 13610 144 24 29 0 120 3
 endmode
 
 mode "1024x768-72"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 13232 144 24 29 0 120 3
 endmode
 
 mode "1024x768-75"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 12703 144 24 29 0 120 3
 endmode
 
 mode "1024x768-80"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 11910 144 24 29 0 120 3
 endmode
 
 mode "1024x768-85"
-    geometry 1024 768 1024 2815 8
+    geometry 1024 768 2048 4096 8
     timings 11209 144 24 29 0 120 3
 endmode
 
 mode "1280x1024-50"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 11114 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-60"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 9262 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-70"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 7939 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-72"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 7719 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-75"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 7410 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-80"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 6946 232 16 39 0 160 3
 endmode
 
 mode "1280x1024-85"
-    geometry 1280 1024 1280 2662 8
+    geometry 1280 1024 2048 4096 8
     timings 6538 232 16 39 0 160 3
 endmode
-
index eb4e47a9cea62befdf011ba72fa367f08d29ffc0..8d15d5dfc6b34a0f39cbdd63e1d52ff2069c5240 100644 (file)
@@ -77,4 +77,3 @@ patch that speeds up kernel bitblitting a lot ( > 20%).
 |          |                 |                 |                 |
 |          |                 |                 |                 |
 +-----------+-----------------+-----------------+-----------------+
-
index 80fb2f89b6c1731445206e0155f384bafd405205..c5f6d0eae5453173afd70f1a861fe2557abafc08 100644 (file)
@@ -22,11 +22,10 @@ accelerated color blitting  Who needs it? The console driver does use color
                                everything else is done using color expanding
                                blitting of 1bpp character bitmaps.
 
-xpanning                       Who needs it?
-
 ioctls                         Who needs it?
 
-TV-out                         Will be done later
+TV-out                         Will be done later. Use "vga= " at boot time
+                               to set a suitable video mode.
 
 ???                            Feel free to contact me if you have any
                                feature requests
index e627c8f542115c546fbde5f08d9e45c6e0316603..a39bb3d402a2b0c4ea3377caa42fa52b109c911a 100644 (file)
@@ -40,6 +40,16 @@ Selecting Modes
        None of the modes possible to select as startup modes are affected by
        the problems described at the end of the next subsection.
 
+       For all startup modes cyblafb chooses a virtual x resolution of 2048,
+       the only exception is mode 1280x1024 in combination with 32 bpp. This
+       allows ywrap scrolling for all those modes if rotation is 0 or 2, and
+       also fast scrolling if rotation is 1 or 3. The default virtual y reso-
+       lution is 4096 for bpp == 8, 2048 for bpp==16 and 1024 for bpp == 32,
+       again with the only exception of 1280x1024 at 32 bpp.
+
+       Please do set your video memory size to 8 Mb in the Bios setup. Other
+       values will work, but performace is decreased for a lot of modes.
+
        Mode changes using fbset
        ========================
 
@@ -54,20 +64,26 @@ Selecting Modes
                - if a flat panel is found, cyblafb does not allow you
                  to program a resolution higher than the physical
                  resolution of the flat panel monitor
-               - cyblafb does not allow xres to differ from xres_virtual
                - cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp
                  and (currently) 24 bit modes use a doubled vclk internally,
                  the dotclock limit as seen by fbset is 115 MHz for those
                  modes and 230 MHz for 8 and 16 bpp modes.
+               - cyblafb will allow you to select very high resolutions as
+                 long as the hardware can be programmed to these modes. The
+                 documented limit 1600x1200 is not enforced, but don't expect
+                 perfect signal quality.
 
-       Any request that violates the rules given above will be ignored and
-       fbset will return an error.
+       Any request that violates the rules given above will be either changed
+       to something the hardware supports or an error value will be returned.
 
        If you program a virtual y resolution higher than the hardware limit,
        cyblafb will silently decrease that value to the highest possible
-       value.
+       value. The same is true for a virtual x resolution that is not
+       supported by the hardware. Cyblafb tries to adapt vyres first because
+       vxres decides if ywrap scrolling is possible or not.
 
-       Attempts to disable acceleration are ignored.
+       Attempts to disable acceleration are ignored, I believe that this is
+       safe.
 
        Some video modes that should work do not work as expected. If you use
        the standard fb.modes, fbset 640x480-60 will program that mode, but
@@ -129,10 +145,6 @@ mode               640x480 or 800x600 or 1024x768 or 1280x1024
 verbosity      0 is the default, increase to at least 2 for every
                bug report!
 
-vesafb         allows cyblafb to be loaded after vesafb has been
-               loaded. See sections "Module unloading ...".
-
-
 Development hints
 =================
 
@@ -195,7 +207,7 @@ a graphics mode.
 After booting, load cyblafb without any mode and bpp parameter and assign
 cyblafb to individual ttys using con2fb, e.g.:
 
-       modprobe cyblafb vesafb=1
+       modprobe cyblafb
        con2fb /dev/fb1 /dev/tty1
 
 Unloading cyblafb works without problems after you assign vesafb to all
@@ -203,4 +215,3 @@ ttys again, e.g.:
 
        con2fb /dev/fb0 /dev/tty1
        rmmod cyblafb
-
diff --git a/Documentation/fb/cyblafb/whatsnew b/Documentation/fb/cyblafb/whatsnew
new file mode 100644 (file)
index 0000000..76c07a2
--- /dev/null
@@ -0,0 +1,29 @@
+0.62
+====
+
+      - the vesafb parameter has been removed as I decided to allow the
+       feature without any special parameter.
+
+      - Cyblafb does not use the vga style of panning any longer, now the
+       "right view" register in the graphics engine IO space is used. Without
+       that change it was impossible to use all available memory, and without
+       access to all available memory it is impossible to ywrap.
+
+      - The imageblit function now uses hardware acceleration for all font
+        widths. Hardware blitting across pixel column 2048 is broken in the
+       cyberblade/i1 graphics core, but we work around that hardware bug.
+
+      - modes with vxres != xres are supported now.
+
+      - ywrap scrolling is supported now and the default. This is a big
+        performance gain.
+
+      - default video modes use vyres > yres and vxres > xres to allow
+        almost optimal scrolling speed for normal and rotated screens
+
+      - some features mainly usefull for debugging the upper layers of the
+        framebuffer system have been added, have a look at the code
+
+      - fixed: Oops after unloading cyblafb when reading /proc/io*
+
+      - we work around some bugs of the higher framebuffer layers.
index 9840d5b8d5b9997621964653f6b3d348dd08f9b7..22e4040564d51d51a7d123e57e855f40d044dab6 100644 (file)
@@ -22,6 +22,11 @@ journal=inum         When a journal already exists, this option is
                        the inode which will represent the ext3 file
                        system's journal file.
 
+journal_dev=devnum     When the external journal device's major/minor numbers
+                       have changed, this option allows to specify the new
+                       journal location. The journal device is identified
+                       through its new major/minor numbers encoded in devnum.
+
 noload                 Don't load the journal on mounting.
 
 data=journal           All data are committed into the journal prior
index d4773565ea2f20fabf868505f8b48f2ea7b6295a..a4dcf42c2fd93f1e1177aad2abe567030ecbcdde 100644 (file)
@@ -1302,6 +1302,23 @@ VM has token based thrashing control mechanism and uses the token to prevent
 unnecessary page faults in thrashing situation. The unit of the value is
 second. The value would be useful to tune thrashing behavior.
 
+drop_caches
+-----------
+
+Writing to this will cause the kernel to drop clean caches, dentries and
+inodes from memory, causing that memory to become free.
+
+To free pagecache:
+       echo 1 > /proc/sys/vm/drop_caches
+To free dentries and inodes:
+       echo 2 > /proc/sys/vm/drop_caches
+To free pagecache, dentries and inodes:
+       echo 3 > /proc/sys/vm/drop_caches
+
+As this is a non-destructive operation and dirty objects are not freeable, the
+user should run `sync' first.
+
+
 2.5 /proc/sys/dev - Device specific parameters
 ----------------------------------------------
 
index b3404a0325967de5fdce4a29e879258075ede500..60ab61e54e8ab9dc05bc191f34fb17d1be5b01c3 100644 (file)
@@ -143,12 +143,26 @@ as the following example:
   dir /mnt 755 0 0
   file /init initramfs/init.sh 755 0 0
 
+Run "usr/gen_init_cpio" (after the kernel build) to get a usage message
+documenting the above file format.
+
 One advantage of the text file is that root access is not required to
 set permissions or create device nodes in the new archive.  (Note that those
 two example "file" entries expect to find files named "init.sh" and "busybox" in
 a directory called "initramfs", under the linux-2.6.* directory.  See
 Documentation/early-userspace/README for more details.)
 
+The kernel does not depend on external cpio tools, gen_init_cpio is created
+from usr/gen_init_cpio.c which is entirely self-contained, and the kernel's
+boot-time extractor is also (obviously) self-contained.  However, if you _do_
+happen to have cpio installed, the following command line can extract the
+generated cpio image back into its component files:
+
+  cpio -i -d -H newc -F initramfs_data.cpio --no-absolute-filenames
+
+Contents of initramfs:
+----------------------
+
 If you don't already understand what shared libraries, devices, and paths
 you need to get a minimal root filesystem up and running, here are some
 references:
@@ -161,13 +175,69 @@ designed to be a tiny C library to statically link early userspace
 code against, along with some related utilities.  It is BSD licensed.
 
 I use uClibc (http://www.uclibc.org) and busybox (http://www.busybox.net)
-myself.  These are LGPL and GPL, respectively.
+myself.  These are LGPL and GPL, respectively.  (A self-contained initramfs
+package is planned for the busybox 1.2 release.)
 
 In theory you could use glibc, but that's not well suited for small embedded
 uses like this.  (A "hello world" program statically linked against glibc is
 over 400k.  With uClibc it's 7k.  Also note that glibc dlopens libnss to do
 name lookups, even when otherwise statically linked.)
 
+Why cpio rather than tar?
+-------------------------
+
+This decision was made back in December, 2001.  The discussion started here:
+
+  http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1538.html
+
+And spawned a second thread (specifically on tar vs cpio), starting here:
+
+  http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1587.html
+
+The quick and dirty summary version (which is no substitute for reading
+the above threads) is:
+
+1) cpio is a standard.  It's decades old (from the AT&T days), and already
+   widely used on Linux (inside RPM, Red Hat's device driver disks).  Here's
+   a Linux Journal article about it from 1996:
+
+      http://www.linuxjournal.com/article/1213
+
+   It's not as popular as tar because the traditional cpio command line tools
+   require _truly_hideous_ command line arguments.  But that says nothing
+   either way about the archive format, and there are alternative tools,
+   such as:
+
+     http://freshmeat.net/projects/afio/
+
+2) The cpio archive format chosen by the kernel is simpler and cleaner (and
+   thus easier to create and parse) than any of the (literally dozens of)
+   various tar archive formats.  The complete initramfs archive format is
+   explained in buffer-format.txt, created in usr/gen_init_cpio.c, and
+   extracted in init/initramfs.c.  All three together come to less than 26k
+   total of human-readable text.
+
+3) The GNU project standardizing on tar is approximately as relevant as
+   Windows standardizing on zip.  Linux is not part of either, and is free
+   to make its own technical decisions.
+
+4) Since this is a kernel internal format, it could easily have been
+   something brand new.  The kernel provides its own tools to create and
+   extract this format anyway.  Using an existing standard was preferable,
+   but not essential.
+
+5) Al Viro made the decision (quote: "tar is ugly as hell and not going to be
+   supported on the kernel side"):
+
+      http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1540.html
+
+   explained his reasoning:
+
+      http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1550.html
+      http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1638.html
+
+   and, most importantly, designed and implemented the initramfs code.
+
 Future directions:
 ------------------
 
index d803abed29f01dcf2072486000750f88f0b564d5..5832377b7340ed4b811b1a5ad12cad4147a2c9bf 100644 (file)
@@ -44,30 +44,41 @@ relayfs can operate in a mode where it will overwrite data not yet
 collected by userspace, and not wait for it to consume it.
 
 relayfs itself does not provide for communication of such data between
-userspace and kernel, allowing the kernel side to remain simple and not
-impose a single interface on userspace. It does provide a separate
-helper though, described below.
+userspace and kernel, allowing the kernel side to remain simple and
+not impose a single interface on userspace. It does provide a set of
+examples and a separate helper though, described below.
+
+klog and relay-apps example code
+================================
+
+relayfs itself is ready to use, but to make things easier, a couple
+simple utility functions and a set of examples are provided.
+
+The relay-apps example tarball, available on the relayfs sourceforge
+site, contains a set of self-contained examples, each consisting of a
+pair of .c files containing boilerplate code for each of the user and
+kernel sides of a relayfs application; combined these two sets of
+boilerplate code provide glue to easily stream data to disk, without
+having to bother with mundane housekeeping chores.
+
+The 'klog debugging functions' patch (klog.patch in the relay-apps
+tarball) provides a couple of high-level logging functions to the
+kernel which allow writing formatted text or raw data to a channel,
+regardless of whether a channel to write into exists or not, or
+whether relayfs is compiled into the kernel or is configured as a
+module.  These functions allow you to put unconditional 'trace'
+statements anywhere in the kernel or kernel modules; only when there
+is a 'klog handler' registered will data actually be logged (see the
+klog and kleak examples for details).
+
+It is of course possible to use relayfs from scratch i.e. without
+using any of the relay-apps example code or klog, but you'll have to
+implement communication between userspace and kernel, allowing both to
+convey the state of buffers (full, empty, amount of padding).
+
+klog and the relay-apps examples can be found in the relay-apps
+tarball on http://relayfs.sourceforge.net
 
-klog, relay-app & librelay
-==========================
-
-relayfs itself is ready to use, but to make things easier, two
-additional systems are provided.  klog is a simple wrapper to make
-writing formatted text or raw data to a channel simpler, regardless of
-whether a channel to write into exists or not, or whether relayfs is
-compiled into the kernel or is configured as a module.  relay-app is
-the kernel counterpart of userspace librelay.c, combined these two
-files provide glue to easily stream data to disk, without having to
-bother with housekeeping.  klog and relay-app can be used together,
-with klog providing high-level logging functions to the kernel and
-relay-app taking care of kernel-user control and disk-logging chores.
-
-It is possible to use relayfs without relay-app & librelay, but you'll
-have to implement communication between userspace and kernel, allowing
-both to convey the state of buffers (full, empty, amount of padding).
-
-klog, relay-app and librelay can be found in the relay-apps tarball on
-http://relayfs.sourceforge.net
 
 The relayfs user space API
 ==========================
@@ -125,6 +136,8 @@ Here's a summary of the API relayfs provides to in-kernel clients:
     relay_reset(chan)
     relayfs_create_dir(name, parent)
     relayfs_remove_dir(dentry)
+    relayfs_create_file(name, parent, mode, fops, data)
+    relayfs_remove_file(dentry)
 
   channel management typically called on instigation of userspace:
 
@@ -141,6 +154,8 @@ Here's a summary of the API relayfs provides to in-kernel clients:
     subbuf_start(buf, subbuf, prev_subbuf, prev_padding)
     buf_mapped(buf, filp)
     buf_unmapped(buf, filp)
+    create_buf_file(filename, parent, mode, buf, is_global)
+    remove_buf_file(dentry)
 
   helper functions:
 
@@ -320,6 +335,71 @@ forces a sub-buffer switch on all the channel buffers, and can be used
 to finalize and process the last sub-buffers before the channel is
 closed.
 
+Creating non-relay files
+------------------------
+
+relay_open() automatically creates files in the relayfs filesystem to
+represent the per-cpu kernel buffers; it's often useful for
+applications to be able to create their own files alongside the relay
+files in the relayfs filesystem as well e.g. 'control' files much like
+those created in /proc or debugfs for similar purposes, used to
+communicate control information between the kernel and user sides of a
+relayfs application.  For this purpose the relayfs_create_file() and
+relayfs_remove_file() API functions exist.  For relayfs_create_file(),
+the caller passes in a set of user-defined file operations to be used
+for the file and an optional void * to a user-specified data item,
+which will be accessible via inode->u.generic_ip (see the relay-apps
+tarball for examples).  The file_operations are a required parameter
+to relayfs_create_file() and thus the semantics of these files are
+completely defined by the caller.
+
+See the relay-apps tarball at http://relayfs.sourceforge.net for
+examples of how these non-relay files are meant to be used.
+
+Creating relay files in other filesystems
+-----------------------------------------
+
+By default of course, relay_open() creates relay files in the relayfs
+filesystem.  Because relay_file_operations is exported, however, it's
+also possible to create and use relay files in other pseudo-filesytems
+such as debugfs.
+
+For this purpose, two callback functions are provided,
+create_buf_file() and remove_buf_file().  create_buf_file() is called
+once for each per-cpu buffer from relay_open() to allow the client to
+create a file to be used to represent the corresponding buffer; if
+this callback is not defined, the default implementation will create
+and return a file in the relayfs filesystem to represent the buffer.
+The callback should return the dentry of the file created to represent
+the relay buffer.  Note that the parent directory passed to
+relay_open() (and passed along to the callback), if specified, must
+exist in the same filesystem the new relay file is created in.  If
+create_buf_file() is defined, remove_buf_file() must also be defined;
+it's responsible for deleting the file(s) created in create_buf_file()
+and is called during relay_close().
+
+The create_buf_file() implementation can also be defined in such a way
+as to allow the creation of a single 'global' buffer instead of the
+default per-cpu set.  This can be useful for applications interested
+mainly in seeing the relative ordering of system-wide events without
+the need to bother with saving explicit timestamps for the purpose of
+merging/sorting per-cpu files in a postprocessing step.
+
+To have relay_open() create a global buffer, the create_buf_file()
+implementation should set the value of the is_global outparam to a
+non-zero value in addition to creating the file that will be used to
+represent the single buffer.  In the case of a global buffer,
+create_buf_file() and remove_buf_file() will be called only once.  The
+normal channel-writing functions e.g. relay_write() can still be used
+- writes from any cpu will transparently end up in the global buffer -
+but since it is a global buffer, callers should make sure they use the
+proper locking for such a buffer, either by wrapping writes in a
+spinlock, or by copying a write function from relayfs_fs.h and
+creating a local version that internally does the proper locking.
+
+See the 'exported-relayfile' examples in the relay-apps tarball for
+examples of creating and using relay files in debugfs.
+
 Misc
 ----
 
diff --git a/Documentation/filesystems/spufs.txt b/Documentation/filesystems/spufs.txt
new file mode 100644 (file)
index 0000000..8edc395
--- /dev/null
@@ -0,0 +1,521 @@
+SPUFS(2)                   Linux Programmer's Manual                  SPUFS(2)
+
+
+
+NAME
+       spufs - the SPU file system
+
+
+DESCRIPTION
+       The SPU file system is used on PowerPC machines that implement the Cell
+       Broadband Engine Architecture in order to access Synergistic  Processor
+       Units (SPUs).
+
+       The file system provides a name space similar to posix shared memory or
+       message queues. Users that have write permissions on  the  file  system
+       can use spu_create(2) to establish SPU contexts in the spufs root.
+
+       Every SPU context is represented by a directory containing a predefined
+       set of files. These files can be used for manipulating the state of the
+       logical SPU. Users can change permissions on those files, but not actu-
+       ally add or remove files.
+
+
+MOUNT OPTIONS
+       uid=<uid>
+              set the user owning the mount point, the default is 0 (root).
+
+       gid=<gid>
+              set the group owning the mount point, the default is 0 (root).
+
+
+FILES
+       The files in spufs mostly follow the standard behavior for regular sys-
+       tem  calls like read(2) or write(2), but often support only a subset of
+       the operations supported on regular file systems. This list details the
+       supported  operations  and  the  deviations  from  the behaviour in the
+       respective man pages.
+
+       All files that support the read(2) operation also support readv(2)  and
+       all  files  that support the write(2) operation also support writev(2).
+       All files support the access(2) and stat(2) family of  operations,  but
+       only  the  st_mode,  st_nlink,  st_uid and st_gid fields of struct stat
+       contain reliable information.
+
+       All files support the chmod(2)/fchmod(2) and chown(2)/fchown(2)  opera-
+       tions,  but  will  not be able to grant permissions that contradict the
+       possible operations, e.g. read access on the wbox file.
+
+       The current set of files is:
+
+
+   /mem
+       the contents of the local storage memory  of  the  SPU.   This  can  be
+       accessed  like  a regular shared memory file and contains both code and
+       data in the address space of the SPU.  The possible  operations  on  an
+       open mem file are:
+
+       read(2), pread(2), write(2), pwrite(2), lseek(2)
+              These  operate  as  documented, with the exception that seek(2),
+              write(2) and pwrite(2) are not supported beyond the end  of  the
+              file. The file size is the size of the local storage of the SPU,
+              which normally is 256 kilobytes.
+
+       mmap(2)
+              Mapping mem into the process address space gives access  to  the
+              SPU  local  storage  within  the  process  address  space.  Only
+              MAP_SHARED mappings are allowed.
+
+
+   /mbox
+       The first SPU to CPU communication mailbox. This file is read-only  and
+       can  be  read  in  units of 32 bits.  The file can only be used in non-
+       blocking mode and it even poll() will not block on  it.   The  possible
+       operations on an open mbox file are:
+
+       read(2)
+              If  a  count smaller than four is requested, read returns -1 and
+              sets errno to EINVAL.  If there is no data available in the mail
+              box,  the  return  value  is set to -1 and errno becomes EAGAIN.
+              When data has been read successfully, four bytes are  placed  in
+              the data buffer and the value four is returned.
+
+
+   /ibox
+       The  second  SPU  to CPU communication mailbox. This file is similar to
+       the first mailbox file, but can be read in blocking I/O mode,  and  the
+       poll  familiy of system calls can be used to wait for it.  The possible
+       operations on an open ibox file are:
+
+       read(2)
+              If a count smaller than four is requested, read returns  -1  and
+              sets errno to EINVAL.  If there is no data available in the mail
+              box and the file descriptor has been opened with O_NONBLOCK, the
+              return value is set to -1 and errno becomes EAGAIN.
+
+              If  there  is  no  data  available  in the mail box and the file
+              descriptor has been opened without  O_NONBLOCK,  the  call  will
+              block  until  the  SPU  writes to its interrupt mailbox channel.
+              When data has been read successfully, four bytes are  placed  in
+              the data buffer and the value four is returned.
+
+       poll(2)
+              Poll  on  the  ibox  file returns (POLLIN | POLLRDNORM) whenever
+              data is available for reading.
+
+
+   /wbox
+       The CPU to SPU communation mailbox. It is write-only can can be written
+       in  units  of  32  bits. If the mailbox is full, write() will block and
+       poll can be used to wait for it becoming  empty  again.   The  possible
+       operations  on  an open wbox file are: write(2) If a count smaller than
+       four is requested, write returns -1 and sets errno to EINVAL.  If there
+       is  no space available in the mail box and the file descriptor has been
+       opened with O_NONBLOCK, the return value is set to -1 and errno becomes
+       EAGAIN.
+
+       If  there is no space available in the mail box and the file descriptor
+       has been opened without O_NONBLOCK, the call will block until  the  SPU
+       reads  from  its PPE mailbox channel.  When data has been read success-
+       fully, four bytes are placed in the data buffer and the value  four  is
+       returned.
+
+       poll(2)
+              Poll  on  the  ibox file returns (POLLOUT | POLLWRNORM) whenever
+              space is available for writing.
+
+
+   /mbox_stat
+   /ibox_stat
+   /wbox_stat
+       Read-only files that contain the length of the current queue, i.e.  how
+       many  words  can  be  read  from  mbox or ibox or how many words can be
+       written to wbox without blocking.  The files can be read only in 4-byte
+       units  and  return  a  big-endian  binary integer number.  The possible
+       operations on an open *box_stat file are:
+
+       read(2)
+              If a count smaller than four is requested, read returns  -1  and
+              sets errno to EINVAL.  Otherwise, a four byte value is placed in
+              the data buffer, containing the number of elements that  can  be
+              read  from  (for  mbox_stat  and  ibox_stat)  or written to (for
+              wbox_stat) the respective mail box without blocking or resulting
+              in EAGAIN.
+
+
+   /npc
+   /decr
+   /decr_status
+   /spu_tag_mask
+   /event_mask
+   /srr0
+       Internal  registers  of  the SPU. The representation is an ASCII string
+       with the numeric value of the next instruction to  be  executed.  These
+       can  be  used in read/write mode for debugging, but normal operation of
+       programs should not rely on them because access to any of  them  except
+       npc requires an SPU context save and is therefore very inefficient.
+
+       The contents of these files are:
+
+       npc                 Next Program Counter
+
+       decr                SPU Decrementer
+
+       decr_status         Decrementer Status
+
+       spu_tag_mask        MFC tag mask for SPU DMA
+
+       event_mask          Event mask for SPU interrupts
+
+       srr0                Interrupt Return address register
+
+
+       The   possible   operations   on   an   open  npc,  decr,  decr_status,
+       spu_tag_mask, event_mask or srr0 file are:
+
+       read(2)
+              When the count supplied to the read call  is  shorter  than  the
+              required  length for the pointer value plus a newline character,
+              subsequent reads from the same file descriptor  will  result  in
+              completing  the string, regardless of changes to the register by
+              a running SPU task.  When a complete string has been  read,  all
+              subsequent read operations will return zero bytes and a new file
+              descriptor needs to be opened to read the value again.
+
+       write(2)
+              A write operation on the file results in setting the register to
+              the  value  given  in  the string. The string is parsed from the
+              beginning to the first non-numeric character or the end  of  the
+              buffer.  Subsequent writes to the same file descriptor overwrite
+              the previous setting.
+
+
+   /fpcr
+       This file gives access to the Floating Point Status and Control  Regis-
+       ter as a four byte long file. The operations on the fpcr file are:
+
+       read(2)
+              If  a  count smaller than four is requested, read returns -1 and
+              sets errno to EINVAL.  Otherwise, a four byte value is placed in
+              the data buffer, containing the current value of the fpcr regis-
+              ter.
+
+       write(2)
+              If a count smaller than four is requested, write returns -1  and
+              sets  errno  to  EINVAL.  Otherwise, a four byte value is copied
+              from the data buffer, updating the value of the fpcr register.
+
+
+   /signal1
+   /signal2
+       The two signal notification channels of an SPU.  These  are  read-write
+       files  that  operate  on  a 32 bit word.  Writing to one of these files
+       triggers an interrupt on the SPU. The  value  writting  to  the  signal
+       files can be read from the SPU through a channel read or from host user
+       space through the file.  After the value has been read by the  SPU,  it
+       is  reset  to zero.  The possible operations on an open signal1 or sig-
+       nal2 file are:
+
+       read(2)
+              If a count smaller than four is requested, read returns  -1  and
+              sets errno to EINVAL.  Otherwise, a four byte value is placed in
+              the data buffer, containing the current value of  the  specified
+              signal notification register.
+
+       write(2)
+              If  a count smaller than four is requested, write returns -1 and
+              sets errno to EINVAL.  Otherwise, a four byte  value  is  copied
+              from the data buffer, updating the value of the specified signal
+              notification register.  The signal  notification  register  will
+              either be replaced with the input data or will be updated to the
+              bitwise OR or the old value and the input data, depending on the
+              contents  of  the  signal1_type,  or  signal2_type respectively,
+              file.
+
+
+   /signal1_type
+   /signal2_type
+       These two files change the behavior of the signal1 and signal2  notifi-
+       cation  files.  The  contain  a numerical ASCII string which is read as
+       either "1" or "0".  In mode 0 (overwrite), the  hardware  replaces  the
+       contents of the signal channel with the data that is written to it.  in
+       mode 1 (logical OR), the hardware accumulates the bits that are  subse-
+       quently written to it.  The possible operations on an open signal1_type
+       or signal2_type file are:
+
+       read(2)
+              When the count supplied to the read call  is  shorter  than  the
+              required  length  for the digit plus a newline character, subse-
+              quent reads from the same file descriptor will  result  in  com-
+              pleting  the  string.  When a complete string has been read, all
+              subsequent read operations will return zero bytes and a new file
+              descriptor needs to be opened to read the value again.
+
+       write(2)
+              A write operation on the file results in setting the register to
+              the value given in the string. The string  is  parsed  from  the
+              beginning  to  the first non-numeric character or the end of the
+              buffer.  Subsequent writes to the same file descriptor overwrite
+              the previous setting.
+
+
+EXAMPLES
+       /etc/fstab entry
+              none      /spu      spufs     gid=spu   0    0
+
+
+AUTHORS
+       Arnd  Bergmann  <arndb@de.ibm.com>,  Mark  Nutter <mnutter@us.ibm.com>,
+       Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+SEE ALSO
+       capabilities(7), close(2), spu_create(2), spu_run(2), spufs(7)
+
+
+
+Linux                             2005-09-28                          SPUFS(2)
+
+------------------------------------------------------------------------------
+
+SPU_RUN(2)                 Linux Programmer's Manual                SPU_RUN(2)
+
+
+
+NAME
+       spu_run - execute an spu context
+
+
+SYNOPSIS
+       #include <sys/spu.h>
+
+       int spu_run(int fd, unsigned int *npc, unsigned int *event);
+
+DESCRIPTION
+       The  spu_run system call is used on PowerPC machines that implement the
+       Cell Broadband Engine Architecture in order to access Synergistic  Pro-
+       cessor  Units  (SPUs).  It  uses the fd that was returned from spu_cre-
+       ate(2) to address a specific SPU context. When the context gets  sched-
+       uled  to a physical SPU, it starts execution at the instruction pointer
+       passed in npc.
+
+       Execution of SPU code happens synchronously, meaning that spu_run  does
+       not  return  while the SPU is still running. If there is a need to exe-
+       cute SPU code in parallel with other code on either  the  main  CPU  or
+       other  SPUs,  you  need to create a new thread of execution first, e.g.
+       using the pthread_create(3) call.
+
+       When spu_run returns, the current value of the SPU instruction  pointer
+       is  written back to npc, so you can call spu_run again without updating
+       the pointers.
+
+       event can be a NULL pointer or point to an extended  status  code  that
+       gets  filled  when spu_run returns. It can be one of the following con-
+       stants:
+
+       SPE_EVENT_DMA_ALIGNMENT
+              A DMA alignment error
+
+       SPE_EVENT_SPE_DATA_SEGMENT
+              A DMA segmentation error
+
+       SPE_EVENT_SPE_DATA_STORAGE
+              A DMA storage error
+
+       If NULL is passed as the event argument, these errors will result in  a
+       signal delivered to the calling process.
+
+RETURN VALUE
+       spu_run  returns the value of the spu_status register or -1 to indicate
+       an error and set errno to one of the error  codes  listed  below.   The
+       spu_status  register  value  contains  a  bit  mask of status codes and
+       optionally a 14 bit code returned from the stop-and-signal  instruction
+       on the SPU. The bit masks for the status codes are:
+
+       0x02   SPU was stopped by stop-and-signal.
+
+       0x04   SPU was stopped by halt.
+
+       0x08   SPU is waiting for a channel.
+
+       0x10   SPU is in single-step mode.
+
+       0x20   SPU has tried to execute an invalid instruction.
+
+       0x40   SPU has tried to access an invalid channel.
+
+       0x3fff0000
+              The  bits  masked with this value contain the code returned from
+              stop-and-signal.
+
+       There are always one or more of the lower eight bits set  or  an  error
+       code is returned from spu_run.
+
+ERRORS
+       EAGAIN or EWOULDBLOCK
+              fd is in non-blocking mode and spu_run would block.
+
+       EBADF  fd is not a valid file descriptor.
+
+       EFAULT npc is not a valid pointer or status is neither NULL nor a valid
+              pointer.
+
+       EINTR  A signal occured while spu_run was in progress.  The  npc  value
+              has  been updated to the new program counter value if necessary.
+
+       EINVAL fd is not a file descriptor returned from spu_create(2).
+
+       ENOMEM Insufficient memory was available to handle a page fault result-
+              ing from an MFC direct memory access.
+
+       ENOSYS the functionality is not provided by the current system, because
+              either the hardware does not provide SPUs or the spufs module is
+              not loaded.
+
+
+NOTES
+       spu_run  is  meant  to  be  used  from  libraries that implement a more
+       abstract interface to SPUs, not to be used from  regular  applications.
+       See  http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec-
+       ommended libraries.
+
+
+CONFORMING TO
+       This call is Linux specific and only implemented by the ppc64 architec-
+       ture. Programs using this system call are not portable.
+
+
+BUGS
+       The code does not yet fully implement all features lined out here.
+
+
+AUTHOR
+       Arnd Bergmann <arndb@de.ibm.com>
+
+SEE ALSO
+       capabilities(7), close(2), spu_create(2), spufs(7)
+
+
+
+Linux                             2005-09-28                        SPU_RUN(2)
+
+------------------------------------------------------------------------------
+
+SPU_CREATE(2)              Linux Programmer's Manual             SPU_CREATE(2)
+
+
+
+NAME
+       spu_create - create a new spu context
+
+
+SYNOPSIS
+       #include <sys/types.h>
+       #include <sys/spu.h>
+
+       int spu_create(const char *pathname, int flags, mode_t mode);
+
+DESCRIPTION
+       The  spu_create  system call is used on PowerPC machines that implement
+       the Cell Broadband Engine Architecture in order to  access  Synergistic
+       Processor  Units (SPUs). It creates a new logical context for an SPU in
+       pathname and returns a handle to associated  with  it.   pathname  must
+       point  to  a  non-existing directory in the mount point of the SPU file
+       system (spufs).  When spu_create is successful, a directory  gets  cre-
+       ated on pathname and it is populated with files.
+
+       The  returned  file  handle can only be passed to spu_run(2) or closed,
+       other operations are not defined on it. When it is closed, all  associ-
+       ated  directory entries in spufs are removed. When the last file handle
+       pointing either inside  of  the  context  directory  or  to  this  file
+       descriptor is closed, the logical SPU context is destroyed.
+
+       The  parameter flags can be zero or any bitwise or'd combination of the
+       following constants:
+
+       SPU_RAWIO
+              Allow mapping of some of the hardware registers of the SPU  into
+              user space. This flag requires the CAP_SYS_RAWIO capability, see
+              capabilities(7).
+
+       The mode parameter specifies the permissions used for creating the  new
+       directory  in  spufs.   mode is modified with the user's umask(2) value
+       and then used for both the directory and the files contained in it. The
+       file permissions mask out some more bits of mode because they typically
+       support only read or write access. See stat(2) for a full list  of  the
+       possible mode values.
+
+
+RETURN VALUE
+       spu_create  returns a new file descriptor. It may return -1 to indicate
+       an error condition and set errno to  one  of  the  error  codes  listed
+       below.
+
+
+ERRORS
+       EACCESS
+              The  current  user does not have write access on the spufs mount
+              point.
+
+       EEXIST An SPU context already exists at the given path name.
+
+       EFAULT pathname is not a valid string pointer in  the  current  address
+              space.
+
+       EINVAL pathname is not a directory in the spufs mount point.
+
+       ELOOP  Too many symlinks were found while resolving pathname.
+
+       EMFILE The process has reached its maximum open file limit.
+
+       ENAMETOOLONG
+              pathname was too long.
+
+       ENFILE The system has reached the global open file limit.
+
+       ENOENT Part of pathname could not be resolved.
+
+       ENOMEM The kernel could not allocate all resources required.
+
+       ENOSPC There  are  not  enough  SPU resources available to create a new
+              context or the user specific limit for the number  of  SPU  con-
+              texts has been reached.
+
+       ENOSYS the functionality is not provided by the current system, because
+              either the hardware does not provide SPUs or the spufs module is
+              not loaded.
+
+       ENOTDIR
+              A part of pathname is not a directory.
+
+
+
+NOTES
+       spu_create  is  meant  to  be used from libraries that implement a more
+       abstract interface to SPUs, not to be used from  regular  applications.
+       See  http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec-
+       ommended libraries.
+
+
+FILES
+       pathname must point to a location beneath the mount point of spufs.  By
+       convention, it gets mounted in /spu.
+
+
+CONFORMING TO
+       This call is Linux specific and only implemented by the ppc64 architec-
+       ture. Programs using this system call are not portable.
+
+
+BUGS
+       The code does not yet fully implement all features lined out here.
+
+
+AUTHOR
+       Arnd Bergmann <arndb@de.ibm.com>
+
+SEE ALSO
+       capabilities(7), close(2), spu_run(2), spufs(7)
+
+
+
+Linux                             2005-09-28                     SPU_CREATE(2)
index 5f2b9c5edbb517be9814ca65b5b0f8bb51f38e41..22488d7911681e8b40cf43a93439f550fa0f93dc 100644 (file)
@@ -56,10 +56,12 @@ A request proceeds in the following manner:
  (4) request_key() then forks and executes /sbin/request-key with a new session
      keyring that contains a link to auth key V.
 
- (5) /sbin/request-key execs an appropriate program to perform the actual
+ (5) /sbin/request-key assumes the authority associated with key U.
+
+ (6) /sbin/request-key execs an appropriate program to perform the actual
      instantiation.
 
- (6) The program may want to access another key from A's context (say a
+ (7) The program may want to access another key from A's context (say a
      Kerberos TGT key). It just requests the appropriate key, and the keyring
      search notes that the session keyring has auth key V in its bottom level.
 
@@ -67,19 +69,19 @@ A request proceeds in the following manner:
      UID, GID, groups and security info of process A as if it was process A,
      and come up with key W.
 
- (7) The program then does what it must to get the data with which to
+ (8) The program then does what it must to get the data with which to
      instantiate key U, using key W as a reference (perhaps it contacts a
      Kerberos server using the TGT) and then instantiates key U.
 
- (8) Upon instantiating key U, auth key V is automatically revoked so that it
+ (9) Upon instantiating key U, auth key V is automatically revoked so that it
      may not be used again.
 
- (9) The program then exits 0 and request_key() deletes key V and returns key
+(10) The program then exits 0 and request_key() deletes key V and returns key
      U to the caller.
 
-This also extends further. If key W (step 5 above) didn't exist, key W would be
-created uninstantiated, another auth key (X) would be created [as per step 3]
-and another copy of /sbin/request-key spawned [as per step 4]; but the context
+This also extends further. If key W (step 7 above) didn't exist, key W would be
+created uninstantiated, another auth key (X) would be created (as per step 3)
+and another copy of /sbin/request-key spawned (as per step 4); but the context
 specified by auth key X will still be process A, as it was in auth key V.
 
 This is because process A's keyrings can't simply be attached to
@@ -138,8 +140,8 @@ until one succeeds:
 
  (3) The process's session keyring is searched.
 
- (4) If the process has a request_key() authorisation key in its session
-     keyring then:
+ (4) If the process has assumed the authority associated with a request_key()
+     authorisation key then:
 
      (a) If extant, the calling process's thread keyring is searched.
 
index 6304db59bfe45619c198494c54705b8f5610a585..aaa01b0e3ee94251476d15f2ae6574844af9bb16 100644 (file)
@@ -308,6 +308,8 @@ process making the call:
        KEY_SPEC_USER_KEYRING           -4      UID-specific keyring
        KEY_SPEC_USER_SESSION_KEYRING   -5      UID-session keyring
        KEY_SPEC_GROUP_KEYRING          -6      GID-specific keyring
+       KEY_SPEC_REQKEY_AUTH_KEY        -7      assumed request_key()
+                                                 authorisation key
 
 
 The main syscalls are:
@@ -498,7 +500,11 @@ The keyctl syscall functions are:
      keyring is full, error ENFILE will result.
 
      The link procedure checks the nesting of the keyrings, returning ELOOP if
-     it appears to deep or EDEADLK if the link would introduce a cycle.
+     it appears too deep or EDEADLK if the link would introduce a cycle.
+
+     Any links within the keyring to keys that match the new key in terms of
+     type and description will be discarded from the keyring as the new one is
+     added.
 
 
  (*) Unlink a key or keyring from another keyring:
@@ -628,6 +634,41 @@ The keyctl syscall functions are:
      there is one, otherwise the user default session keyring.
 
 
+ (*) Set the timeout on a key.
+
+       long keyctl(KEYCTL_SET_TIMEOUT, key_serial_t key, unsigned timeout);
+
+     This sets or clears the timeout on a key. The timeout can be 0 to clear
+     the timeout or a number of seconds to set the expiry time that far into
+     the future.
+
+     The process must have attribute modification access on a key to set its
+     timeout. Timeouts may not be set with this function on negative, revoked
+     or expired keys.
+
+
+ (*) Assume the authority granted to instantiate a key
+
+       long keyctl(KEYCTL_ASSUME_AUTHORITY, key_serial_t key);
+
+     This assumes or divests the authority required to instantiate the
+     specified key. Authority can only be assumed if the thread has the
+     authorisation key associated with the specified key in its keyrings
+     somewhere.
+
+     Once authority is assumed, searches for keys will also search the
+     requester's keyrings using the requester's security label, UID, GID and
+     groups.
+
+     If the requested authority is unavailable, error EPERM will be returned,
+     likewise if the authority has been revoked because the target key is
+     already instantiated.
+
+     If the specified key is 0, then any assumed authority will be divested.
+
+     The assumed authorititive key is inherited across fork and exec.
+
+
 ===============
 KERNEL SERVICES
 ===============
index 0541fe1de70482e74fa2f10c409130b1ac21ef4b..0ea5a0c6e8277f9691f21aed46edfa923d30adf4 100644 (file)
@@ -411,7 +411,8 @@ int init_module(void)
                printk("Couldn't find %s to plant kprobe\n", "do_fork");
                return -1;
        }
-       if ((ret = register_kprobe(&kp) < 0)) {
+       ret = register_kprobe(&kp);
+       if (ret < 0) {
                printk("register_kprobe failed, returned %d\n", ret);
                return -1;
        }
index b0fe41da007bf847e8ae2da4c4b2b840461d9353..8d8b4e5ea184a26da6bfab62bed0f796ce16679a 100644 (file)
@@ -945,7 +945,6 @@ bond0     Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4
           collisions:0 txqueuelen:0
 
 eth0      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4
-          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
           UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
           RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0
           TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0
@@ -953,7 +952,6 @@ eth0      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4
           Interrupt:10 Base address:0x1080
 
 eth1      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4
-          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
           UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
           RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0
           TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0
index e7bea0a407b4d5939ebb3866d42e1a1175da2b38..d6d65b9bcfe325c6360183093975b89b19073c68 100644 (file)
@@ -8,12 +8,18 @@ please mail me.
 cpu_features.txt
        - info on how we support a variety of CPUs with minimal compile-time
        options.
+eeh-pci-error-recovery.txt
+       - info on PCI Bus EEH Error Recovery
+hvcs.txt
+       - IBM "Hypervisor Virtual Console Server" Installation Guide
+mpc52xx.txt
+       - Linux 2.6.x on MPC52xx family
 ppc_htab.txt
        - info about the Linux/PPC /proc/ppc_htab entry
-smp.txt
-       - use and state info about Linux/PPC on MP machines
 SBC8260_memory_mapping.txt
        - EST SBC8260 board info
+smp.txt
+       - use and state info about Linux/PPC on MP machines
 sound.txt
        - info on sound support under Linux/PPC
 zImage_layout.txt
index 2f1aae32a5d9dfc2c0f71bb0400ce4a714d49c07..6910c0136f8d7e23458ef0279fbf7b301c3fdd0b 100644 (file)
@@ -26,12 +26,13 @@ Currently, these files are in /proc/sys/vm:
 - min_free_kbytes
 - laptop_mode
 - block_dump
+- drop-caches
 
 ==============================================================
 
 dirty_ratio, dirty_background_ratio, dirty_expire_centisecs,
 dirty_writeback_centisecs, vfs_cache_pressure, laptop_mode,
-block_dump, swap_token_timeout:
+block_dump, swap_token_timeout, drop-caches:
 
 See Documentation/filesystems/proc.txt
 
@@ -102,3 +103,20 @@ This is used to force the Linux VM to keep a minimum number
 of kilobytes free.  The VM uses this number to compute a pages_min
 value for each lowmem zone in the system.  Each lowmem zone gets 
 a number of reserved free pages based proportionally on its size.
+
+==============================================================
+
+percpu_pagelist_fraction
+
+This is the fraction of pages at most (high mark pcp->high) in each zone that
+are allocated for each per cpu page list.  The min value for this is 8.  It
+means that we don't allow more than 1/8th of pages in each zone to be
+allocated in any single per_cpu_pagelist.  This entry only changes the value
+of hot per cpu pagelists.  User can specify a number like 100 to allocate
+1/100th of each zone to each per cpu page list.
+
+The batch value of each per cpu pagelist is also updated as a result.  It is
+set to pcp->high/4.  The upper limit of batch is (PAGE_SHIFT * 8)
+
+The initial value is zero.  Kernel does not use this value at boot time to set
+the high water marks for each per cpu page list.
index 330246ac80f80f282e987d83d78acac8856ddc14..74fb085e178b9da6c37cd3efa0224626665ec371 100644 (file)
 140 -> Osprey 440                                          [0070:ff07]
 141 -> Asound Skyeye PCTV
 142 -> Sabrent TV-FM (bttv version)
+143 -> Hauppauge ImpactVCB (bt878)                         [0070:13eb]
index a1017d1a85d4b83988865fc47af683023fa22ba6..34b6e59f2968244421e23739d852b69610f83393 100644 (file)
@@ -16,7 +16,7 @@
  15 -> DViCO FusionHDTV DVB-T1                             [18ac:db00]
  16 -> KWorld LTV883RF
  17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810]
- 18 -> Hauppauge Nova-T DVB-T                              [0070:9002]
+ 18 -> Hauppauge Nova-T DVB-T                              [0070:9002,0070:9001]
  19 -> Conexant DVB-T reference design                     [14f1:0187]
  20 -> Provideo PV259                                      [1540:2580]
  21 -> DViCO FusionHDTV DVB-T Plus                         [18ac:db10]
  34 -> ATI HDTV Wonder                                     [1002:a101]
  35 -> WinFast DTV1000-T                                   [107d:665f]
  36 -> AVerTV 303 (M126)                                   [1461:000a]
+ 37 -> Hauppauge Nova-S-Plus DVB-S                         [0070:9201,0070:9202]
+ 38 -> Hauppauge Nova-SE2 DVB-S                            [0070:9200]
+ 39 -> KWorld DVB-S 100                                    [17de:08b2]
+ 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid                [0070:9400,0070:9402]
+ 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)  [0070:9800,0070:9802]
+ 42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025]
+ 43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1]
+ 44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50]
index efb708ec116ace349ccabdb31ccc0a1123fe5238..cb3a59bbeb172b0aad3a7b95e6a9123482a340ae 100644 (file)
@@ -56,7 +56,7 @@
  55 -> LifeView FlyDVB-T DUO                    [5168:0502,5168:0306]
  56 -> Avermedia AVerTV 307                     [1461:a70a]
  57 -> Avermedia AVerTV GO 007 FM               [1461:f31f]
- 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0370,1421:1370]
+ 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0351,1421:0370,1421:1370]
  59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
  60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502]
  61 -> Philips TOUGH DVB-T reference design     [1131:2004]
@@ -81,4 +81,5 @@
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
  82 -> MSI TV@Anywhere plus                     [1462:6231]
-
+ 83 -> Terratec Cinergy 250 PCI TV              [153b:1160]
+ 84 -> LifeView FlyDVB Trio                     [5168:0319]
index 9d6544ea9f41881f0df7fea74f4f31b90211b9e5..0bf3d5bf9ef8c2a837fee536e9da636c7dd4bc36 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 daul in
+tuner=42 - Philips 1236D 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
@@ -50,7 +50,7 @@ tuner=48 - Tenna TNF 8831 BGFF)
 tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in
 tuner=50 - TCL 2002N
 tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
-tuner=52 - Thomson DDT 7610 (ATSC/NTSC)
+tuner=52 - Thomson DTT 7610 (ATSC/NTSC)
 tuner=53 - Philips FQ1286
 tuner=54 - tda8290+75
 tuner=55 - TCL 2002MB
@@ -58,7 +58,7 @@ tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
 tuner=57 - Philips FQ1236A MK4
 tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF
 tuner=59 - Ymec TVision TVF-5533MF
-tuner=60 - Thomson DDT 7611 (ATSC/NTSC)
+tuner=60 - Thomson DTT 761X (ATSC/NTSC)
 tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
 tuner=62 - Philips TEA5767HN FM Radio
 tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
index 7e780906d34ca7daa716c4f49f6f0b8c57c4a57c..270e28c0506aa4dba9af46c57f853a9ddea4c92c 100644 (file)
@@ -927,7 +927,6 @@ S:  Maintained
 FARSYNC SYNCHRONOUS DRIVER
 P:     Kevin Curtis
 M:     kevin.curtis@farsite.co.uk
-M:     kevin.curtis@farsite.co.uk
 W:     http://www.farsite.co.uk/
 S:     Supported
 
@@ -1698,7 +1697,6 @@ S: Maintained
 
 MARVELL MV64340 ETHERNET DRIVER
 P:     Manish Lachwani
-M:     Manish_Lachwani@pmc-sierra.com
 L:     linux-mips@linux-mips.org
 L:     netdev@vger.kernel.org
 S:     Supported
diff --git a/README b/README
index 61c4f7429233d509f26c267cf95fa01742b81e3e..cd5e2eb6213b052d4bbd40d8c6bf92e92ca787e9 100644 (file)
--- a/README
+++ b/README
@@ -183,11 +183,8 @@ CONFIGURING the kernel:
 
 COMPILING the kernel:
 
- - Make sure you have gcc 2.95.3 available.
-   gcc 2.91.66 (egcs-1.1.2), and gcc 2.7.2.3 are known to miscompile
-   some parts of the kernel, and are *no longer supported*.
-   Also remember to upgrade your binutils package (for as/ld/nm and company)
-   if necessary. For more information, refer to Documentation/Changes.
+ - Make sure you have at least gcc 3.2 available.
+   For more information, refer to Documentation/Changes.
 
    Please note that you can still run a.out user programs with this kernel.
 
index 153337ff1d7b32b688b00659a7f54c5c7c3a0d5e..eedf41bf7057567b182ab221c64908da1685c98d 100644 (file)
@@ -18,9 +18,6 @@ config MMU
        bool
        default y
 
-config UID16
-       bool
-
 config RWSEM_GENERIC_SPINLOCK
        bool
 
index a8682612abc0d8ce46c1979a48b4b6d78f31b7b0..abb739b88ed15603400495cd6cadab48ff63a1ac 100644 (file)
 #include "proto.h"
 #include "pci_impl.h"
 
+/*
+ * Power off function, if any
+ */
+void (*pm_power_off)(void) = machine_power_off;
+
 void
 cpu_idle(void)
 {
index bbd37536d14ef98458b3142bd532f4065a4dd8ec..9969d212e94d9d4b16da2f66921f8b206822612e 100644 (file)
@@ -265,30 +265,16 @@ do_sys_ptrace(long request, long pid, long addr, long data,
        lock_kernel();
        DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",
                      request, pid, addr, data));
-       ret = -EPERM;
        if (request == PTRACE_TRACEME) {
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
-                       goto out_notsk;
-               ret = security_ptrace(current->parent, current);
-               if (ret)
-                       goto out_notsk;
-               /* set the ptrace bit in the process ptrace flags. */
-               current->ptrace |= PT_PTRACED;
-               ret = 0;
+               ret = ptrace_traceme();
                goto out_notsk;
        }
-       if (pid == 1)           /* you may not mess with init */
-               goto out_notsk;
 
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
                goto out_notsk;
+       }
 
        if (request == PTRACE_ATTACH) {
                ret = ptrace_attach(child);
index 16a5d522b2f2d93a2fcb097aeed620b3fd4090de..7a74e3e5f9161941d9d3e3613053332ec7e342a5 100644 (file)
@@ -46,10 +46,6 @@ config MCA
          <file:Documentation/mca.txt> (and especially the web page given
          there) before attempting to build an MCA bus kernel.
 
-config UID16
-       bool
-       default y
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index b6de43e736998b05c2d598ccf530d0ece0dcec2e..a2dfe0b0f1ec53d24a78e6c141b813772589f8db 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <asm/io.h>
 #include <asm/hardware/scoop.h>
index 04d3082a7b948af1911fe6b3813ea80333f4c4e9..0abbce8c70bc7911d949ee026ab4996df343ef0e 100644 (file)
 #error Sorry, your compiler targets APCS-26 but this kernel requires APCS-32
 #endif
 /*
- * GCC 2.95.1, 2.95.2: ignores register clobber list in asm().
  * GCC 3.0, 3.1: general bad code generation.
  * GCC 3.2.0: incorrect function argument offset calculation.
  * GCC 3.2.x: miscompiles NEW_AUX_ENT in fs/binfmt_elf.c
  *            (http://gcc.gnu.org/PR8896) and incorrect structure
  *           initialisation in fs/jffs2/erase.c
  */
-#if __GNUC__ < 2 || \
-   (__GNUC__ == 2 && __GNUC_MINOR__ < 95) || \
-   (__GNUC__ == 2 && __GNUC_MINOR__ == 95 && __GNUC_PATCHLEVEL__ != 0 && \
-                                            __GNUC_PATCHLEVEL__ < 3) || \
-   (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
+#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
 #error Your compiler is too buggy; it is known to miscompile kernels.
-#error    Known good compilers: 2.95.3, 2.95.4, 2.96, 3.3
+#error    Known good compilers: 3.3
 #endif
 
 /* Use marker if you need to separate the values later */
index 869c466e625852689c6f1e792d4ee1e0262884f6..b5645c4462cffa95f5887d2cf8b8c9cfcbd2e4a1 100644 (file)
@@ -684,8 +684,12 @@ int setup_irq(unsigned int irq, struct irqaction *new)
        spin_lock_irqsave(&irq_controller_lock, flags);
        p = &desc->action;
        if ((old = *p) != NULL) {
-               /* Can't share interrupts unless both agree to */
-               if (!(old->flags & new->flags & SA_SHIRQ)) {
+               /*
+                * Can't share interrupts unless both agree to and are
+                * the same type.
+                */
+               if (!(old->flags & new->flags & SA_SHIRQ) ||
+                   (~old->flags & new->flags) & SA_TRIGGER_MASK) {
                        spin_unlock_irqrestore(&irq_controller_lock, flags);
                        return -EBUSY;
                }
@@ -705,6 +709,12 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                desc->running = 0;
                desc->pending = 0;
                desc->disable_depth = 1;
+
+               if (new->flags & SA_TRIGGER_MASK) {
+                       unsigned int type = new->flags & SA_TRIGGER_MASK;
+                       desc->chip->set_type(irq, type);
+               }
+
                if (!desc->noautoenable) {
                        desc->disable_depth = 0;
                        desc->chip->unmask(irq);
index 775f85fc85139ac2dbea4d4515e6936c3bd79d4a..9e563de465b53ccc186f17a955838fc91548c4da 100644 (file)
@@ -601,6 +601,7 @@ EXPORT_SYMBOL(gpio_lock);
 EXPORT_SYMBOL(gpio_modify_op);
 EXPORT_SYMBOL(gpio_modify_io);
 EXPORT_SYMBOL(cpld_modify);
+EXPORT_SYMBOL(gpio_read);
 
 /*
  * Initialise any other hardware after we've got the PCI bus
index 9f46aaef8968de59ec1c762baeb9703e832879c5..3c22c16b38bf82e2b898e48779b15530b100e8fc 100644 (file)
@@ -96,7 +96,8 @@ static struct rtc_ops rtc_ops = {
        .set_alarm      = rtc_set_alarm,
 };
 
-static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id,
+                                    struct pt_regs *regs)
 {
        writel(0, rtc_base + RTC_EOI);
        return IRQ_HANDLED;
@@ -124,7 +125,7 @@ static int rtc_probe(struct amba_device *dev, void *id)
 
        xtime.tv_sec = __raw_readl(rtc_base + RTC_DR);
 
-       ret = request_irq(dev->irq[0], rtc_interrupt, SA_INTERRUPT,
+       ret = request_irq(dev->irq[0], arm_rtc_interrupt, SA_INTERRUPT,
                          "rtc-pl030", dev);
        if (ret)
                goto map_out;
index fcfb81d13cfe69490810d225e6ac40386bb16366..7a68f098a0254365da8f1da60edd94f081f9df65 100644 (file)
@@ -252,9 +252,8 @@ static void __init omap_serial_set_port_wakeup(int gpio_nr)
                return;
        }
        omap_set_gpio_direction(gpio_nr, 1);
-       set_irq_type(OMAP_GPIO_IRQ(gpio_nr), IRQT_RISING);
        ret = request_irq(OMAP_GPIO_IRQ(gpio_nr), &omap_serial_wake_interrupt,
-                         0, "serial wakeup", NULL);
+                         SA_TRIGGER_RISING, "serial wakeup", NULL);
        if (ret) {
                omap_free_gpio(gpio_nr);
                printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n",
index 100fb31b5156df4a9cb3e6b0372ef2736d23d7e0..5a7b873f29b3cd853a9975626182dcb38d5463c0 100644 (file)
@@ -213,15 +213,14 @@ static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(in
 
        corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250);
 
-       err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int, SA_INTERRUPT,
-                            "MMC card detect", data);
+       err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int,
+                         SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+                         "MMC card detect", data);
        if (err) {
                printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
                return -1;
        }
 
-       set_irq_type(CORGI_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
-
        return 0;
 }
 
index eef3de26ad3704dba4604255abcf13bb3942b16a..663c9500598553604f0f04c3f3b9355b29c2e640 100644 (file)
@@ -146,15 +146,14 @@ static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)(
 
        poodle_mci_platform_data.detect_delay = msecs_to_jiffies(250);
 
-       err = request_irq(POODLE_IRQ_GPIO_nSD_DETECT, poodle_detect_int, SA_INTERRUPT,
-                            "MMC card detect", data);
+       err = request_irq(POODLE_IRQ_GPIO_nSD_DETECT, poodle_detect_int,
+                         SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+                         "MMC card detect", data);
        if (err) {
                printk(KERN_ERR "poodle_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
                return -1;
        }
 
-       set_irq_type(POODLE_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
-
        return 0;
 }
 
index f2007db0cda5aebe5ad398a3909f8ddecd1f688f..a9eacc06555f2e775da7f0a859ad671293324a2a 100644 (file)
@@ -296,15 +296,14 @@ static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(in
 
        spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250);
 
-       err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int, SA_INTERRUPT,
-                            "MMC card detect", data);
+       err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int,
+                         SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+                         "MMC card detect", data);
        if (err) {
                printk(KERN_ERR "spitz_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
                return -1;
        }
 
-       set_irq_type(SPITZ_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
-
        return 0;
 }
 
index c9d7c596b200866b8ccf2f8dfb98127044fbd8e8..caf6b8bb6c951e9bc29ed322a26748948681e7d4 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/smp.h>
+#include <linux/jiffies.h>
 
 #include <asm/mach/time.h>
 #include <asm/hardware/arm_twd.h>
index 5098b50158a332ce81b8bdd36945c5916d9f8cb3..495f8c6ffcb6e6d39c51bbb67d95e63688c86c5c 100644 (file)
@@ -84,13 +84,13 @@ static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
        int ret;
 
        if (on) {
-               ret = request_irq(IRQ_USBOC, usb_simtec_ocirq, SA_INTERRUPT,
+               ret = request_irq(IRQ_USBOC, usb_simtec_ocirq,
+                                 SA_INTERRUPT | SA_TRIGGER_RISING |
+                                  SA_TRIGGER_FALLING,
                                  "USB Over-current", info);
                if (ret != 0) {
                        printk(KERN_ERR "failed to request usb oc irq\n");
                }
-
-               set_irq_type(IRQ_USBOC, IRQT_BOTHEDGE);
        } else {
                free_irq(IRQ_USBOC, info);
        }
index 1f00b3d03a076a9a9f70a694198c42e96d9277ba..274e07019b461040660a0f10d6ed308c742813b9 100644 (file)
@@ -34,10 +34,6 @@ config FORCE_MAX_ZONEORDER
         int
         default 9
 
-config UID16
-       bool
-       default y
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index 4ccacaef94dfb2dce7cfbdcfde65e8cc3c70ba25..ac682d5fd0398cd67a96ac3b22410a40d74c959a 100644 (file)
 #if defined(__APCS_32__) && defined(CONFIG_CPU_26)
 #error Sorry, your compiler targets APCS-32 but this kernel requires APCS-26
 #endif
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
-#error Sorry, your compiler is known to miscompile kernels.  Only use gcc 2.95.3 and later.
-#endif
-#if __GNUC__ == 2 && __GNUC_MINOR__ == 95
-/* shame we can't detect the .1 or .2 releases */
-#warning GCC 2.95.2 and earlier miscompiles kernels.
-#endif
 
 /* Use marker if you need to separate the values later */
 
index e5979d68e3524d595f6a108fd122d30020f9b660..b832619497372a6336b8ad46f1b21f01728d98bf 100644 (file)
@@ -9,10 +9,6 @@ config MMU
        bool
        default y
 
-config UID16
-       bool
-       default y
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index ec85c0d6c6da48677fca66e507e1dc52d64118f0..61261b78ced7617571f349edbb683050d2f51741 100644 (file)
@@ -274,6 +274,11 @@ config GPREL_DATA_NONE
 
 endchoice
 
+config FRV_ONCPU_SERIAL
+       bool "Use on-CPU serial ports"
+       select SERIAL_8250
+       default y
+
 config PCI
        bool "Use PCI"
        depends on MB93090_MB00
@@ -305,23 +310,7 @@ config RESERVE_DMA_COHERENT
 
 source "drivers/pci/Kconfig"
 
-config PCMCIA
-       tristate "Use PCMCIA"
-       help
-         Say Y here if you want to attach PCMCIA- or PC-cards to your FR-V
-         board.  These are credit-card size devices such as network cards,
-         modems or hard drives often used with laptops computers.  There are
-         actually two varieties of these cards: the older 16 bit PCMCIA cards
-         and the newer 32 bit CardBus cards.  If you want to use CardBus
-         cards, you need to say Y here and also to "CardBus support" below.
-
-         To use your PC-cards, you will need supporting software from David
-         Hinds pcmcia-cs package (see the file <file:Documentation/Changes>
-         for location).  Please also read the PCMCIA-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as modules, choose M here: the
-         modules will be called pcmcia_core and ds.
+source "drivers/pcmcia/Kconfig"
 
 #config MATH_EMULATION
 #      bool "Math emulation support (EXPERIMENTAL)"
index 0034b654995df0ea879c5152df0d5b4ff1d8b779..211f01bc4caa8f88db015cb4be8578e38ee7b6ec 100644 (file)
@@ -2,32 +2,10 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-config EARLY_PRINTK
-       bool "Early printk"
-       depends on EMBEDDED && DEBUG_KERNEL
-       default n
-       help
-         Write kernel log output directly into the VGA buffer or to a serial
-         port.
-
-         This is useful for kernel debugging when your machine crashes very
-         early before the console code is initialized. For normal operation
-         it is not recommended because it looks ugly and doesn't cooperate
-         with klogd/syslogd or the X server. You should normally N here,
-         unless you want to debug such a crash.
-
 config DEBUG_STACKOVERFLOW
        bool "Check for stack overflows"
        depends on DEBUG_KERNEL
 
-config DEBUG_PAGEALLOC
-       bool "Page alloc debugging"
-       depends on DEBUG_KERNEL
-       help
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a large slowdown, but helps to find certain types
-         of memory corruptions.
-
 config GDBSTUB
        bool "Remote GDB kernel debugging"
        depends on DEBUG_KERNEL
index 54046d2386f56d38a5bd7b311841b6db08dee000..90c0fb8d9dc3de577f3bbc011a4911821881a5fc 100644 (file)
@@ -109,10 +109,10 @@ bootstrap:
        $(Q)$(MAKEBOOT) bootstrap
 
 archmrproper:
-       $(Q)$(MAKE) -C arch/frv/boot mrproper
+       $(Q)$(MAKE) $(build)=arch/frv/boot mrproper
 
 archclean:
-       $(Q)$(MAKE) -C arch/frv/boot clean
+       $(Q)$(MAKE) $(build)=arch/frv/boot clean
 
 archdep: scripts/mkdep symlinks
-       $(Q)$(MAKE) -C arch/frv/boot dep
+       $(Q)$(MAKE) $(build)=arch/frv/boot dep
index 422f30ede57570199ec5232a8c7f2317d65ed97c..5a827b349b5e989a9de3032dd2bc572a3c4fb79a 100644 (file)
@@ -21,3 +21,4 @@ obj-$(CONFIG_PM)              += pm.o cmode.o
 obj-$(CONFIG_MB93093_PDK)      += pm-mb93093.o
 obj-$(CONFIG_SYSCTL)           += sysctl.o
 obj-$(CONFIG_FUTEX)            += futex.o
+obj-$(CONFIG_MODULES)          += module.o
index 1a76d52471902975401703d0bcb3d107fc787238..5f118c89d091f82a5dedcaf2f3a4696fdf5117f6 100644 (file)
 #include <asm/semaphore.h>
 #include <asm/checksum.h>
 #include <asm/hardirq.h>
-#include <asm/current.h>
+#include <asm/cacheflush.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern long __memcpy_user(void *dst, const void *src, size_t count);
+extern long __memset_user(void *dst, const void *src, size_t count);
 
 /* platform dependent support */
 
@@ -50,7 +51,11 @@ EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(__res_bus_clock_speed_HZ);
 EXPORT_SYMBOL(__page_offset);
 EXPORT_SYMBOL(__memcpy_user);
-EXPORT_SYMBOL(flush_dcache_page);
+EXPORT_SYMBOL(__memset_user);
+EXPORT_SYMBOL(frv_dcache_writeback);
+EXPORT_SYMBOL(frv_cache_invalidate);
+EXPORT_SYMBOL(frv_icache_invalidate);
+EXPORT_SYMBOL(frv_cache_wback_inv);
 
 #ifndef CONFIG_MMU
 EXPORT_SYMBOL(memory_start);
@@ -72,6 +77,9 @@ EXPORT_SYMBOL(memcmp);
 EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(memmove);
 
+EXPORT_SYMBOL(__outsl_ns);
+EXPORT_SYMBOL(__insl_ns);
+
 EXPORT_SYMBOL(get_wchan);
 
 #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
@@ -80,14 +88,13 @@ EXPORT_SYMBOL(atomic_test_and_OR_mask);
 EXPORT_SYMBOL(atomic_test_and_XOR_mask);
 EXPORT_SYMBOL(atomic_add_return);
 EXPORT_SYMBOL(atomic_sub_return);
-EXPORT_SYMBOL(__xchg_8);
-EXPORT_SYMBOL(__xchg_16);
 EXPORT_SYMBOL(__xchg_32);
-EXPORT_SYMBOL(__cmpxchg_8);
-EXPORT_SYMBOL(__cmpxchg_16);
 EXPORT_SYMBOL(__cmpxchg_32);
 #endif
 
+EXPORT_SYMBOL(__debug_bug_printk);
+EXPORT_SYMBOL(__delay_loops_MHz);
+
 /*
  * libgcc functions - functions that are used internally by the
  * compiler...  (prototypes are not correct though, but that
@@ -101,6 +108,8 @@ extern void __divdi3(void);
 extern void __lshrdi3(void);
 extern void __moddi3(void);
 extern void __muldi3(void);
+extern void __mulll(void);
+extern void __umulll(void);
 extern void __negdi2(void);
 extern void __ucmpdi2(void);
 extern void __udivdi3(void);
@@ -116,8 +125,10 @@ EXPORT_SYMBOL(__ashrdi3);
 EXPORT_SYMBOL(__lshrdi3);
 //EXPORT_SYMBOL(__moddi3);
 EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__mulll);
+EXPORT_SYMBOL(__umulll);
 EXPORT_SYMBOL(__negdi2);
-//EXPORT_SYMBOL(__ucmpdi2);
+EXPORT_SYMBOL(__ucmpdi2);
 //EXPORT_SYMBOL(__udivdi3);
 //EXPORT_SYMBOL(__udivmoddi4);
 //EXPORT_SYMBOL(__umoddi3);
index 8c524cdd2717abe82d7a3bd25c30951a27f2260b..59580c59c62ca899c0a150b59b41f16161d47e6e 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/module.h>
 
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -178,6 +179,8 @@ void disable_irq_nosync(unsigned int irq)
        spin_unlock_irqrestore(&level->lock, flags);
 }
 
+EXPORT_SYMBOL(disable_irq_nosync);
+
 /**
  *     disable_irq - disable an irq and wait for completion
  *     @irq: Interrupt to disable
@@ -204,6 +207,8 @@ void disable_irq(unsigned int irq)
 #endif
 }
 
+EXPORT_SYMBOL(disable_irq);
+
 /**
  *     enable_irq - enable handling of an irq
  *     @irq: Interrupt to enable
@@ -268,6 +273,8 @@ void enable_irq(unsigned int irq)
        spin_unlock_irqrestore(&level->lock, flags);
 }
 
+EXPORT_SYMBOL(enable_irq);
+
 /*****************************************************************************/
 /*
  * handles all normal device IRQ's
@@ -425,6 +432,8 @@ int request_irq(unsigned int irq,
        return retval;
 }
 
+EXPORT_SYMBOL(request_irq);
+
 /**
  *     free_irq - free an interrupt
  *     @irq: Interrupt line to free
@@ -496,6 +505,8 @@ void free_irq(unsigned int irq, void *dev_id)
        }
 }
 
+EXPORT_SYMBOL(free_irq);
+
 /*
  * IRQ autodetection code..
  *
@@ -519,6 +530,8 @@ unsigned long probe_irq_on(void)
        return 0;
 }
 
+EXPORT_SYMBOL(probe_irq_on);
+
 /*
  * Return a mask of triggered interrupts (this
  * can handle only legacy ISA interrupts).
@@ -542,6 +555,8 @@ unsigned int probe_irq_mask(unsigned long xmask)
        return 0;
 }
 
+EXPORT_SYMBOL(probe_irq_mask);
+
 /*
  * Return the one interrupt that triggered (this can
  * handle any interrupt source).
@@ -571,6 +586,8 @@ int probe_irq_off(unsigned long xmask)
        return -1;
 }
 
+EXPORT_SYMBOL(probe_irq_off);
+
 /* this was setup_x86_irq but it seems pretty generic */
 int setup_irq(unsigned int irq, struct irqaction *new)
 {
diff --git a/arch/frv/kernel/module.c b/arch/frv/kernel/module.c
new file mode 100644 (file)
index 0000000..850d168
--- /dev/null
@@ -0,0 +1,80 @@
+/* module.c: FRV specific module loading bits
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ * - Derived from arch/i386/kernel/module.c, Copyright (C) 2001 Rusty Russell.
+ *
+ * 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/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+       if (size == 0)
+               return NULL;
+
+       return vmalloc_exec(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+       vfree(module_region);
+       /* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+                             Elf_Shdr *sechdrs,
+                             char *secstrings,
+                             struct module *mod)
+{
+       return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name);
+       return -ENOEXEC;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *me)
+{
+       printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name);
+       return -ENOEXEC;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *me)
+{
+       return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
index 712c3c24c954008d520f7925a492eee0a85f97e5..f0b8fff3e7336235f6b2a25b87324f98ae9b9445 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/pm_legacy.h>
 #include <linux/sched.h>
@@ -27,6 +28,7 @@
 #include "local.h"
 
 void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
 
 extern void frv_change_cmode(int);
 
index 767ebb55bd83d7e763b38d719aee47728f037052..5908deae9607b7a5c991c3a6e4176d93f7248095 100644 (file)
@@ -787,6 +787,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        /* register those serial ports that are available */
+#ifdef CONFIG_FRV_ONCPU_SERIAL
 #ifndef CONFIG_GDBSTUB_UART0
        __reg(UART0_BASE + UART_IER * 8) = 0;
        early_serial_setup(&__frv_uart0);
@@ -795,6 +796,7 @@ void __init setup_arch(char **cmdline_p)
        __reg(UART1_BASE + UART_IER * 8) = 0;
        early_serial_setup(&__frv_uart1);
 #endif
+#endif
 
 #if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
        /* we need to initialize the Flashrom device here since we might
index 2e9741227b739161bd57b5f4b2d47593971da0b2..24cf85f89e400f675e8820c94438e8f5e38431ad 100644 (file)
@@ -189,6 +189,8 @@ void do_gettimeofday(struct timeval *tv)
        tv->tv_usec = usec;
 }
 
+EXPORT_SYMBOL(do_gettimeofday);
+
 int do_settimeofday(struct timespec *tv)
 {
        time_t wtm_sec, sec = tv->tv_sec;
@@ -218,6 +220,7 @@ int do_settimeofday(struct timespec *tv)
        clock_was_set();
        return 0;
 }
+
 EXPORT_SYMBOL(do_settimeofday);
 
 /*
index 89073cae4b5ddf66543861ec14fdf352ba32eca8..9eb84b2e6abc498362f57762a1e5e8e3c0c24b58 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/string.h>
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 #include <asm/setup.h>
 #include <asm/fpu.h>
@@ -250,6 +251,8 @@ void dump_stack(void)
        show_stack(NULL, NULL);
 }
 
+EXPORT_SYMBOL(dump_stack);
+
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
 }
index f3fd58a5bc4a84ba2256d39bc5ffff25f66acc22..9b751c0f0e84677a00b0a4245a38792fd7c501e0 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 
 /*****************************************************************************/
@@ -58,8 +59,11 @@ long strncpy_from_user(char *dst, const char *src, long count)
                memset(p, 0, count); /* clear remainder of buffer [security] */
 
        return err;
+
 } /* end strncpy_from_user() */
 
+EXPORT_SYMBOL(strncpy_from_user);
+
 /*****************************************************************************/
 /*
  * Return the size of a string (including the ending 0)
@@ -92,4 +96,7 @@ long strnlen_user(const char *src, long count)
        }
 
        return p - src + 1; /* return length including NUL */
+
 } /* end strnlen_user() */
+
+EXPORT_SYMBOL(strnlen_user);
index fceafd2cc20226e76a790db64a315afd97d60901..f474534ba78a50ff61b7c60b31fa37121ba3de1a 100644 (file)
@@ -112,6 +112,7 @@ SECTIONS
 #endif
        )
        SCHED_TEXT
+       LOCK_TEXT
        *(.fixup)
        *(.gnu.warning)
        *(.exitcall.exit)
index 19be2626d5e62d205461fc8077721aa6762c6427..08be305c9f446c436a51aa6930d7cb8d2ebb24f6 100644 (file)
@@ -3,6 +3,6 @@
 #
 
 lib-y := \
-       __ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o \
+       __ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o __ucmpdi2.o \
        checksum.o memcpy.o memset.o atomic-ops.o \
        outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o
diff --git a/arch/frv/lib/__ucmpdi2.S b/arch/frv/lib/__ucmpdi2.S
new file mode 100644 (file)
index 0000000..d892f16
--- /dev/null
@@ -0,0 +1,45 @@
+/* __ucmpdi2.S: 64-bit unsigned compare
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+        .text
+        .p2align       4
+
+###############################################################################
+#
+# int __ucmpdi2(unsigned long long a [GR8:GR9],
+#              unsigned long long b [GR10:GR11])
+#
+# - returns 0, 1, or 2 as a <, =, > b respectively.
+#
+###############################################################################
+        .globl         __ucmpdi2
+        .type          __ucmpdi2,@function
+__ucmpdi2:
+       or.p            gr8,gr0,gr4
+       subcc           gr8,gr10,gr0,icc0
+       setlos.p        #0,gr8
+       bclr            icc0,#2                 ; a.msw < b.msw
+
+       setlos.p        #2,gr8
+       bhilr           icc0,#0                 ; a.msw > b.msw
+
+       subcc.p         gr9,gr11,gr0,icc1
+       setlos          #0,gr8
+       setlos.p        #2,gr9
+       setlos          #1,gr7
+       cknc            icc1,cc6
+       cor.p           gr9,gr0,gr8,            cc6,#1
+       cckls           icc1,cc4,               cc6,#1
+       andcr           cc6,cc4,cc4
+       cor             gr7,gr0,gr8,            cc4,#1
+       bralr
+       .size           __ucmpdi2, .-__ucmpdi2
index b03d510a89e4ed11e825b48159cbf7a89cb43e3e..545cd325ac577d00c9ef96dc3f73fc97d24d44fe 100644 (file)
@@ -127,48 +127,6 @@ atomic_sub_return:
 
        .size           atomic_sub_return, .-atomic_sub_return
 
-###############################################################################
-#
-# uint8_t __xchg_8(uint8_t i, uint8_t *v)
-#
-###############################################################################
-       .globl          __xchg_8
-        .type          __xchg_8,@function
-__xchg_8:
-       or.p            gr8,gr8,gr10
-0:
-       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
-       ckeq            icc3,cc7
-       ldub.p          @(gr9,gr0),gr8                  /* LD.P/ORCR must be atomic */
-       orcr            cc7,cc7,cc3                     /* set CC3 to true */
-       cstb.p          gr10,@(gr9,gr0)         ,cc3,#1
-       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
-       beq             icc3,#0,0b
-       bralr
-
-       .size           __xchg_8, .-__xchg_8
-
-###############################################################################
-#
-# uint16_t __xchg_16(uint16_t i, uint16_t *v)
-#
-###############################################################################
-       .globl          __xchg_16
-        .type          __xchg_16,@function
-__xchg_16:
-       or.p            gr8,gr8,gr10
-0:
-       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
-       ckeq            icc3,cc7
-       lduh.p          @(gr9,gr0),gr8                  /* LD.P/ORCR must be atomic */
-       orcr            cc7,cc7,cc3                     /* set CC3 to true */
-       csth.p          gr10,@(gr9,gr0)         ,cc3,#1
-       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
-       beq             icc3,#0,0b
-       bralr
-
-       .size           __xchg_16, .-__xchg_16
-
 ###############################################################################
 #
 # uint32_t __xchg_32(uint32_t i, uint32_t *v)
@@ -190,56 +148,6 @@ __xchg_32:
 
        .size           __xchg_32, .-__xchg_32
 
-###############################################################################
-#
-# uint8_t __cmpxchg_8(uint8_t *v, uint8_t test, uint8_t new)
-#
-###############################################################################
-       .globl          __cmpxchg_8
-        .type          __cmpxchg_8,@function
-__cmpxchg_8:
-       or.p            gr8,gr8,gr11
-0:
-       orcc            gr0,gr0,gr0,icc3
-       ckeq            icc3,cc7
-       ldub.p          @(gr11,gr0),gr8
-       orcr            cc7,cc7,cc3
-       sub             gr8,gr9,gr7
-       sllicc          gr7,#24,gr0,icc0
-       bne             icc0,#0,1f
-       cstb.p          gr10,@(gr11,gr0)        ,cc3,#1
-       corcc           gr29,gr29,gr0           ,cc3,#1
-       beq             icc3,#0,0b
-1:
-       bralr
-
-       .size           __cmpxchg_8, .-__cmpxchg_8
-
-###############################################################################
-#
-# uint16_t __cmpxchg_16(uint16_t *v, uint16_t test, uint16_t new)
-#
-###############################################################################
-       .globl          __cmpxchg_16
-        .type          __cmpxchg_16,@function
-__cmpxchg_16:
-       or.p            gr8,gr8,gr11
-0:
-       orcc            gr0,gr0,gr0,icc3
-       ckeq            icc3,cc7
-       lduh.p          @(gr11,gr0),gr8
-       orcr            cc7,cc7,cc3
-       sub             gr8,gr9,gr7
-       sllicc          gr7,#16,gr0,icc0
-       bne             icc0,#0,1f
-       csth.p          gr10,@(gr11,gr0)        ,cc3,#1
-       corcc           gr29,gr29,gr0           ,cc3,#1
-       beq             icc3,#0,0b
-1:
-       bralr
-
-       .size           __cmpxchg_16, .-__cmpxchg_16
-
 ###############################################################################
 #
 # uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new)
index 7bf5bd6cac8a80f6dac26f81e621b9e32df184d3..20e7dfc474eff203d1bd36d242716db921b6a20c 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <net/checksum.h>
 #include <asm/checksum.h>
+#include <linux/module.h>
 
 static inline unsigned short from32to16(unsigned long x)
 {
@@ -115,34 +116,52 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
        return result;
 }
 
+EXPORT_SYMBOL(csum_partial);
+
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
 unsigned short ip_compute_csum(const unsigned char * buff, int len)
 {
-       return ~do_csum(buff,len);
+       return ~do_csum(buff, len);
 }
 
+EXPORT_SYMBOL(ip_compute_csum);
+
 /*
  * copy from fs while checksumming, otherwise like csum_partial
  */
-
 unsigned int
-csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *csum_err)
+csum_partial_copy_from_user(const char __user *src, char *dst,
+                           int len, int sum, int *csum_err)
 {
-       if (csum_err) *csum_err = 0;
-       memcpy(dst, src, len);
+       int rem;
+
+       if (csum_err)
+               *csum_err = 0;
+
+       rem = copy_from_user(dst, src, len);
+       if (rem != 0) {
+               if (csum_err)
+                       *csum_err = -EFAULT;
+               memset(dst + len - rem, 0, rem);
+               len = rem;
+       }
+
        return csum_partial(dst, len, sum);
 }
 
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
 /*
  * copy from ds while checksumming, otherwise like csum_partial
  */
-
 unsigned int
 csum_partial_copy(const char *src, char *dst, int len, int sum)
 {
        memcpy(dst, src, len);
        return csum_partial(dst, len, sum);
 }
+
+EXPORT_SYMBOL(csum_partial_copy);
index 3faf0f8cf9b5ba633fffe30d2c3de3e441167857..76595e87073315bc1bc59fee043a6d83912f63c4 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 ifeq "$(CONFIG_PCI)" "y"
-obj-y := pci-frv.o pci-irq.o pci-vdk.o
+obj-y := pci-frv.o pci-irq.o pci-vdk.o pci-iomap.o
 
 ifeq "$(CONFIG_MMU)" "y"
 obj-y += pci-dma.o
index 2082a9647f4fb03172ee7ae33468e85077142598..4985466b1a7cdccc8f28d3399e58b6530c46a537 100644 (file)
@@ -83,6 +83,8 @@ void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_hand
        return NULL;
 }
 
+EXPORT_SYMBOL(dma_alloc_coherent);
+
 void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
 {
        struct dma_alloc_record *rec;
@@ -102,6 +104,8 @@ void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_
        BUG();
 }
 
+EXPORT_SYMBOL(dma_free_coherent);
+
 /*
  * Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
@@ -120,6 +124,8 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
        return virt_to_bus(ptr);
 }
 
+EXPORT_SYMBOL(dma_map_single);
+
 /*
  * Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
@@ -150,3 +156,5 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 
        return nents;
 }
+
+EXPORT_SYMBOL(dma_map_sg);
index 86fbdadc51b6b2eb01cbece116a7797e94467938..671ce1e8434f2d27c9a956f2957eb6fcdb29d3fd 100644 (file)
@@ -28,11 +28,15 @@ void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_hand
        return ret;
 }
 
+EXPORT_SYMBOL(dma_alloc_coherent);
+
 void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
 {
        consistent_free(vaddr);
 }
 
+EXPORT_SYMBOL(dma_free_coherent);
+
 /*
  * Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
@@ -51,6 +55,8 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
        return virt_to_bus(ptr);
 }
 
+EXPORT_SYMBOL(dma_map_single);
+
 /*
  * Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
@@ -96,6 +102,8 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        return nents;
 }
 
+EXPORT_SYMBOL(dma_map_sg);
+
 dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset,
                        size_t size, enum dma_data_direction direction)
 {
@@ -103,3 +111,5 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long off
        flush_dcache_page(page);
        return (dma_addr_t) page_to_phys(page) + offset;
 }
+
+EXPORT_SYMBOL(dma_map_page);
diff --git a/arch/frv/mb93090-mb00/pci-iomap.c b/arch/frv/mb93090-mb00/pci-iomap.c
new file mode 100644 (file)
index 0000000..068fa04
--- /dev/null
@@ -0,0 +1,29 @@
+/* pci-iomap.c: description
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/pci.h>
+#include <linux/module.h>
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+       unsigned long start = pci_resource_start(dev, bar);
+       unsigned long len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len || !start)
+               return NULL;
+
+       if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM))
+               return (void __iomem *) start;
+
+       return NULL;
+}
+
+EXPORT_SYMBOL(pci_iomap);
index 683b5e344318b7ec6bf39d4b0ee3e1c07265a269..0261cbe153b5ecf4ff427a6a4d806b280a6a3930 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <asm/pgalloc.h>
 
 /*****************************************************************************/
@@ -38,6 +39,8 @@ void flush_dcache_page(struct page *page)
 
 } /* end flush_dcache_page() */
 
+EXPORT_SYMBOL(flush_dcache_page);
+
 /*****************************************************************************/
 /*
  * ICI takes a virtual address and the page may not currently have one
@@ -64,3 +67,5 @@ void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
        }
 
 } /* end flush_icache_user_range() */
+
+EXPORT_SYMBOL(flush_icache_user_range);
index 41be1128dc6433b5779fd27d4a21f63c5a2fe12a..caacf030ac753f438026d8c642458bba7c07518e 100644 (file)
@@ -43,7 +43,7 @@ static inline unsigned long search_one_table(const struct exception_table_entry
  */
 unsigned long search_exception_table(unsigned long pc)
 {
-       unsigned long ret = 0;
+       const struct exception_table_entry *extab;
 
        /* determine if the fault lay during a memcpy_user or a memset_user */
        if (__frame->lr == (unsigned long) &__memset_user_error_lr &&
@@ -55,9 +55,10 @@ unsigned long search_exception_table(unsigned long pc)
                 */
                return (unsigned long) &__memset_user_error_handler;
        }
-       else if (__frame->lr == (unsigned long) &__memcpy_user_error_lr &&
-                (unsigned long) &memcpy <= pc && pc < (unsigned long) &__memcpy_end
-                ) {
+
+       if (__frame->lr == (unsigned long) &__memcpy_user_error_lr &&
+           (unsigned long) &memcpy <= pc && pc < (unsigned long) &__memcpy_end
+           ) {
                /* the fault occurred in a protected memset
                 * - we search for the return address (in LR) instead of the program counter
                 * - it was probably during a copy_to/from_user()
@@ -65,27 +66,10 @@ unsigned long search_exception_table(unsigned long pc)
                return (unsigned long) &__memcpy_user_error_handler;
        }
 
-#ifndef CONFIG_MODULES
-       /* there is only the kernel to search.  */
-       ret = search_one_table(__start___ex_table, __stop___ex_table - 1, pc);
-       return ret;
-
-#else
-       /* the kernel is the last "module" -- no need to treat it special */
-       unsigned long flags;
-       struct module *mp;
+       extab = search_exception_tables(pc);
+       if (extab)
+               return extab->fixup;
 
-       spin_lock_irqsave(&modlist_lock, flags);
-
-       for (mp = module_list; mp != NULL; mp = mp->next) {
-               if (mp->ex_table_start == NULL || !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING)))
-                       continue;
-               ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, pc);
-               if (ret)
-                       break;
-       }
+       return 0;
 
-       spin_unlock_irqrestore(&modlist_lock, flags);
-       return ret;
-#endif
 } /* end search_exception_table() */
index 7dc8fbf3af97ee8388fa349ef755641ed1f15db9..7f77db7fabc702f255c60b3cef73b62097a5d58e 100644 (file)
@@ -9,6 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <linux/highmem.h>
+#include <linux/module.h>
 
 void *kmap(struct page *page)
 {
@@ -18,6 +19,8 @@ void *kmap(struct page *page)
        return kmap_high(page);
 }
 
+EXPORT_SYMBOL(kmap);
+
 void kunmap(struct page *page)
 {
        if (in_interrupt())
@@ -27,7 +30,12 @@ void kunmap(struct page *page)
        kunmap_high(page);
 }
 
+EXPORT_SYMBOL(kunmap);
+
 struct page *kmap_atomic_to_page(void *ptr)
 {
        return virt_to_page(ptr);
 }
+
+
+EXPORT_SYMBOL(kmap_atomic_to_page);
index 26698a49f1535883d01a4a6031db7d08aeda284c..80940d712acf76b6bea39df0cc27a618d0f632b1 100644 (file)
@@ -21,10 +21,6 @@ config FPU
        bool
        default n
 
-config UID16
-       bool
-       default y
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index 968fabd8723fd5aaf81dcfc7b659499328e5630c..d849c6870e3a3a7e7a44014020f709a3286874bf 100644 (file)
@@ -29,10 +29,6 @@ config MMU
 config SBUS
        bool
 
-config UID16
-       bool
-       default y
-
 config GENERIC_ISA_DMA
        bool
        default y
@@ -630,10 +626,6 @@ config REGPARM
        and passes the first three arguments of a function call in registers.
        This will probably break binary only modules.
 
-       This feature is only enabled for gcc-3.0 and later - earlier compilers
-       generate incorrect output with certain kernel constructs when
-       -mregparm=3 is used.
-
 config SECCOMP
        bool "Enable seccomp to safely compute untrusted bytecode"
        depends on PROC_FS
@@ -703,7 +695,7 @@ depends on PM && !X86_VISWS
 
 config APM
        tristate "APM (Advanced Power Management) BIOS support"
-       depends on PM && PM_LEGACY
+       depends on PM
        ---help---
          APM is a BIOS specification for saving power using several different
          techniques. This is mostly useful for battery powered laptops with
index d121ea18460fe89335c2019c818f55dedd4c14b0..b84119f9cc63a1ff2df55dd1e3fad00e5211b3b6 100644 (file)
@@ -37,10 +37,7 @@ CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
 # CPU-specific tuning. Anything which can be shared with UML should go here.
 include $(srctree)/arch/i386/Makefile.cpu
 
-# -mregparm=3 works ok on gcc-3.0 and later
-#
-GCC_VERSION                    := $(call cc-version)
-cflags-$(CONFIG_REGPARM)       += $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;)
+cflags-$(CONFIG_REGPARM)       += -mregparm=3
 
 # Disable unit-at-a-time mode, it makes gcc use a lot more stack
 # due to the lack of sharing of stacklots.
index 8e51456df23d0cf8590910f041783ee4463e5930..dcd936ef45db613b941ba178c6b0ff786827c94b 100644 (file)
@@ -1,7 +1,7 @@
 # CPU tuning section - shared with UML.
 # Must change only cflags-y (or [yn]), not CFLAGS! That makes a difference for UML.
 
-#-mtune exists since gcc 3.4, and some -mcpu flavors didn't exist in gcc 2.95.
+#-mtune exists since gcc 3.4
 HAS_MTUNE      := $(call cc-option-yn, -mtune=i386)
 ifeq ($(HAS_MTUNE),y)
 tune           = $(call cc-option,-mtune=$(1),)
@@ -14,7 +14,7 @@ cflags-$(CONFIG_M386)         += -march=i386
 cflags-$(CONFIG_M486)          += -march=i486
 cflags-$(CONFIG_M586)          += -march=i586
 cflags-$(CONFIG_M586TSC)       += -march=i586
-cflags-$(CONFIG_M586MMX)       += $(call cc-option,-march=pentium-mmx,-march=i586)
+cflags-$(CONFIG_M586MMX)       += -march=pentium-mmx
 cflags-$(CONFIG_M686)          += -march=i686
 cflags-$(CONFIG_MPENTIUMII)    += -march=i686 $(call tune,pentium2)
 cflags-$(CONFIG_MPENTIUMIII)   += -march=i686 $(call tune,pentium3)
@@ -23,8 +23,8 @@ cflags-$(CONFIG_MPENTIUM4)    += -march=i686 $(call tune,pentium4)
 cflags-$(CONFIG_MK6)           += -march=k6
 # Please note, that patches that add -march=athlon-xp and friends are pointless.
 # They make zero difference whatsosever to performance at this time.
-cflags-$(CONFIG_MK7)           += $(call cc-option,-march=athlon,-march=i686 $(align)-functions=4)
-cflags-$(CONFIG_MK8)           += $(call cc-option,-march=k8,$(call cc-option,-march=athlon,-march=i686 $(align)-functions=4))
+cflags-$(CONFIG_MK7)           += -march=athlon
+cflags-$(CONFIG_MK8)           += $(call cc-option,-march=k8,-march=athlon)
 cflags-$(CONFIG_MCRUSOE)       += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MEFFICEON)     += -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MWINCHIPC6)    += $(call cc-option,-march=winchip-c6,-march=i586)
@@ -37,5 +37,5 @@ cflags-$(CONFIG_MVIAC3_2)     += $(call cc-option,-march=c3-2,-march=i686)
 cflags-$(CONFIG_X86_ELAN)      += -march=i486
 
 # Geode GX1 support
-cflags-$(CONFIG_MGEODEGX1)             += $(call cc-option,-march=pentium-mmx,-march=i486)
+cflags-$(CONFIG_MGEODEGX1)     += -march=pentium-mmx
 
index 82a807f9f5e64d8e9230705941e55186d5537ab7..f19f3a7492a5699703c16aab29b26537cf91c32e 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <linux/linkage.h>
 #include <linux/vmalloc.h>
-#include <linux/tty.h>
+#include <linux/screen_info.h>
 #include <asm/io.h>
 #include <asm/page.h>
 
index f10de0f2c5e622258517b978afac886378a04333..be1880bb75b48ddace3a08ceb642b803b37413a0 100644 (file)
@@ -4,10 +4,10 @@
 
 extra-y := head.o init_task.o vmlinux.lds
 
-obj-y  := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
+obj-y  := process.o semaphore.o signal.o entry.o traps.o irq.o \
                ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
                pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
-               doublefault.o quirks.o i8237.o
+               quirks.o i8237.o
 
 obj-y                          += cpu/
 obj-y                          += timers/
@@ -33,6 +33,8 @@ obj-y                         += sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT)        += srat.o
 obj-$(CONFIG_HPET_TIMER)       += time_hpet.o
 obj-$(CONFIG_EFI)              += efi.o efi_stub.o
+obj-$(CONFIG_DOUBLEFAULT)      += doublefault.o
+obj-$(CONFIG_VM86)             += vm86.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 
 EXTRA_AFLAGS   := -traditional
index 2d793d4aef1a7075b62bb16bc04f4af5c7a90d5e..9d8827156e54ad7ea6832f97d34e116f89d14ac1 100644 (file)
@@ -2291,7 +2291,9 @@ static int __init apm_init(void)
                apm_info.disabled = 1;
                return -ENODEV;
        }
+#ifdef CONFIG_PM_LEGACY
        pm_active = 1;
+#endif
 
        /*
         * Set up a segment that references the real mode segment 0x40
@@ -2382,7 +2384,9 @@ static void __exit apm_exit(void)
        exit_kapmd = 1;
        while (kapmd_running)
                schedule();
+#ifdef CONFIG_PM_LEGACY
        pm_active = 0;
+#endif
 }
 
 module_init(apm_init);
index cca655688ffc20b8a4722af4e503544f62cee3d8..170400879f448dff13106e1b9f94e1bd645c8117 100644 (file)
@@ -609,8 +609,10 @@ void __devinit cpu_init(void)
        load_TR_desc();
        load_LDT(&init_mm.context);
 
+#ifdef CONFIG_DOUBLEFAULT
        /* Set up doublefault TSS pointer in the GDT */
        __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
+#endif
 
        /* Clear %fs and %gs. */
        asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
index 607c0600750894e21f2beeb423101ab2e56f5952..4d704724b2f5bfeb00f72e23735d0e8290893e8e 100644 (file)
@@ -323,6 +323,7 @@ work_notifysig:                             # deal with pending signals and
 
        ALIGN
 work_notifysig_v86:
+#ifdef CONFIG_VM86
        pushl %ecx                      # save ti_flags for do_notify_resume
        call save_v86_state             # %eax contains pt_regs pointer
        popl %ecx
@@ -330,6 +331,7 @@ work_notifysig_v86:
        xorl %edx, %edx
        call do_notify_resume
        jmp resume_userspace
+#endif
 
        # perform syscall exit tracing
        ALIGN
index 9caa8e8db80cacb961c399f9399dce767da3f39c..cff95d10a4d8251173ee8ceac7351d774279cbbb 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_maxaligned_in_smp = INIT_TSS;
+DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
 
index 1a201a9328659930d41ade1ccc5aa7f1ef977455..f3a9c78c4a24412cfea2cddbe8d1c1e51eb00bea 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/cpu.h>
 #include <linux/delay.h>
 
-DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp;
+DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
 EXPORT_PER_CPU_SYMBOL(irq_stat);
 
 #ifndef CONFIG_X86_LOCAL_APIC
index 45e7f0ac4b04be579a50db8e21e821894c6c7191..035928f3f6c1c96bf8869c9388f275fd49db703c 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/desc.h>
+#include <asm/vm86.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
index f7ba4acc20ec3d7049d77b8d417e95e49e94787a..6ff3e524322672a9e0c8b90935a1b439f6c2375a 100644 (file)
@@ -293,3 +293,4 @@ ENTRY(sys_call_table)
        .long sys_inotify_init
        .long sys_inotify_add_watch
        .long sys_inotify_rm_watch
+       .long sys_migrate_pages
index 9caeaa315cd7c00157ba7621a8c2082e116cfa68..a529f0cdce17018dcc6849340954e84731006598 100644 (file)
@@ -259,8 +259,6 @@ __setup("hpet=", hpet_setup);
 #include <linux/mc146818rtc.h>
 #include <linux/rtc.h>
 
-extern irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
 #define DEFAULT_RTC_INT_FREQ   64
 #define RTC_NUM_INTS           1
 
index 67932ad530822882047655b58f1d6ba0992bbc08..57b047c27e4641e092dd485b7c09e6fba1d28fc5 100644 (file)
@@ -37,10 +37,6 @@ $(error Sorry, you need a newer version of the assember, one that is built from
                ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz)
 endif
 
-ifneq ($(shell if [ $(GCC_VERSION) -lt 0300 ] ; then echo "bad"; fi ;),)
-$(error Sorry, your compiler is too old.  GCC v2.96 is known to generate bad code.)
-endif
-
 ifeq ($(GCC_VERSION),0304)
        cflags-$(CONFIG_ITANIUM)        += -mtune=merced
        cflags-$(CONFIG_MCKINLEY)       += -mtune=mckinley
index dc282710421a18b71053a3ecb86f9ae8f778f129..9f8e8d5588731066475d8dc235a3f8bc7d608e34 100644 (file)
@@ -1761,21 +1761,15 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data)
 
        lock_kernel();
        if (request == PTRACE_TRACEME) {
-               ret = sys_ptrace(request, pid, addr, data);
+               ret = ptrace_traceme();
                goto out;
        }
 
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
                goto out;
-       ret = -EPERM;
-       if (pid == 1)           /* no messing around with init! */
-               goto out_tsk;
+       }
 
        if (request == PTRACE_ATTACH) {
                ret = sys_ptrace(request, pid, addr, data);
index a3aa45cbcfa03e460dab2d8696259126688407fb..c485a3b32ba8ba4a31ce380635441ab4e3ff1729 100644 (file)
@@ -247,6 +247,32 @@ typedef struct kern_memdesc {
 
 static kern_memdesc_t *kern_memmap;
 
+#define efi_md_size(md)        (md->num_pages << EFI_PAGE_SHIFT)
+
+static inline u64
+kmd_end(kern_memdesc_t *kmd)
+{
+       return (kmd->start + (kmd->num_pages << EFI_PAGE_SHIFT));
+}
+
+static inline u64
+efi_md_end(efi_memory_desc_t *md)
+{
+       return (md->phys_addr + efi_md_size(md));
+}
+
+static inline int
+efi_wb(efi_memory_desc_t *md)
+{
+       return (md->attribute & EFI_MEMORY_WB);
+}
+
+static inline int
+efi_uc(efi_memory_desc_t *md)
+{
+       return (md->attribute & EFI_MEMORY_UC);
+}
+
 static void
 walk (efi_freemem_callback_t callback, void *arg, u64 attr)
 {
@@ -595,8 +621,8 @@ efi_get_iobase (void)
        return 0;
 }
 
-u32
-efi_mem_type (unsigned long phys_addr)
+static efi_memory_desc_t *
+efi_memory_descriptor (unsigned long phys_addr)
 {
        void *efi_map_start, *efi_map_end, *p;
        efi_memory_desc_t *md;
@@ -610,13 +636,13 @@ efi_mem_type (unsigned long phys_addr)
                md = p;
 
                if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT))
-                        return md->type;
+                        return md;
        }
        return 0;
 }
 
-u64
-efi_mem_attributes (unsigned long phys_addr)
+static int
+efi_memmap_has_mmio (void)
 {
        void *efi_map_start, *efi_map_end, *p;
        efi_memory_desc_t *md;
@@ -629,36 +655,98 @@ efi_mem_attributes (unsigned long phys_addr)
        for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
                md = p;
 
-               if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT))
-                       return md->attribute;
+               if (md->type == EFI_MEMORY_MAPPED_IO)
+                       return 1;
        }
        return 0;
 }
+
+u32
+efi_mem_type (unsigned long phys_addr)
+{
+       efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
+
+       if (md)
+               return md->type;
+       return 0;
+}
+
+u64
+efi_mem_attributes (unsigned long phys_addr)
+{
+       efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
+
+       if (md)
+               return md->attribute;
+       return 0;
+}
 EXPORT_SYMBOL(efi_mem_attributes);
 
+/*
+ * Determines whether the memory at phys_addr supports the desired
+ * attribute (WB, UC, etc).  If this returns 1, the caller can safely
+ * access *size bytes at phys_addr with the specified attribute.
+ */
+static int
+efi_mem_attribute_range (unsigned long phys_addr, unsigned long *size, u64 attr)
+{
+       efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
+       unsigned long md_end;
+
+       if (!md || (md->attribute & attr) != attr)
+               return 0;
+
+       do {
+               md_end = efi_md_end(md);
+               if (phys_addr + *size <= md_end)
+                       return 1;
+
+               md = efi_memory_descriptor(md_end);
+               if (!md || (md->attribute & attr) != attr) {
+                       *size = md_end - phys_addr;
+                       return 1;
+               }
+       } while (md);
+       return 0;
+}
+
+/*
+ * For /dev/mem, we only allow read & write system calls to access
+ * write-back memory, because read & write don't allow the user to
+ * control access size.
+ */
 int
 valid_phys_addr_range (unsigned long phys_addr, unsigned long *size)
 {
-       void *efi_map_start, *efi_map_end, *p;
-       efi_memory_desc_t *md;
-       u64 efi_desc_size;
+       return efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB);
+}
 
-       efi_map_start = __va(ia64_boot_param->efi_memmap);
-       efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
-       efi_desc_size = ia64_boot_param->efi_memdesc_size;
+/*
+ * We allow mmap of anything in the EFI memory map that supports
+ * either write-back or uncacheable access.  For uncacheable regions,
+ * the supported access sizes are system-dependent, and the user is
+ * responsible for using the correct size.
+ *
+ * Note that this doesn't currently allow access to hot-added memory,
+ * because that doesn't appear in the boot-time EFI memory map.
+ */
+int
+valid_mmap_phys_addr_range (unsigned long phys_addr, unsigned long *size)
+{
+       if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB))
+               return 1;
 
-       for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
-               md = p;
+       if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_UC))
+               return 1;
 
-               if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) {
-                       if (!(md->attribute & EFI_MEMORY_WB))
-                               return 0;
+       /*
+        * Some firmware doesn't report MMIO regions in the EFI memory map.
+        * The Intel BigSur (a.k.a. HP i2000) has this problem.  In this
+        * case, we can't use the EFI memory map to validate mmap requests.
+        */
+       if (!efi_memmap_has_mmio())
+               return 1;
 
-                       if (*size > md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - phys_addr)
-                               *size = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - phys_addr;
-                       return 1;
-               }
-       }
        return 0;
 }
 
@@ -707,32 +795,6 @@ efi_uart_console_only(void)
        return 0;
 }
 
-#define efi_md_size(md)        (md->num_pages << EFI_PAGE_SHIFT)
-
-static inline u64
-kmd_end(kern_memdesc_t *kmd)
-{
-       return (kmd->start + (kmd->num_pages << EFI_PAGE_SHIFT));
-}
-
-static inline u64
-efi_md_end(efi_memory_desc_t *md)
-{
-       return (md->phys_addr + efi_md_size(md));
-}
-
-static inline int
-efi_wb(efi_memory_desc_t *md)
-{
-       return (md->attribute & EFI_MEMORY_WB);
-}
-
-static inline int
-efi_uc(efi_memory_desc_t *md)
-{
-       return (md->attribute & EFI_MEMORY_UC);
-}
-
 /*
  * Look for the first granule aligned memory descriptor memory
  * that is big enough to hold EFI memory map. Make sure this
index 0741b066b98fd92af00131bc170b47bbcf6264de..7a6ffd6137895f2abd629ecc936f107251ef6b96 100644 (file)
@@ -1600,5 +1600,6 @@ sys_call_table:
        data8 sys_inotify_init
        data8 sys_inotify_add_watch
        data8 sys_inotify_rm_watch
+       data8 sys_migrate_pages                 // 1280
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
index bfe65b2e862146ad9a16d1761e3f91ff69e05347..fbc7ea35dd5789fab0d15f0a2e7ac1e28b1b99c2 100644 (file)
@@ -1060,7 +1060,7 @@ SET_REG(b5);
         * the clobber lists for spin_lock() in include/asm-ia64/spinlock.h.
         */
 
-#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
+#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
 
 GLOBAL_ENTRY(ia64_spinlock_contention_pre3_4)
        .prologue
index 5db9d3bcbbcbe262b85352e3c8fb3be7d1ff8597..e72de580ebbf8b9a41801c08b7e09da4d9d33a7c 100644 (file)
@@ -103,7 +103,7 @@ EXPORT_SYMBOL(unw_init_running);
 
 #ifdef ASM_SUPPORTED
 # ifdef CONFIG_SMP
-#  if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
+#  if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
 /*
  * This is not a normal routine and we don't want a function descriptor for it, so we use
  * a fake declaration here.
index 4b19d04106326db6b01cfa3735421d07c27a4190..8d88eeea02d12fa762a1d54ba71ce15be73529c9 100644 (file)
@@ -1422,14 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
        lock_kernel();
        ret = -EPERM;
        if (request == PTRACE_TRACEME) {
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
-                       goto out;
-               ret = security_ptrace(current->parent, current);
-               if (ret)
-                       goto out;
-               current->ptrace |= PT_PTRACED;
-               ret = 0;
+               ret = ptrace_traceme();
                goto out;
        }
 
index b7dabbfb0d619b244c897d741701187b27dbf7c0..adb01566bd57306ae23e33af799588421425d8df 100644 (file)
@@ -32,7 +32,7 @@ typedef struct
        u64 *prev_pfs_loc;      /* state for WAR for old spinlock ool code */
 } ia64_backtrace_t;
 
-#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
+#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
 /*
  * Returns non-zero if the PC is in the spinlock contention out-of-line code
  * with non-standard calling sequence (on older compilers).
index cc4b571e5db715c1fba35eab7ce3ee0d1e6784ef..3bf55d92933f62f635c1c1be3290f5fa13cc4348 100644 (file)
@@ -50,6 +50,10 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
  * Powermanagement idle function, if any..
  */
 void (*pm_idle)(void) = NULL;
+EXPORT_SYMBOL(pm_idle);
+
+void (*pm_power_off)(void) = NULL;
+EXPORT_SYMBOL(pm_power_off);
 
 void disable_hlt(void)
 {
index 078d2a0e71c2669f3ce47673bc49e5857a03b3fc..9b75caaf5cec49ba98a0357312f4a4cdbb35042f 100644 (file)
@@ -762,28 +762,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
        int ret;
 
        lock_kernel();
-       ret = -EPERM;
        if (request == PTRACE_TRACEME) {
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
-                       goto out;
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
-               ret = 0;
+               ret = ptrace_traceme();
                goto out;
        }
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
-               goto out;
 
-       ret = -EPERM;
-       if (pid == 1)           /* you may not mess with init */
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
                goto out;
+       }
 
        if (request == PTRACE_ATTACH) {
                ret = ptrace_attach(child);
index 1dd5d18b22019b47eb60117f918510484433b8a6..96b91982805316769128ac8e5a00791b5b4cf8bf 100644 (file)
@@ -10,10 +10,6 @@ config MMU
        bool
        default y
 
-config UID16
-       bool
-       default y
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index b96498120fe9aed0c3dc9565c89e9b93c92bb8d2..e2a6e864896080a42b2cd76e98e43b63d67dc92e 100644 (file)
@@ -17,10 +17,6 @@ config FPU
        bool
        default n
 
-config UID16
-       bool
-       default y
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index 9a9b049721327cb28fca14dffd8b6bf5f5d47ec1..7e55457a491f3c71b730dd5c3286030db571f02f 100644 (file)
@@ -57,30 +57,16 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
               (unsigned long) data);
 #endif
        lock_kernel();
-       ret = -EPERM;
        if (request == PTRACE_TRACEME) {
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
-                       goto out;
-               if ((ret = security_ptrace(current->parent, current)))
-                       goto out;
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
-               ret = 0;
+               ret = ptrace_traceme();
                goto out;
        }
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
-               goto out;
 
-       ret = -EPERM;
-       if (pid == 1)           /* you may not mess with init */
-               goto out_tsk;
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
+               goto out;
+       }
 
        if (request == PTRACE_ATTACH) {
                ret = ptrace_attach(child);
index 06be405be3999f44fe8e30135f73ffe6a0427d86..9c89eebc356febd946fc44c8dc3f5d41eed8d8d2 100644 (file)
@@ -1171,7 +1171,8 @@ static int __init vpe_module_init(void)
                return -ENODEV;
        }
 
-       if ((major = register_chrdev(0, module_name, &vpe_fops) < 0)) {
+       major = register_chrdev(0, module_name, &vpe_fops);
+       if (major < 0) {
                printk("VPE loader: unable to register character device\n");
                return major;
        }
index 07631a97670bd85897c9e9208b708a6200b87bd1..ce907eda221b6b91e395029b30d8eabc4dbe5bd2 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/signal.h>      /* for SIGBUS */
+#include <linux/sched.h>       /* schow_regs(), force_sig() */
 
 #include <asm/module.h>
 #include <asm/sn/addrs.h>
index 874a283edb958c72968258ba13cce826e0884e75..e77a06e9621ec54278ed6c440866e5e9205031c4 100644 (file)
@@ -19,9 +19,6 @@ config MMU
 config STACK_GROWSUP
        def_bool y
 
-config UID16
-       bool
-
 config RWSEM_GENERIC_SPINLOCK
        def_bool y
 
index db93dbc0e21a9896ee25c8dcc1c517f8f330d5cd..28004f002ec9f810e3885db237514fab696a42fe 100644 (file)
@@ -26,9 +26,6 @@ config MMU
        bool
        default y
 
-config UID16
-       bool
-
 config GENERIC_HARDIRQS
        bool
        default y
@@ -50,7 +47,7 @@ config PPC
 
 config EARLY_PRINTK
        bool
-       default y if PPC64
+       default y
 
 config COMPAT
        bool
@@ -300,6 +297,7 @@ config PPC_PMAC64
        bool
        depends on PPC_PMAC && POWER4
        select U3_DART
+       select MPIC_BROKEN_U3
        select GENERIC_TBSYNC
        default y
 
@@ -328,9 +326,7 @@ config PPC_CELL
        select MMIO_NVRAM
 
 config PPC_OF
-       bool
-       depends on PPC_MULTIPLATFORM    # for now
-       default y
+       def_bool y
 
 config XICS
        depends on PPC_PSERIES
@@ -379,11 +375,28 @@ config CELL_IIC
        bool
        default y
 
+config CRASH_DUMP
+       bool "kernel crash dumps (EXPERIMENTAL)"
+       depends on PPC_MULTIPLATFORM
+       depends on EXPERIMENTAL
+       help
+         Build a kernel suitable for use as a kdump capture kernel.
+         The kernel will be linked at a different address than normal, and
+         so can only be used for Kdump.
+
+         Don't change this unless you know what you are doing.
+
 config IBMVIO
        depends on PPC_PSERIES || PPC_ISERIES
        bool
        default y
 
+config IBMEBUS
+       depends on PPC_PSERIES
+       bool "Support for GX bus based adapters"
+       help
+         Bus device driver for GX bus based adapters.
+
 config PPC_MPC106
        bool
        default n
@@ -475,6 +488,7 @@ source arch/powerpc/platforms/embedded6xx/Kconfig
 source arch/powerpc/platforms/4xx/Kconfig
 source arch/powerpc/platforms/85xx/Kconfig
 source arch/powerpc/platforms/8xx/Kconfig
+source arch/powerpc/platforms/cell/Kconfig
 
 menu "Kernel options"
 
@@ -578,11 +592,12 @@ config ARCH_SELECT_MEMORY_MODEL
        depends on PPC64
 
 config ARCH_FLATMEM_ENABLE
-       def_bool y
-       depends on PPC64 && !NUMA
+       def_bool y
+       depends on (PPC64 && !NUMA) || PPC32
 
 config ARCH_SPARSEMEM_ENABLE
        def_bool y
+       depends on PPC64
 
 config ARCH_SPARSEMEM_DEFAULT
        def_bool y
index a13eb575f834c2520d30276aba3e5545ac66f310..5f80e58e5cb34aa4d20e1c0a8c2d13e8c04b2fb3 100644 (file)
@@ -151,7 +151,7 @@ CPPFLAGS_vmlinux.lds        := -Upowerpc
 # All the instructions talk about "make bzImage".
 bzImage: zImage
 
-BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm
+BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage
 
 .PHONY: $(BOOT_TARGETS)
 
index 9770f587af73a73fe2db976c67d7d75ab18d54bf..22726aefc8ea6d3cb68cb8808a0b0859343cafce 100644 (file)
@@ -143,6 +143,36 @@ $(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote
        @cp -f $< $@
        $(call if_changed,addnote)
 
+#-----------------------------------------------------------
+# build u-boot images
+#-----------------------------------------------------------
+quiet_cmd_mygzip = GZIP $@
+cmd_mygzip = gzip -f -9 < $< > $@.$$$$ && mv $@.$$$$ $@
+
+quiet_cmd_objbin = OBJCOPY $@
+      cmd_objbin = $(OBJCOPY) -O binary $< $@
+
+quiet_cmd_uimage = UIMAGE $@
+      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A ppc -O linux -T kernel \
+               -C gzip -a 00000000 -e 00000000 -n 'Linux-$(KERNELRELEASE)' \
+               -d $< $@
+
+MKIMAGE                := $(srctree)/scripts/mkuboot.sh
+targets                += uImage
+extra-y                += vmlinux.bin vmlinux.gz
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objbin)
+
+$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,mygzip)
+
+$(obj)/uImage: $(obj)/vmlinux.gz
+       $(Q)rm -f $@
+       $(call cmd,uimage)
+       @echo -n '  Image: $@ '
+       @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
+
 install: $(CONFIGURE) $(BOOTIMAGE)
        sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
 
diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
new file mode 100644 (file)
index 0000000..398203b
--- /dev/null
@@ -0,0 +1,1729 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc5
+# Tue Dec 13 17:24:05 2005
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# 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_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_LBD=y
+
+#
+# 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"
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
+# CONFIG_PPC_CHRP is not set
+CONFIG_PPC_PMAC=y
+CONFIG_PPC_OF=y
+CONFIG_MPIC=y
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PPC_MPC106=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_PMAC=y
+CONFIG_PPC601_SYNC_FIX=y
+# CONFIG_TAU is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_KEXEC is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+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=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+CONFIG_PM_DEBUG=y
+CONFIG_SOFTWARE_SUSPEND=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=m
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=m
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+# CONFIG_IP_NF_MATCH_SCTP is not set
+CONFIG_IP_NF_MATCH_DCCP=m
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_TARGET_NFQUEUE is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+# CONFIG_IP_NF_MANGLE is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+# CONFIG_IP_DCCP_UNLOAD_HACK is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP 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_NET_DIVERT 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=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+# CONFIG_BT_HCIUART is not set
+CONFIG_BT_HCIBCM203X=m
+# CONFIG_BT_HCIBPA10X is not set
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI 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=m
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_MAC_FLOPPY=y
+# 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
+# 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_SX8 is not set
+CONFIG_BLK_DEV_UB=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_SL82C105=y
+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
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_BLINK=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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+# 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=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MESH_RESET_DELAY_MS=1000
+CONFIG_SCSI_MAC53C94=y
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+# CONFIG_IEEE1394_EXPORT_FULL_API is not set
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+# CONFIG_IEEE1394_CMP is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+CONFIG_ADB=y
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_PMU=y
+CONFIG_PMAC_APM_EMU=y
+CONFIG_PMAC_MEDIABAY=y
+CONFIG_PMAC_BACKLIGHT=y
+CONFIG_INPUT_ADBHID=y
+CONFIG_MAC_EMUMOUSEBTN=y
+CONFIG_THERM_WINDTUNNEL=m
+CONFIG_THERM_ADT746X=m
+# CONFIG_WINDFARM is not set
+# CONFIG_ANSLCD 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
+
+#
+# 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=y
+CONFIG_MACE=y
+# CONFIG_MACE_AAUI_PORT is not set
+CONFIG_BMAC=y
+# CONFIG_HAPPYMEAL is not set
+CONFIG_SUNGEM=y
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_MV643XX_ETH is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+CONFIG_APPLE_AIRPORT=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_NORTEL_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_PCMCIA_SPECTRUM is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+# CONFIG_HOSTAP is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC 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
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+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_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# 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_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=m
+# CONFIG_SERIAL_PMACZILOG is not set
+# CONFIG_SERIAL_JSM is not set
+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_NVRAM=y
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+CONFIG_AGP=m
+CONFIG_AGP_UNINORTH=m
+CONFIG_DRM=m
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# 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_KEYWEST=m
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA 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_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_MACMODES=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_CT65550=y
+# CONFIG_FB_ASILIANT is not set
+CONFIG_FB_IMSTT=y
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=y
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_FB_RIVA is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_FB_MATROX_G is not set
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY_CT=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+# CONFIG_FB_ATY_XL_INIT is not set
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+CONFIG_FB_3DFX=y
+# CONFIG_FB_3DFX_ACCEL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_CYBLA is not set
+# CONFIG_FB_TRIDENT 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
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+CONFIG_DMASOUND_PMAC=m
+CONFIG_DMASOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_GENERIC_DRIVER=y
+
+#
+# Generic devices
+#
+CONFIG_SND_DUMMY=m
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_HDA_INTEL is not set
+
+#
+# ALSA PowerMac devices
+#
+CONFIG_SND_POWERMAC=m
+# CONFIG_SND_POWERMAC_AUTO_DRC is not set
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+# CONFIG_SND_USB_USX2Y is not set
+
+#
+# PCMCIA devices
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# 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_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+CONFIG_USB_APPLETOUCH=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# 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=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=m
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=m
+# CONFIG_USB_ZD1201 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 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_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# 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_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_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_RELAYFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS 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 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_LOCKD=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# 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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# 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=m
+# 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=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+
+#
+# Instrumentation Support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+# CONFIG_BDI_SWITCH is not set
+CONFIG_BOOTX_TEXT=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC 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_DES 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=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
index 9ed551b6c17223258785920f1d37ce2d62868ae8..6e03b595b6c83220e10e97b937f267ada37d2875 100644 (file)
@@ -17,11 +17,11 @@ obj-y                               += vdso32/
 obj-$(CONFIG_PPC64)            += setup_64.o binfmt_elf32.o sys_ppc32.o \
                                   signal_64.o ptrace32.o systbl.o \
                                   paca.o ioctl32.o cpu_setup_power4.o \
-                                  firmware.o sysfs.o udbg.o idle_64.o
+                                  firmware.o sysfs.o idle_64.o
 obj-$(CONFIG_PPC64)            += vdso64/
 obj-$(CONFIG_ALTIVEC)          += vecemu.o vector.o
 obj-$(CONFIG_POWER4)           += idle_power4.o
-obj-$(CONFIG_PPC_OF)           += of_device.o
+obj-$(CONFIG_PPC_OF)           += of_device.o prom_parse.o
 procfs-$(CONFIG_PPC64)         := proc_ppc64.o
 obj-$(CONFIG_PROC_FS)          += $(procfs-y)
 rtaspci-$(CONFIG_PPC64)                := rtas_pci.o
@@ -30,12 +30,10 @@ obj-$(CONFIG_RTAS_FLASH)    += rtas_flash.o
 obj-$(CONFIG_RTAS_PROC)                += rtas-proc.o
 obj-$(CONFIG_LPARCFG)          += lparcfg.o
 obj-$(CONFIG_IBMVIO)           += vio.o
+obj-$(CONFIG_IBMEBUS)           += ibmebus.o
 obj-$(CONFIG_GENERIC_TBSYNC)   += smp-tbsync.o
-obj-$(CONFIG_PPC_PSERIES)      += udbg_16550.o
-obj-$(CONFIG_PPC_MAPLE)                += udbg_16550.o
-udbgscc-$(CONFIG_PPC64)                := udbg_scc.o
-obj-$(CONFIG_PPC_PMAC)         += $(udbgscc-y)
 obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o
+obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 
@@ -48,25 +46,25 @@ extra-$(CONFIG_8xx)         := head_8xx.o
 extra-y                                += vmlinux.lds
 
 obj-y                          += process.o init_task.o time.o \
-                                  prom.o traps.o setup-common.o
+                                  prom.o traps.o setup-common.o udbg.o
 obj-$(CONFIG_PPC32)            += entry_32.o setup_32.o misc_32.o systbl.o
 obj-$(CONFIG_PPC64)            += misc_64.o dma_64.o iommu.o
-obj-$(CONFIG_PPC_OF)           += prom_init.o
+obj-$(CONFIG_PPC_MULTIPLATFORM)        += prom_init.o
 obj-$(CONFIG_MODULES)          += ppc_ksyms.o
 obj-$(CONFIG_BOOTX_TEXT)       += btext.o
 obj-$(CONFIG_6xx)              += idle_6xx.o
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
-
+obj-$(CONFIG_SERIAL_8250)      += legacy_serial.o udbg_16550.o
 module-$(CONFIG_PPC64)         += module_64.o
 obj-$(CONFIG_MODULES)          += $(module-y)
 
 pci64-$(CONFIG_PPC64)          += pci_64.o pci_dn.o pci_iommu.o \
                                   pci_direct_iommu.o iomap.o
 obj-$(CONFIG_PCI)              += $(pci64-y)
-
-kexec64-$(CONFIG_PPC64)                += machine_kexec_64.o
-obj-$(CONFIG_KEXEC)            += $(kexec64-y)
+kexec-$(CONFIG_PPC64)          := machine_kexec_64.o
+kexec-$(CONFIG_PPC32)          := machine_kexec_32.o
+obj-$(CONFIG_KEXEC)            += machine_kexec.o crash.o $(kexec-y)
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
 $(obj)/head_64.o: $(obj)/lparmap.s
index 91538d2445bfa2e29e60237439acd985c4f583a3..56399c5c931a94ef809a61b432ca82311327dceb 100644 (file)
@@ -92,9 +92,9 @@ int main(void)
 
        DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
        DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
-       DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
-#ifdef CONFIG_PPC32
+       DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame));
        DEFINE(TI_TASK, offsetof(struct thread_info, task));
+#ifdef CONFIG_PPC32
        DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
        DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 #endif /* CONFIG_PPC32 */
@@ -131,11 +131,9 @@ int main(void)
        DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
        DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
 #endif /* CONFIG_HUGETLB_PAGE */
-       DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
        DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
        DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
        DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
-       DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi));
        DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
        DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca));
        DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
index bdfba92b2b3869972a253f40f49a47f087d46f0d..6223d39177cb7c7bd9ee408be588e9cfa3d06014 100644 (file)
@@ -31,15 +31,18 @@ static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);
 static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
 static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
 
-static int g_loc_X;
-static int g_loc_Y;
-static int g_max_loc_X;
-static int g_max_loc_Y;
+#define __force_data __attribute__((__section__(".data")))
 
-static int dispDeviceRowBytes;
-static int dispDeviceDepth;
-static int dispDeviceRect[4];
-static unsigned char *dispDeviceBase, *logicalDisplayBase;
+static int g_loc_X __force_data;
+static int g_loc_Y __force_data;
+static int g_max_loc_X __force_data;
+static int g_max_loc_Y __force_data;
+
+static int dispDeviceRowBytes __force_data;
+static int dispDeviceDepth  __force_data;
+static int dispDeviceRect[4] __force_data;
+static unsigned char *dispDeviceBase __force_data;
+static unsigned char *logicalDisplayBase __force_data;
 
 unsigned long disp_BAT[2] __initdata = {0, 0};
 
@@ -47,7 +50,7 @@ unsigned long disp_BAT[2] __initdata = {0, 0};
 
 static unsigned char vga_font[cmapsz];
 
-int boot_text_mapped;
+int boot_text_mapped __force_data = 0;
 int force_printk_to_btext = 0;
 
 #ifdef CONFIG_PPC32
@@ -57,7 +60,7 @@ int force_printk_to_btext = 0;
  *
  * The display is mapped to virtual address 0xD0000000, rather
  * than 1:1, because some some CHRP machines put the frame buffer
- * in the region starting at 0xC0000000 (KERNELBASE).
+ * in the region starting at 0xC0000000 (PAGE_OFFSET).
  * This mapping is temporary and will disappear as soon as the
  * setup done by MMU_Init() is applied.
  *
@@ -66,10 +69,9 @@ int force_printk_to_btext = 0;
  * is really badly aligned, but I didn't encounter this case
  * yet.
  */
-void __init
-btext_prepare_BAT(void)
+void __init btext_prepare_BAT(void)
 {
-       unsigned long vaddr = KERNELBASE + 0x10000000;
+       unsigned long vaddr = PAGE_OFFSET + 0x10000000;
        unsigned long addr;
        unsigned long lowbits;
 
@@ -95,12 +97,13 @@ btext_prepare_BAT(void)
 }
 #endif
 
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
+
+/* This function can be used to enable the early boot text when doing
+ * OF booting or within bootx init. It must be followed by a btext_unmap()
+ * call before the logical address becomes unuseable
  */
-void __init
-btext_setup_display(int width, int height, int depth, int pitch,
-                   unsigned long address)
+void __init btext_setup_display(int width, int height, int depth, int pitch,
+                               unsigned long address)
 {
        g_loc_X = 0;
        g_loc_Y = 0;
@@ -116,6 +119,11 @@ btext_setup_display(int width, int height, int depth, int pitch,
        boot_text_mapped = 1;
 }
 
+void __init btext_unmap(void)
+{
+       boot_text_mapped = 0;
+}
+
 /* Here's a small text engine to use during early boot
  * or for debugging purposes
  *
@@ -127,7 +135,7 @@ btext_setup_display(int width, int height, int depth, int pitch,
  *    changes.
  */
 
-void map_boot_text(void)
+static void map_boot_text(void)
 {
        unsigned long base, offset, size;
        unsigned char *vbase;
@@ -175,8 +183,9 @@ int btext_initialize(struct device_node *np)
        if (prop)
                address = *prop;
 
-       /* FIXME: Add support for PCI reg properties */
-
+       /* FIXME: Add support for PCI reg properties. Right now, only
+        * reliable on macs
+        */
        if (address == 0)
                return -EINVAL;
 
@@ -184,7 +193,6 @@ int btext_initialize(struct device_node *np)
        g_loc_Y = 0;
        g_max_loc_X = width / 8;
        g_max_loc_Y = height / 16;
-       logicalDisplayBase = (unsigned char *)address;
        dispDeviceBase = (unsigned char *)address;
        dispDeviceRowBytes = pitch;
        dispDeviceDepth = depth;
@@ -197,14 +205,12 @@ int btext_initialize(struct device_node *np)
        return 0;
 }
 
-void __init init_boot_display(void)
+int __init btext_find_display(int allow_nonstdout)
 {
        char *name;
        struct device_node *np = NULL; 
        int rc = -ENODEV;
 
-       printk("trying to initialize btext ...\n");
-
        name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
        if (name != NULL) {
                np = of_find_node_by_path(name);
@@ -218,8 +224,8 @@ void __init init_boot_display(void)
        }
        if (np)
                rc = btext_initialize(np);
-       if (rc == 0)
-               return;
+       if (rc == 0 || !allow_nonstdout)
+               return rc;
 
        for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
                if (get_property(np, "linux,opened", NULL)) {
@@ -228,8 +234,9 @@ void __init init_boot_display(void)
                        printk("result: %d\n", rc);
                }
                if (rc == 0)
-                       return;
+                       break;
        }
+       return rc;
 }
 
 /* Calc the base address of a given point (x,y) */
@@ -277,44 +284,83 @@ EXPORT_SYMBOL(btext_update_display);
 
 void btext_clearscreen(void)
 {
-       unsigned long *base     = (unsigned long *)calc_base(0, 0);
+       unsigned int *base      = (unsigned int *)calc_base(0, 0);
        unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
-                                       (dispDeviceDepth >> 3)) >> 3;
+                                       (dispDeviceDepth >> 3)) >> 2;
        int i,j;
 
        for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
        {
-               unsigned long *ptr = base;
+               unsigned int *ptr = base;
                for(j=width; j; --j)
                        *(ptr++) = 0;
-               base += (dispDeviceRowBytes >> 3);
+               base += (dispDeviceRowBytes >> 2);
        }
 }
 
+void btext_flushscreen(void)
+{
+       unsigned int *base      = (unsigned int *)calc_base(0, 0);
+       unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
+                                       (dispDeviceDepth >> 3)) >> 2;
+       int i,j;
+
+       for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++)
+       {
+               unsigned int *ptr = base;
+               for(j = width; j > 0; j -= 8) {
+                       __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
+                       ptr += 8;
+               }
+               base += (dispDeviceRowBytes >> 2);
+       }
+       __asm__ __volatile__ ("sync" ::: "memory");
+}
+
+void btext_flushline(void)
+{
+       unsigned int *base      = (unsigned int *)calc_base(0, g_loc_Y << 4);
+       unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
+                                       (dispDeviceDepth >> 3)) >> 2;
+       int i,j;
+
+       for (i=0; i < 16; i++)
+       {
+               unsigned int *ptr = base;
+               for(j = width; j > 0; j -= 8) {
+                       __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
+                       ptr += 8;
+               }
+               base += (dispDeviceRowBytes >> 2);
+       }
+       __asm__ __volatile__ ("sync" ::: "memory");
+}
+
+
 #ifndef NO_SCROLL
 static void scrollscreen(void)
 {
-       unsigned long *src      = (unsigned long *)calc_base(0,16);
-       unsigned long *dst      = (unsigned long *)calc_base(0,0);
+       unsigned int *src       = (unsigned int *)calc_base(0,16);
+       unsigned int *dst       = (unsigned int *)calc_base(0,0);
        unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
-                                  (dispDeviceDepth >> 3)) >> 3;
+                                  (dispDeviceDepth >> 3)) >> 2;
        int i,j;
 
        for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
        {
-               unsigned long *src_ptr = src;
-               unsigned long *dst_ptr = dst;
+               unsigned int *src_ptr = src;
+               unsigned int *dst_ptr = dst;
                for(j=width; j; --j)
                        *(dst_ptr++) = *(src_ptr++);
-               src += (dispDeviceRowBytes >> 3);
-               dst += (dispDeviceRowBytes >> 3);
+               src += (dispDeviceRowBytes >> 2);
+               dst += (dispDeviceRowBytes >> 2);
        }
        for (i=0; i<16; i++)
        {
-               unsigned long *dst_ptr = dst;
+               unsigned int *dst_ptr = dst;
                for(j=width; j; --j)
                        *(dst_ptr++) = 0;
-               dst += (dispDeviceRowBytes >> 3);
+               dst += (dispDeviceRowBytes >> 2);
        }
 }
 #endif /* ndef NO_SCROLL */
@@ -377,6 +423,14 @@ void btext_drawstring(const char *c)
                btext_drawchar(*c++);
 }
 
+void btext_drawtext(const char *c, unsigned int len)
+{
+       if (!boot_text_mapped)
+               return;
+       while (len--)
+               btext_drawchar(*c++);
+}
+
 void btext_drawhex(unsigned long v)
 {
        char *hex_table = "0123456789abcdef";
index 1d85cedbbb7b740d4ed9d14db828e469f2942244..43c74a6b07b1502e5039f8d10ea2e9a3d1f2ade5 100644 (file)
@@ -78,10 +78,8 @@ struct cpu_spec      cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/power3",
-               .oprofile_model         = &op_model_rs64,
-#endif
+               .oprofile_type          = RS64,
        },
        {       /* Power3+ */
                .pvr_mask               = 0xffff0000,
@@ -93,10 +91,8 @@ struct cpu_spec      cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/power3",
-               .oprofile_model         = &op_model_rs64,
-#endif
+               .oprofile_type          = RS64,
        },
        {       /* Northstar */
                .pvr_mask               = 0xffff0000,
@@ -108,10 +104,8 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/rs64",
-               .oprofile_model         = &op_model_rs64,
-#endif
+               .oprofile_type          = RS64,
        },
        {       /* Pulsar */
                .pvr_mask               = 0xffff0000,
@@ -123,10 +117,8 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/rs64",
-               .oprofile_model         = &op_model_rs64,
-#endif
+               .oprofile_type          = RS64,
        },
        {       /* I-star */
                .pvr_mask               = 0xffff0000,
@@ -138,10 +130,8 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/rs64",
-               .oprofile_model         = &op_model_rs64,
-#endif
+               .oprofile_type          = RS64,
        },
        {       /* S-star */
                .pvr_mask               = 0xffff0000,
@@ -153,10 +143,8 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/rs64",
-               .oprofile_model         = &op_model_rs64,
-#endif
+               .oprofile_type          = RS64,
        },
        {       /* Power4 */
                .pvr_mask               = 0xffff0000,
@@ -168,10 +156,8 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/power4",
-               .oprofile_model         = &op_model_rs64,
-#endif
+               .oprofile_type          = POWER4,
        },
        {       /* Power4+ */
                .pvr_mask               = 0xffff0000,
@@ -183,10 +169,8 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/power4",
-               .oprofile_model         = &op_model_power4,
-#endif
+               .oprofile_type          = POWER4,
        },
        {       /* PPC970 */
                .pvr_mask               = 0xffff0000,
@@ -199,10 +183,8 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/970",
-               .oprofile_model         = &op_model_power4,
-#endif
+               .oprofile_type          = POWER4,
        },
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_PPC64) || defined(CONFIG_POWER4)
@@ -221,10 +203,8 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/970",
-               .oprofile_model         = &op_model_power4,
-#endif
+               .oprofile_type          = POWER4,
        },
 #endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */
 #ifdef CONFIG_PPC64
@@ -238,10 +218,8 @@ struct cpu_spec    cpu_specs[] = {
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
                .cpu_setup              = __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/970",
-               .oprofile_model         = &op_model_power4,
-#endif
+               .oprofile_type          = POWER4,
        },
        {       /* Power5 GR */
                .pvr_mask               = 0xffff0000,
@@ -253,27 +231,23 @@ struct cpu_spec   cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
                .oprofile_cpu_type      = "ppc64/power5",
-               .oprofile_model         = &op_model_power4,
-#endif
+               .oprofile_type          = POWER4,
        },
        {       /* Power5 GS */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x003b0000,
-               .cpu_name               = "POWER5 (gs)",
+               .cpu_name               = "POWER5+ (gs)",
                .cpu_features           = CPU_FTRS_POWER5,
                .cpu_user_features      = COMMON_USER_POWER5_PLUS,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
-               .oprofile_cpu_type      = "ppc64/power5",
-               .oprofile_model         = &op_model_power4,
-#endif
+               .oprofile_cpu_type      = "ppc64/power5+",
+               .oprofile_type          = POWER4,
        },
-       {       /* BE DD1.x */
+       {       /* Cell Broadband Engine */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x00700000,
                .cpu_name               = "Cell Broadband Engine",
@@ -545,7 +519,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7450 2.1 */
                .pvr_mask               = 0xffffffff,
@@ -556,7 +532,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7450 2.3 and newer */
                .pvr_mask               = 0xffff0000,
@@ -567,7 +545,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7455 rev 1.x */
                .pvr_mask               = 0xffffff00,
@@ -578,7 +558,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7455 rev 2.0 */
                .pvr_mask               = 0xffffffff,
@@ -589,7 +571,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7455 others */
                .pvr_mask               = 0xffff0000,
@@ -600,7 +584,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7447/7457 Rev 1.0 */
                .pvr_mask               = 0xffffffff,
@@ -611,7 +597,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7447/7457 Rev 1.1 */
                .pvr_mask               = 0xffffffff,
@@ -622,7 +610,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7447/7457 Rev 1.2 and later */
                .pvr_mask               = 0xffff0000,
@@ -633,7 +623,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7447A */
                .pvr_mask               = 0xffff0000,
@@ -644,7 +636,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 7448 */
                .pvr_mask               = 0xffff0000,
@@ -655,7 +649,9 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
+               .cpu_setup              = __setup_cpu_745x,
+               .oprofile_cpu_type      = "ppc/7450",
+               .oprofile_type          = G4,
        },
        {       /* 82xx (8240, 8245, 8260 are all 603e cores) */
                .pvr_mask               = 0x7fff0000,
@@ -979,6 +975,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .oprofile_cpu_type      = "ppc/e500",
+               .oprofile_type          = BOOKE,
        },
        {       /* e500v2 */
                .pvr_mask               = 0xffff0000,
@@ -992,6 +990,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .oprofile_cpu_type      = "ppc/e500",
+               .oprofile_type          = BOOKE,
        },
 #endif
 #if !CLASSIC_PPC
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
new file mode 100644 (file)
index 0000000..4681155
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Architecture specific (PPC64) functions for kexec based crash dumps.
+ *
+ * Copyright (C) 2005, IBM Corp.
+ *
+ * Created by: Haren Myneni
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/reboot.h>
+#include <linux/kexec.h>
+#include <linux/bootmem.h>
+#include <linux/crash_dump.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/kdump.h>
+#include <asm/lmb.h>
+#include <asm/firmware.h>
+
+#ifdef DEBUG
+#include <asm/udbg.h>
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/* This keeps a track of which one is crashing cpu. */
+int crashing_cpu = -1;
+
+static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
+                                                              size_t data_len)
+{
+       struct elf_note note;
+
+       note.n_namesz = strlen(name) + 1;
+       note.n_descsz = data_len;
+       note.n_type   = type;
+       memcpy(buf, &note, sizeof(note));
+       buf += (sizeof(note) +3)/4;
+       memcpy(buf, name, note.n_namesz);
+       buf += (note.n_namesz + 3)/4;
+       memcpy(buf, data, note.n_descsz);
+       buf += (note.n_descsz + 3)/4;
+
+       return buf;
+}
+
+static void final_note(u32 *buf)
+{
+       struct elf_note note;
+
+       note.n_namesz = 0;
+       note.n_descsz = 0;
+       note.n_type   = 0;
+       memcpy(buf, &note, sizeof(note));
+}
+
+static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
+{
+       struct elf_prstatus prstatus;
+       u32 *buf;
+
+       if ((cpu < 0) || (cpu >= NR_CPUS))
+               return;
+
+       /* Using ELF notes here is opportunistic.
+        * I need a well defined structure format
+        * for the data I pass, and I need tags
+        * on the data to indicate what information I have
+        * squirrelled away.  ELF notes happen to provide
+        * all of that that no need to invent something new.
+        */
+       buf = &crash_notes[cpu][0];
+       memset(&prstatus, 0, sizeof(prstatus));
+       prstatus.pr_pid = current->pid;
+       elf_core_copy_regs(&prstatus.pr_reg, regs);
+       buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
+                       sizeof(prstatus));
+       final_note(buf);
+}
+
+/* FIXME Merge this with xmon_save_regs ?? */
+static inline void crash_get_current_regs(struct pt_regs *regs)
+{
+       unsigned long tmp1, tmp2;
+
+       __asm__ __volatile__ (
+               "std    0,0(%2)\n"
+               "std    1,8(%2)\n"
+               "std    2,16(%2)\n"
+               "std    3,24(%2)\n"
+               "std    4,32(%2)\n"
+               "std    5,40(%2)\n"
+               "std    6,48(%2)\n"
+               "std    7,56(%2)\n"
+               "std    8,64(%2)\n"
+               "std    9,72(%2)\n"
+               "std    10,80(%2)\n"
+               "std    11,88(%2)\n"
+               "std    12,96(%2)\n"
+               "std    13,104(%2)\n"
+               "std    14,112(%2)\n"
+               "std    15,120(%2)\n"
+               "std    16,128(%2)\n"
+               "std    17,136(%2)\n"
+               "std    18,144(%2)\n"
+               "std    19,152(%2)\n"
+               "std    20,160(%2)\n"
+               "std    21,168(%2)\n"
+               "std    22,176(%2)\n"
+               "std    23,184(%2)\n"
+               "std    24,192(%2)\n"
+               "std    25,200(%2)\n"
+               "std    26,208(%2)\n"
+               "std    27,216(%2)\n"
+               "std    28,224(%2)\n"
+               "std    29,232(%2)\n"
+               "std    30,240(%2)\n"
+               "std    31,248(%2)\n"
+               "mfmsr  %0\n"
+               "std    %0, 264(%2)\n"
+               "mfctr  %0\n"
+               "std    %0, 280(%2)\n"
+               "mflr   %0\n"
+               "std    %0, 288(%2)\n"
+               "bl     1f\n"
+       "1:      mflr   %1\n"
+               "std    %1, 256(%2)\n"
+               "mtlr   %0\n"
+               "mfxer  %0\n"
+               "std    %0, 296(%2)\n"
+               : "=&r" (tmp1), "=&r" (tmp2)
+               : "b" (regs));
+}
+
+/* We may have saved_regs from where the error came from
+ * or it is NULL if via a direct panic().
+ */
+static void crash_save_self(struct pt_regs *saved_regs)
+{
+       struct pt_regs regs;
+       int cpu;
+
+       cpu = smp_processor_id();
+       if (saved_regs)
+               memcpy(&regs, saved_regs, sizeof(regs));
+       else
+               crash_get_current_regs(&regs);
+       crash_save_this_cpu(&regs, cpu);
+}
+
+#ifdef CONFIG_SMP
+static atomic_t waiting_for_crash_ipi;
+
+void crash_ipi_callback(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       if (cpu == crashing_cpu)
+               return;
+
+       if (!cpu_online(cpu))
+               return;
+
+       if (ppc_md.kexec_cpu_down)
+               ppc_md.kexec_cpu_down(1, 1);
+
+       local_irq_disable();
+
+       crash_save_this_cpu(regs, cpu);
+       atomic_dec(&waiting_for_crash_ipi);
+       kexec_smp_wait();
+       /* NOTREACHED */
+}
+
+static void crash_kexec_prepare_cpus(void)
+{
+       unsigned int msecs;
+
+       atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+
+       crash_send_ipi(crash_ipi_callback);
+       smp_wmb();
+
+       /*
+        * FIXME: Until we will have the way to stop other CPUSs reliabally,
+        * the crash CPU will send an IPI and wait for other CPUs to
+        * respond. If not, proceed the kexec boot even though we failed to
+        * capture other CPU states.
+        */
+       msecs = 1000000;
+       while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) {
+               barrier();
+               mdelay(1);
+       }
+
+       /* Would it be better to replace the trap vector here? */
+
+       /*
+        * FIXME: In case if we do not get all CPUs, one possibility: ask the
+        * user to do soft reset such that we get all.
+        * IPI handler is already set by the panic cpu initially. Therefore,
+        * all cpus could invoke this handler from die() and the panic CPU
+        * will call machine_kexec() directly from this handler to do
+        * kexec boot.
+        */
+       if (atomic_read(&waiting_for_crash_ipi))
+               printk(KERN_ALERT "done waiting: %d cpus not responding\n",
+                       atomic_read(&waiting_for_crash_ipi));
+       /* Leave the IPI callback set */
+}
+#else
+static void crash_kexec_prepare_cpus(void)
+{
+       /*
+        * move the secondarys to us so that we can copy
+        * the new kernel 0-0x100 safely
+        *
+        * do this if kexec in setup.c ?
+        */
+       smp_release_cpus();
+}
+
+#endif
+
+void default_machine_crash_shutdown(struct pt_regs *regs)
+{
+       /*
+        * This function is only called after the system
+        * has paniced or is otherwise in a critical state.
+        * The minimum amount of code to allow a kexec'd kernel
+        * to run successfully needs to happen here.
+        *
+        * In practice this means stopping other cpus in
+        * an SMP system.
+        * The kernel is broken so disable interrupts.
+        */
+       local_irq_disable();
+
+       if (ppc_md.kexec_cpu_down)
+               ppc_md.kexec_cpu_down(1, 0);
+
+       /*
+        * Make a note of crashing cpu. Will be used in machine_kexec
+        * such that another IPI will not be sent.
+        */
+       crashing_cpu = smp_processor_id();
+       crash_kexec_prepare_cpus();
+       crash_save_self(regs);
+}
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
new file mode 100644 (file)
index 0000000..87effa3
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Routines for doing kexec-based kdump.
+ *
+ * Copyright (C) 2005, IBM Corp.
+ *
+ * Created by: Michael Ellerman
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/crash_dump.h>
+#include <linux/bootmem.h>
+#include <asm/kdump.h>
+#include <asm/lmb.h>
+#include <asm/firmware.h>
+#include <asm/uaccess.h>
+
+#ifdef DEBUG
+#include <asm/udbg.h>
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static void __init create_trampoline(unsigned long addr)
+{
+       /* The maximum range of a single instruction branch, is the current
+        * instruction's address + (32 MB - 4) bytes. For the trampoline we
+        * need to branch to current address + 32 MB. So we insert a nop at
+        * the trampoline address, then the next instruction (+ 4 bytes)
+        * does a branch to (32 MB - 4). The net effect is that when we
+        * branch to "addr" we jump to ("addr" + 32 MB). Although it requires
+        * two instructions it doesn't require any registers.
+        */
+       create_instruction(addr, 0x60000000); /* nop */
+       create_branch(addr + 4, addr + PHYSICAL_START, 0);
+}
+
+void __init kdump_setup(void)
+{
+       unsigned long i;
+
+       DBG(" -> kdump_setup()\n");
+
+       for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) {
+               create_trampoline(i);
+       }
+
+       create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START);
+       create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START);
+
+       DBG(" <- kdump_setup()\n");
+}
+
+static int __init parse_elfcorehdr(char *p)
+{
+       if (p)
+               elfcorehdr_addr = memparse(p, &p);
+
+       return 0;
+}
+__setup("elfcorehdr=", parse_elfcorehdr);
+
+static int __init parse_savemaxmem(char *p)
+{
+       if (p)
+               saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
+
+       return 0;
+}
+__setup("savemaxmem=", parse_savemaxmem);
+
+/*
+ * copy_oldmem_page - copy one page from "oldmem"
+ * @pfn: page frame number to be copied
+ * @buf: target memory address for the copy; this can be in kernel address
+ *      space or user address space (see @userbuf)
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page (based on pfn) to begin the copy
+ * @userbuf: if set, @buf is in user address space, use copy_to_user(),
+ *      otherwise @buf is in kernel address space, use memcpy().
+ *
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+                       size_t csize, unsigned long offset, int userbuf)
+{
+       void  *vaddr;
+
+       if (!csize)
+               return 0;
+
+       vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0);
+
+       if (userbuf) {
+               if (copy_to_user((char __user *)buf, (vaddr + offset), csize)) {
+                       iounmap(vaddr);
+                       return -EFAULT;
+               }
+       } else
+               memcpy(buf, (vaddr + offset), csize);
+
+       iounmap(vaddr);
+       return csize;
+}
index 7c3419656ccce2f96fe98cd7a5362f6ab6bd671b..36aaa7663f028c53aec287fd65f97d7735cf5b4e 100644 (file)
@@ -10,6 +10,7 @@
 /* Include the busses we support */
 #include <linux/pci.h>
 #include <asm/vio.h>
+#include <asm/ibmebus.h>
 #include <asm/scatterlist.h>
 #include <asm/bug.h>
 
@@ -22,6 +23,10 @@ static struct dma_mapping_ops *get_dma_ops(struct device *dev)
 #ifdef CONFIG_IBMVIO
        if (dev->bus == &vio_bus_type)
                return &vio_dma_ops;
+#endif
+#ifdef CONFIG_IBMEBUS
+       if (dev->bus == &ibmebus_bus_type)
+               return &ibmebus_dma_ops;
 #endif
        return NULL;
 }
@@ -47,6 +52,10 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
        if (dev->bus == &vio_bus_type)
                return -EIO;
 #endif /* CONFIG_IBMVIO */
+#ifdef CONFIG_IBMEBUS
+       if (dev->bus == &ibmebus_bus_type)
+               return -EIO;
+#endif
        BUG();
        return 0;
 }
index 2e99ae41723c5a1d0a6d84124f393364fafbb665..036b71d2adfc191c0dd5e33be04264aae16894e0 100644 (file)
@@ -200,8 +200,6 @@ _GLOBAL(DoSyscall)
        bl      do_show_syscall
 #endif /* SHOW_SYSCALLS */
        rlwinm  r10,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
-       li      r11,0
-       stb     r11,TI_SC_NOERR(r10)
        lwz     r11,TI_FLAGS(r10)
        andi.   r11,r11,_TIF_SYSCALL_T_OR_A
        bne-    syscall_dotrace
@@ -222,25 +220,21 @@ ret_from_syscall:
        bl      do_show_syscall_exit
 #endif
        mr      r6,r3
-       li      r11,-_LAST_ERRNO
-       cmplw   0,r3,r11
        rlwinm  r12,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
-       blt+    30f
-       lbz     r11,TI_SC_NOERR(r12)
-       cmpwi   r11,0
-       bne     30f
-       neg     r3,r3
-       lwz     r10,_CCR(r1)    /* Set SO bit in CR */
-       oris    r10,r10,0x1000
-       stw     r10,_CCR(r1)
-
        /* disable interrupts so current_thread_info()->flags can't change */
-30:    LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
+       LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
        SYNC
        MTMSRD(r10)
        lwz     r9,TI_FLAGS(r12)
-       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+       li      r8,-_LAST_ERRNO
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
        bne-    syscall_exit_work
+       cmplw   0,r3,r8
+       blt+    syscall_exit_cont
+       lwz     r11,_CCR(r1)                    /* Load CR */
+       neg     r3,r3
+       oris    r11,r11,0x1000  /* Set SO bit in CR */
+       stw     r11,_CCR(r1)
 syscall_exit_cont:
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
        /* If the process has its own DBCR0 value, load it up.  The single
@@ -292,46 +286,113 @@ syscall_dotrace:
        b       syscall_dotrace_cont
 
 syscall_exit_work:
-       stw     r6,RESULT(r1)   /* Save result */
+       andi.   r0,r9,_TIF_RESTOREALL
+       bne-    2f
+       cmplw   0,r3,r8
+       blt+    1f
+       andi.   r0,r9,_TIF_NOERROR
+       bne-    1f
+       lwz     r11,_CCR(r1)                    /* Load CR */
+       neg     r3,r3
+       oris    r11,r11,0x1000  /* Set SO bit in CR */
+       stw     r11,_CCR(r1)
+
+1:     stw     r6,RESULT(r1)   /* Save result */
        stw     r3,GPR3(r1)     /* Update return value */
-       andi.   r0,r9,_TIF_SYSCALL_T_OR_A
-       beq     5f
-       ori     r10,r10,MSR_EE
-       SYNC
-       MTMSRD(r10)             /* re-enable interrupts */
+2:     andi.   r0,r9,(_TIF_PERSYSCALL_MASK)
+       beq     4f
+
+       /* Clear per-syscall TIF flags if any are set, but _leave_
+       _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+       yet.  */
+
+       li      r11,_TIF_PERSYSCALL_MASK
+       addi    r12,r12,TI_FLAGS
+3:     lwarx   r8,0,r12
+       andc    r8,r8,r11
+#ifdef CONFIG_IBM405_ERR77
+       dcbt    0,r12
+#endif
+       stwcx.  r8,0,r12
+       bne-    3b
+       subi    r12,r12,TI_FLAGS
+       
+4:     /* Anything which requires enabling interrupts? */
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+       beq     7f
+
+       /* Save NVGPRS if they're not saved already */
        lwz     r4,_TRAP(r1)
        andi.   r4,r4,1
-       beq     4f
+       beq     5f
        SAVE_NVGPRS(r1)
        li      r4,0xc00
        stw     r4,_TRAP(r1)
-4:
+
+       /* Re-enable interrupts */
+5:     ori     r10,r10,MSR_EE
+       SYNC
+       MTMSRD(r10)
+
+       andi.   r0,r9,_TIF_SAVE_NVGPRS
+       bne     save_user_nvgprs
+
+save_user_nvgprs_cont:
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+       beq     7f
+
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      do_syscall_trace_leave
        REST_NVGPRS(r1)
-2:
-       lwz     r3,GPR3(r1)
+
+6:     lwz     r3,GPR3(r1)
        LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
        SYNC
        MTMSRD(r10)             /* disable interrupts again */
        rlwinm  r12,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
        lwz     r9,TI_FLAGS(r12)
-5:
+7:
        andi.   r0,r9,_TIF_NEED_RESCHED
-       bne     1f
+       bne     8f
        lwz     r5,_MSR(r1)
        andi.   r5,r5,MSR_PR
-       beq     syscall_exit_cont
+       beq     ret_from_except
        andi.   r0,r9,_TIF_SIGPENDING
-       beq     syscall_exit_cont
+       beq     ret_from_except
        b       do_user_signal
-1:
+8:
        ori     r10,r10,MSR_EE
        SYNC
        MTMSRD(r10)             /* re-enable interrupts */
        bl      schedule
-       b       2b
+       b       6b
+
+save_user_nvgprs:
+       lwz     r8,TI_SIGFRAME(r12)
+
+.macro savewords start, end
+  1:   stw \start,4*(\start)(r8)
+       .section __ex_table,"a"
+       .align  2
+       .long   1b,save_user_nvgprs_fault
+       .previous
+       .if \end - \start
+       savewords "(\start+1)",\end
+       .endif
+.endm  
+       savewords 14,31
+       b       save_user_nvgprs_cont
+
+       
+save_user_nvgprs_fault:
+       li      r3,11           /* SIGSEGV */
+       lwz     r4,TI_TASK(r12)
+       bl      force_sigsegv
 
+       rlwinm  r12,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
+       lwz     r9,TI_FLAGS(r12)
+       b       save_user_nvgprs_cont
+       
 #ifdef SHOW_SYSCALLS
 do_show_syscall:
 #ifdef SHOW_SYSCALLS_TASK
@@ -401,28 +462,10 @@ show_syscalls_task:
 #endif /* SHOW_SYSCALLS */
 
 /*
- * The sigsuspend and rt_sigsuspend system calls can call do_signal
- * and thus put the process into the stopped state where we might
- * want to examine its user state with ptrace.  Therefore we need
- * to save all the nonvolatile registers (r13 - r31) before calling
- * the C code.
+ * The fork/clone functions need to copy the full register set into
+ * the child process. Therefore we need to save all the nonvolatile
+ * registers (r13 - r31) before calling the C code.
  */
-       .globl  ppc_sigsuspend
-ppc_sigsuspend:
-       SAVE_NVGPRS(r1)
-       lwz     r0,_TRAP(r1)
-       rlwinm  r0,r0,0,0,30            /* clear LSB to indicate full */
-       stw     r0,_TRAP(r1)            /* register set saved */
-       b       sys_sigsuspend
-
-       .globl  ppc_rt_sigsuspend
-ppc_rt_sigsuspend:
-       SAVE_NVGPRS(r1)
-       lwz     r0,_TRAP(r1)
-       rlwinm  r0,r0,0,0,30
-       stw     r0,_TRAP(r1)
-       b       sys_rt_sigsuspend
-
        .globl  ppc_fork
 ppc_fork:
        SAVE_NVGPRS(r1)
@@ -447,14 +490,6 @@ ppc_clone:
        stw     r0,_TRAP(r1)            /* register set saved */
        b       sys_clone
 
-       .globl  ppc_swapcontext
-ppc_swapcontext:
-       SAVE_NVGPRS(r1)
-       lwz     r0,_TRAP(r1)
-       rlwinm  r0,r0,0,0,30            /* clear LSB to indicate full */
-       stw     r0,_TRAP(r1)            /* register set saved */
-       b       sys_swapcontext
-
 /*
  * Top-level page fault handling.
  * This is in assembler because if do_page_fault tells us that
@@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
        .long   ret_from_except
 #endif
 
-       .globl  sigreturn_exit
-sigreturn_exit:
-       subi    r1,r3,STACK_FRAME_OVERHEAD
-       rlwinm  r12,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
-       lwz     r9,TI_FLAGS(r12)
-       andi.   r0,r9,_TIF_SYSCALL_T_OR_A
-       beq+    ret_from_except_full
-       bl      do_syscall_trace_leave
-       /* fall through */
-
        .globl  ret_from_except_full
 ret_from_except_full:
        REST_NVGPRS(r1)
@@ -658,7 +683,7 @@ user_exc_return:            /* r10 contains MSR_KERNEL here */
        /* Check current_thread_info()->flags */
        rlwinm  r9,r1,0,0,(31-THREAD_SHIFT)
        lwz     r9,TI_FLAGS(r9)
-       andi.   r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+       andi.   r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
        bne     do_work
 
 restore_user:
index bce33a38399fb41f04a12157a154aca99a8c82e9..aacebb33e98a1a9224371e943e5c9fb9f5163512 100644 (file)
@@ -113,9 +113,7 @@ system_call_common:
        addi    r9,r1,STACK_FRAME_OVERHEAD
 #endif
        clrrdi  r11,r1,THREAD_SHIFT
-       li      r12,0
        ld      r10,TI_FLAGS(r11)
-       stb     r12,TI_SC_NOERR(r11)
        andi.   r11,r10,_TIF_SYSCALL_T_OR_A
        bne-    syscall_dotrace
 syscall_dotrace_cont:
@@ -144,24 +142,12 @@ system_call:                      /* label this so stack traces look sane */
        bctrl                   /* Call handler */
 
 syscall_exit:
+       std     r3,RESULT(r1)
 #ifdef SHOW_SYSCALLS
-       std     r3,GPR3(r1)
        bl      .do_show_syscall_exit
-       ld      r3,GPR3(r1)
+       ld      r3,RESULT(r1)
 #endif
-       std     r3,RESULT(r1)
-       ld      r5,_CCR(r1)
-       li      r10,-_LAST_ERRNO
-       cmpld   r3,r10
        clrrdi  r12,r1,THREAD_SHIFT
-       bge-    syscall_error
-syscall_error_cont:
-
-       /* check for syscall tracing or audit */
-       ld      r9,TI_FLAGS(r12)
-       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
-       bne-    syscall_exit_trace
-syscall_exit_trace_cont:
 
        /* disable interrupts so current_thread_info()->flags can't change,
           and so that we don't get interrupted after loading SRR0/1. */
@@ -173,8 +159,13 @@ syscall_exit_trace_cont:
        rotldi  r10,r10,16
        mtmsrd  r10,1
        ld      r9,TI_FLAGS(r12)
-       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+       li      r11,-_LAST_ERRNO
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR)
        bne-    syscall_exit_work
+       cmpld   r3,r11
+       ld      r5,_CCR(r1)
+       bge-    syscall_error
+syscall_error_cont:
        ld      r7,_NIP(r1)
        stdcx.  r0,0,r1                 /* to clear the reservation */
        andi.   r6,r8,MSR_PR
@@ -193,21 +184,12 @@ syscall_exit_trace_cont:
        rfid
        b       .       /* prevent speculative execution */
 
-syscall_enosys:
-       li      r3,-ENOSYS
-       std     r3,RESULT(r1)
-       clrrdi  r12,r1,THREAD_SHIFT
-       ld      r5,_CCR(r1)
-
-syscall_error:
-       lbz     r11,TI_SC_NOERR(r12)
-       cmpwi   0,r11,0
-       bne-    syscall_error_cont
-       neg     r3,r3
+syscall_error: 
        oris    r5,r5,0x1000    /* Set SO bit in CR */
+       neg     r3,r3
        std     r5,_CCR(r1)
        b       syscall_error_cont
-        
+       
 /* Traced system call support */
 syscall_dotrace:
        bl      .save_nvgprs
@@ -225,21 +207,69 @@ syscall_dotrace:
        ld      r10,TI_FLAGS(r10)
        b       syscall_dotrace_cont
 
-syscall_exit_trace:
-       std     r3,GPR3(r1)
-       bl      .save_nvgprs
+syscall_enosys:
+       li      r3,-ENOSYS
+       b       syscall_exit
+       
+syscall_exit_work:
+       /* If TIF_RESTOREALL is set, don't scribble on either r3 or ccr.
+        If TIF_NOERROR is set, just save r3 as it is. */
+
+       andi.   r0,r9,_TIF_RESTOREALL
+       bne-    2f
+       cmpld   r3,r11          /* r10 is -LAST_ERRNO */
+       blt+    1f
+       andi.   r0,r9,_TIF_NOERROR
+       bne-    1f
+       ld      r5,_CCR(r1)
+       neg     r3,r3
+       oris    r5,r5,0x1000    /* Set SO bit in CR */
+       std     r5,_CCR(r1)
+1:     std     r3,GPR3(r1)
+2:     andi.   r0,r9,(_TIF_PERSYSCALL_MASK)
+       beq     4f
+
+       /* Clear per-syscall TIF flags if any are set, but _leave_
+       _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+       yet.  */
+
+       li      r11,_TIF_PERSYSCALL_MASK
+       addi    r12,r12,TI_FLAGS
+3:     ldarx   r10,0,r12
+       andc    r10,r10,r11
+       stdcx.  r10,0,r12
+       bne-    3b
+       subi    r12,r12,TI_FLAGS
+       
+4:     bl      .save_nvgprs
+       /* Anything else left to do? */
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+       beq     .ret_from_except_lite
+
+       /* Re-enable interrupts */
+       mfmsr   r10
+       ori     r10,r10,MSR_EE
+       mtmsrd  r10,1
+
+       andi.   r0,r9,_TIF_SAVE_NVGPRS
+       bne     save_user_nvgprs
+
+       /* If tracing, re-enable interrupts and do it */
+save_user_nvgprs_cont: 
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+       beq     5f
+       
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .do_syscall_trace_leave
        REST_NVGPRS(r1)
-       ld      r3,GPR3(r1)
-       ld      r5,_CCR(r1)
        clrrdi  r12,r1,THREAD_SHIFT
-       b       syscall_exit_trace_cont
 
-/* Stuff to do on exit from a system call. */
-syscall_exit_work:
-       std     r3,GPR3(r1)
-       std     r5,_CCR(r1)
+       /* Disable interrupts again and handle other work if any */
+5:     mfmsr   r10
+       rldicl  r10,r10,48,1
+       rotldi  r10,r10,16
+       mtmsrd  r10,1
+
        b       .ret_from_except_lite
 
 /* Save non-volatile GPRs, if not already saved. */
@@ -252,6 +282,52 @@ _GLOBAL(save_nvgprs)
        std     r0,_TRAP(r1)
        blr
 
+
+save_user_nvgprs:
+       ld      r10,TI_SIGFRAME(r12)
+       andi.   r0,r9,_TIF_32BIT
+       beq-    save_user_nvgprs_64
+
+       /* 32-bit save to userspace */
+
+.macro savewords start, end
+  1:   stw \start,4*(\start)(r10)
+       .section __ex_table,"a"
+       .align  3
+       .llong  1b,save_user_nvgprs_fault
+       .previous
+       .if \end - \start
+       savewords "(\start+1)",\end
+       .endif
+.endm  
+       savewords 14,31
+       b       save_user_nvgprs_cont
+
+save_user_nvgprs_64:
+       /* 64-bit save to userspace */
+
+.macro savelongs start, end
+  1:   std \start,8*(\start)(r10)
+       .section __ex_table,"a"
+       .align  3
+       .llong  1b,save_user_nvgprs_fault
+       .previous
+       .if \end - \start
+       savelongs "(\start+1)",\end
+       .endif
+.endm  
+       savelongs 14,31
+       b       save_user_nvgprs_cont
+
+save_user_nvgprs_fault:
+       li      r3,11           /* SIGSEGV */
+       ld      r4,TI_TASK(r12)
+       bl      .force_sigsegv
+
+       clrrdi  r12,r1,THREAD_SHIFT
+       ld      r9,TI_FLAGS(r12)
+       b       save_user_nvgprs_cont
+       
 /*
  * The sigsuspend and rt_sigsuspend system calls can call do_signal
  * and thus put the process into the stopped state where we might
@@ -260,35 +336,6 @@ _GLOBAL(save_nvgprs)
  * the C code.  Similarly, fork, vfork and clone need the full
  * register state on the stack so that it can be copied to the child.
  */
-_GLOBAL(ppc32_sigsuspend)
-       bl      .save_nvgprs
-       bl      .compat_sys_sigsuspend
-       b       70f
-
-_GLOBAL(ppc64_rt_sigsuspend)
-       bl      .save_nvgprs
-       bl      .sys_rt_sigsuspend
-       b       70f
-
-_GLOBAL(ppc32_rt_sigsuspend)
-       bl      .save_nvgprs
-       bl      .compat_sys_rt_sigsuspend
-70:    cmpdi   0,r3,0
-       /* If it returned an error, we need to return via syscall_exit to set
-          the SO bit in cr0 and potentially stop for ptrace. */
-       bne     syscall_exit
-       /* If sigsuspend() returns zero, we are going into a signal handler. We
-          may need to call audit_syscall_exit() to mark the exit from sigsuspend() */
-#ifdef CONFIG_AUDITSYSCALL
-       ld      r3,PACACURRENT(r13)
-       ld      r4,AUDITCONTEXT(r3)
-       cmpdi   0,r4,0
-       beq     .ret_from_except        /* No audit_context: Leave immediately. */
-       li      r4, 2                   /* AUDITSC_FAILURE */
-       li      r5,-4                   /* It's always -EINTR */
-       bl      .audit_syscall_exit
-#endif
-       b       .ret_from_except
 
 _GLOBAL(ppc_fork)
        bl      .save_nvgprs
@@ -305,37 +352,6 @@ _GLOBAL(ppc_clone)
        bl      .sys_clone
        b       syscall_exit
 
-_GLOBAL(ppc32_swapcontext)
-       bl      .save_nvgprs
-       bl      .compat_sys_swapcontext
-       b       80f
-       
-_GLOBAL(ppc64_swapcontext)
-       bl      .save_nvgprs
-       bl      .sys_swapcontext
-       b       80f
-
-_GLOBAL(ppc32_sigreturn)
-       bl      .compat_sys_sigreturn
-       b       80f
-
-_GLOBAL(ppc32_rt_sigreturn)
-       bl      .compat_sys_rt_sigreturn
-       b       80f
-
-_GLOBAL(ppc64_rt_sigreturn)
-       bl      .sys_rt_sigreturn
-
-80:    cmpdi   0,r3,0
-       blt     syscall_exit
-       clrrdi  r4,r1,THREAD_SHIFT
-       ld      r4,TI_FLAGS(r4)
-       andi.   r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
-       beq+    81f
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_syscall_trace_leave
-81:    b       .ret_from_except
-
 _GLOBAL(ret_from_fork)
        bl      .schedule_tail
        REST_NVGPRS(r1)
@@ -674,7 +690,7 @@ _GLOBAL(enter_rtas)
 
        /* Setup our real return addr */        
        SET_REG_TO_LABEL(r4,.rtas_return_loc)
-       SET_REG_TO_CONST(r9,KERNELBASE)
+       SET_REG_TO_CONST(r9,PAGE_OFFSET)
        sub     r4,r4,r9
                mtlr    r4
 
@@ -702,7 +718,7 @@ _GLOBAL(enter_rtas)
 _STATIC(rtas_return_loc)
        /* relocation is off at this point */
        mfspr   r4,SPRN_SPRG3           /* Get PACA */
-       SET_REG_TO_CONST(r5, KERNELBASE)
+       SET_REG_TO_CONST(r5, PAGE_OFFSET)
         sub     r4,r4,r5                /* RELOC the PACA base pointer */
 
        mfmsr   r6
index ccdf94731e300c8d5f3160f5dd74d6eb9a7d3471..03b25f9359f86db2ffb001de76db8653fd356ff8 100644 (file)
@@ -120,10 +120,25 @@ __start:
  * because OF may have I/O devices mapped into that area
  * (particularly on CHRP).
  */
+#ifdef CONFIG_PPC_MULTIPLATFORM
        cmpwi   0,r5,0
        beq     1f
        bl      prom_init
        trap
+#endif
+
+/*
+ * Check for BootX signature when supporting PowerMac and branch to
+ * appropriate trampoline if it's present
+ */
+#ifdef CONFIG_PPC_PMAC
+1:     lis     r31,0x426f
+       ori     r31,r31,0x6f58
+       cmpw    0,r3,r31
+       bne     1f
+       bl      bootx_init
+       trap
+#endif /* CONFIG_PPC_PMAC */
 
 1:     mr      r31,r3                  /* save parameters */
        mr      r30,r4
@@ -153,6 +168,9 @@ __after_mmu_off:
        bl      flush_tlbs
 
        bl      initial_bats
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+       bl      setup_disp_bat
+#endif
 
 /*
  * Call setup_cpu for CPU 0 and initialize 6xx Idle
@@ -450,16 +468,11 @@ SystemCall:
  * by executing an altivec instruction.
  */
        . = 0xf00
-       b       Trap_0f
+       b       PerformanceMonitor
 
        . = 0xf20
        b       AltiVecUnavailable
 
-Trap_0f:
-       EXCEPTION_PROLOG
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_EE(0xf00, unknown_exception)
-
 /*
  * Handle TLB miss for instruction on 603/603e.
  * Note: we get an alternate set of r0 - r3 to use automatically.
@@ -703,6 +716,11 @@ AltiVecUnavailable:
 #endif /* CONFIG_ALTIVEC */
        EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)
 
+PerformanceMonitor:
+       EXCEPTION_PROLOG
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_STD(0xf00, performance_monitor_exception)
+
 #ifdef CONFIG_ALTIVEC
 /* Note that the AltiVec support is closely modeled after the FP
  * support.  Changes to one are likely to be applicable to the
@@ -1306,6 +1324,32 @@ initial_bats:
        blr
 
 
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+setup_disp_bat:
+       /*
+        * setup the display bat prepared for us in prom.c
+        */
+       mflr    r8
+       bl      reloc_offset
+       mtlr    r8
+       addis   r8,r3,disp_BAT@ha
+       addi    r8,r8,disp_BAT@l
+       cmpwi   cr0,r8,0
+       beqlr
+       lwz     r11,0(r8)
+       lwz     r8,4(r8)
+       mfspr   r9,SPRN_PVR
+       rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
+       cmpwi   0,r9,1
+       beq     1f
+       mtspr   SPRN_DBAT3L,r8
+       mtspr   SPRN_DBAT3U,r11
+       blr
+1:     mtspr   SPRN_IBAT3L,r8
+       mtspr   SPRN_IBAT3U,r11
+       blr
+#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
+
 #ifdef CONFIG_8260
 /* Jump into the system reset for the rom.
  * We first disable the MMU, and then jump to the ROM reset address.
index 8a8bf79ef0449605fa6ea36152f927d6de854e57..1c066d1253756ae3b9f008e5246bcbe2fa2bf9b3 100644 (file)
@@ -154,11 +154,15 @@ _GLOBAL(__secondary_hold)
        bne     100b
 
 #ifdef CONFIG_HMT
-       b       .hmt_init
+       LOADADDR(r4, .hmt_init)
+       mtctr   r4
+       bctr
 #else
 #ifdef CONFIG_SMP
+       LOADADDR(r4, .pSeries_secondary_smp_init)
+       mtctr   r4
        mr      r3,r24
-       b       .pSeries_secondary_smp_init
+       bctr
 #else
        BUG_OPCODE
 #endif
@@ -200,6 +204,20 @@ exception_marker:
 #define EX_R3          64
 #define EX_LR          72
 
+/*
+ * We're short on space and time in the exception prolog, so we can't use
+ * the normal LOADADDR macro. Normally we just need the low halfword of the
+ * address, but for Kdump we need the whole low word.
+ */
+#ifdef CONFIG_CRASH_DUMP
+#define LOAD_HANDLER(reg, label)                                       \
+       oris    reg,reg,(label)@h;      /* virt addr of handler ... */  \
+       ori     reg,reg,(label)@l;      /* .. and the rest */
+#else
+#define LOAD_HANDLER(reg, label)                                       \
+       ori     reg,reg,(label)@l;      /* virt addr of handler ... */
+#endif
+
 #define EXCEPTION_PROLOG_PSERIES(area, label)                          \
        mfspr   r13,SPRN_SPRG3;         /* get paca address into r13 */ \
        std     r9,area+EX_R9(r13);     /* save r9 - r12 */             \
@@ -212,7 +230,7 @@ exception_marker:
        clrrdi  r12,r13,32;             /* get high part of &label */   \
        mfmsr   r10;                                                    \
        mfspr   r11,SPRN_SRR0;          /* save SRR0 */                 \
-       ori     r12,r12,(label)@l;      /* virt addr of handler */      \
+       LOAD_HANDLER(r12,label)                                         \
        ori     r10,r10,MSR_IR|MSR_DR|MSR_RI;                           \
        mtspr   SPRN_SRR0,r12;                                          \
        mfspr   r12,SPRN_SRR1;          /* and SRR1 */                  \
@@ -553,6 +571,7 @@ slb_miss_user_pseries:
  * Vectors for the FWNMI option.  Share common code.
  */
        .globl system_reset_fwnmi
+      .align 7
 system_reset_fwnmi:
        HMT_MEDIUM
        mtspr   SPRN_SPRG1,r13          /* save r13 */
@@ -560,6 +579,7 @@ system_reset_fwnmi:
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
 
        .globl machine_check_fwnmi
+      .align 7
 machine_check_fwnmi:
        HMT_MEDIUM
        mtspr   SPRN_SPRG1,r13          /* save r13 */
@@ -726,7 +746,8 @@ iSeries_secondary_smp_loop:
 decrementer_iSeries_masked:
        li      r11,1
        stb     r11,PACALPPACA+LPPACADECRINT(r13)
-       lwz     r12,PACADEFAULTDECR(r13)
+       LOADBASE(r12,tb_ticks_per_jiffy)
+       lwz     r12,OFF(tb_ticks_per_jiffy)(r12)
        mtspr   SPRN_DEC,r12
        /* fall through */
 
@@ -1345,7 +1366,7 @@ _GLOBAL(do_stab_bolted)
  * fixed address (the linker can't compute (u64)&initial_stab >>
  * PAGE_SHIFT).
  */
-       . = STAB0_PHYS_ADDR     /* 0x6000 */
+       . = STAB0_OFFSET        /* 0x6000 */
        .globl initial_stab
 initial_stab:
        .space  4096
@@ -1485,11 +1506,13 @@ _STATIC(__mmu_off)
  *
  */
 _GLOBAL(__start_initialization_multiplatform)
+#ifdef CONFIG_PPC_MULTIPLATFORM
        /*
         * Are we booted from a PROM Of-type client-interface ?
         */
        cmpldi  cr0,r5,0
        bne     .__boot_from_prom               /* yes -> prom */
+#endif
 
        /* Save parameters */
        mr      r31,r3
@@ -1510,6 +1533,7 @@ _GLOBAL(__start_initialization_multiplatform)
        bl      .__mmu_off
        b       .__after_prom_start
 
+#ifdef CONFIG_PPC_MULTIPLATFORM
 _STATIC(__boot_from_prom)
        /* Save parameters */
        mr      r31,r3
@@ -1542,6 +1566,7 @@ _STATIC(__boot_from_prom)
        bl      .prom_init
        /* We never return */
        trap
+#endif
 
 /*
  * At this point, r3 contains the physical address we are running at,
@@ -1550,7 +1575,7 @@ _STATIC(__boot_from_prom)
 _STATIC(__after_prom_start)
 
 /*
- * We need to run with __start at physical address 0.
+ * We need to run with __start at physical address PHYSICAL_START.
  * This will leave some code in the first 256B of
  * real memory, which are reserved for software use.
  * The remainder of the first page is loaded with the fixed
@@ -1565,7 +1590,7 @@ _STATIC(__after_prom_start)
        mr      r26,r3
        SET_REG_TO_CONST(r27,KERNELBASE)
 
-       li      r3,0                    /* target addr */
+       LOADADDR(r3, PHYSICAL_START)    /* target addr */
 
        // XXX FIXME: Use phys returned by OF (r30)
        add     r4,r27,r26              /* source addr                   */
@@ -1846,7 +1871,7 @@ _STATIC(start_here_multiplatform)
        mulli   r13,r27,PACA_SIZE       /* Calculate vaddr of right paca */
        add     r13,r13,r24             /* for this processor.           */
        add     r13,r13,r26             /* convert to physical addr      */
-       mtspr   SPRN_SPRG3,r13          /* PPPBBB: Temp... -Peter */
+       mtspr   SPRN_SPRG3,r13
        
        /* Do very early kernel initializations, including initial hash table,
         * stab and slb setup before we turn on relocation.     */
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
new file mode 100644 (file)
index 0000000..e47d40a
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * IBM PowerPC IBM eBus Infrastructure Support.
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *  Heiko J Schick <schickhj@de.ibm.com>
+ *    
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB 
+ * BSD. 
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met: 
+ *
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer. 
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials
+ * provided with the distribution. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/kobject.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <asm/ibmebus.h>
+#include <asm/abs_addr.h>
+
+static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */
+       .name = ibmebus_bus_device.ofdev.dev.bus_id,
+       .ofdev.dev.bus_id = "ibmebus",
+       .ofdev.dev.bus    = &ibmebus_bus_type,
+};
+
+static void *ibmebus_alloc_coherent(struct device *dev,
+                                   size_t size,
+                                   dma_addr_t *dma_handle,
+                                   gfp_t flag)
+{
+       void *mem;
+       
+       mem = kmalloc(size, flag);
+       *dma_handle = (dma_addr_t)mem;
+
+       return mem;
+}
+
+static void ibmebus_free_coherent(struct device *dev,
+                                 size_t size, void *vaddr, 
+                                 dma_addr_t dma_handle)
+{
+       kfree(vaddr);
+}
+
+static dma_addr_t ibmebus_map_single(struct device *dev,
+                                    void *ptr,
+                                    size_t size,
+                                    enum dma_data_direction direction)
+{
+       return (dma_addr_t)(ptr);
+}
+
+static void ibmebus_unmap_single(struct device *dev,
+                                dma_addr_t dma_addr,
+                                size_t size, 
+                                enum dma_data_direction direction)
+{
+       return;
+}
+
+static int ibmebus_map_sg(struct device *dev,
+                         struct scatterlist *sg,
+                         int nents, enum dma_data_direction direction)
+{
+       int i;
+       
+       for (i = 0; i < nents; i++) {
+               sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) 
+                       + sg[i].offset;
+               sg[i].dma_length = sg[i].length;
+       }
+       
+       return nents;
+}
+
+static void ibmebus_unmap_sg(struct device *dev,
+                            struct scatterlist *sg,
+                            int nents, enum dma_data_direction direction)
+{
+       return;
+}
+
+static int ibmebus_dma_supported(struct device *dev, u64 mask)
+{
+       return 1;
+}
+
+struct dma_mapping_ops ibmebus_dma_ops = {
+       .alloc_coherent = ibmebus_alloc_coherent,
+       .free_coherent  = ibmebus_free_coherent,
+       .map_single     = ibmebus_map_single,
+       .unmap_single   = ibmebus_unmap_single,
+       .map_sg         = ibmebus_map_sg,
+       .unmap_sg       = ibmebus_unmap_sg,
+       .dma_supported  = ibmebus_dma_supported,
+};
+
+static int ibmebus_bus_probe(struct device *dev)
+{
+       struct ibmebus_dev *ibmebusdev    = to_ibmebus_dev(dev);
+       struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
+       const struct of_device_id *id;
+       int error = -ENODEV;
+       
+       if (!ibmebusdrv->probe)
+               return error;
+       
+       id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev);
+       if (id) {
+               error = ibmebusdrv->probe(ibmebusdev, id);
+       }
+       
+       return error;
+}
+
+static int ibmebus_bus_remove(struct device *dev)
+{
+       struct ibmebus_dev *ibmebusdev    = to_ibmebus_dev(dev);
+       struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
+       
+       if (ibmebusdrv->remove) {
+               return ibmebusdrv->remove(ibmebusdev);
+       }
+       
+       return 0;
+}
+
+static void __devinit ibmebus_dev_release(struct device *dev)
+{
+       of_node_put(to_ibmebus_dev(dev)->ofdev.node);
+       kfree(to_ibmebus_dev(dev));
+}
+
+static ssize_t ibmebusdev_show_name(struct device *dev, 
+                                   struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
+}
+static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name, 
+                  NULL);
+
+static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+       struct ibmebus_dev *dev, char *name)
+{
+       int err = 0;
+
+       dev->name = name;
+       dev->ofdev.dev.parent  = &ibmebus_bus_device.ofdev.dev;
+       dev->ofdev.dev.bus     = &ibmebus_bus_type;
+       dev->ofdev.dev.release = ibmebus_dev_release;
+
+       /* An ibmebusdev is based on a of_device. We have to change the
+        * bus type to use our own DMA mapping operations. 
+        */       
+       if ((err = of_device_register(&dev->ofdev)) != 0) {
+               printk(KERN_ERR "%s: failed to register device (%d).\n",
+                      __FUNCTION__, err);
+               return NULL;
+       }
+       
+       device_create_file(&dev->ofdev.dev, &dev_attr_name);
+       
+       return dev;
+}
+
+static struct ibmebus_dev* __devinit ibmebus_register_device_node(
+       struct device_node *dn)
+{
+       struct ibmebus_dev *dev;
+       char *loc_code;
+       int length;
+
+       loc_code = (char *)get_property(dn, "ibm,loc-code", NULL);
+       if (!loc_code) {
+                printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
+                      __FUNCTION__, dn->name ? dn->name : "<unknown>");
+               return NULL;
+        }
+       
+       if (strlen(loc_code) == 0) {
+               printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
+                      __FUNCTION__);
+               return NULL;
+       }
+
+       dev = kmalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
+       if (!dev) {
+               return NULL;
+       }
+       memset(dev, 0, sizeof(struct ibmebus_dev));
+
+       dev->ofdev.node = of_node_get(dn);
+       
+       length = strlen(loc_code);
+       memcpy(dev->ofdev.dev.bus_id, loc_code 
+               + (length - min(length, BUS_ID_SIZE - 1)), 
+               min(length, BUS_ID_SIZE - 1));
+
+       /* Register with generic device framework. */
+       if (ibmebus_register_device_common(dev, dn->name) == NULL) {
+               kfree(dev);
+               return NULL;
+       }
+
+       return dev;
+}
+
+static void ibmebus_probe_of_nodes(char* name)
+{
+       struct device_node *dn = NULL;
+       
+       while ((dn = of_find_node_by_name(dn, name))) {
+               if (ibmebus_register_device_node(dn) == NULL) {
+                       of_node_put(dn);
+                       
+                       return;
+               }
+       }
+       
+       of_node_put(dn);
+       
+       return;
+}
+
+static void ibmebus_add_devices_by_id(struct of_device_id *idt)
+{
+       while (strlen(idt->name) > 0) {
+               ibmebus_probe_of_nodes(idt->name);
+               idt++;
+       }
+
+       return;
+}
+
+static int ibmebus_match_helper(struct device *dev, void *data)
+{
+       if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0)
+               return 1;
+       
+       return 0;
+}
+
+static int ibmebus_unregister_device(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_name);
+       of_device_unregister(to_of_device(dev));
+
+       return 0;
+}
+
+static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
+{
+       struct device *dev;
+       
+       while (strlen(idt->name) > 0) {
+               while ((dev = bus_find_device(&ibmebus_bus_type, NULL, 
+                                             (void*)idt->name,
+                                             ibmebus_match_helper))) {
+                       ibmebus_unregister_device(dev);
+               }
+               idt++;
+               
+       }
+       
+       return;
+}
+
+int ibmebus_register_driver(struct ibmebus_driver *drv)
+{
+       int err = 0;
+
+       drv->driver.name   = drv->name;
+       drv->driver.bus    = &ibmebus_bus_type;
+       drv->driver.probe  = ibmebus_bus_probe;
+       drv->driver.remove = ibmebus_bus_remove;
+
+       if ((err = driver_register(&drv->driver) != 0))
+               return err;
+
+       ibmebus_add_devices_by_id(drv->id_table);
+       
+       return 0;
+}
+EXPORT_SYMBOL(ibmebus_register_driver);
+
+void ibmebus_unregister_driver(struct ibmebus_driver *drv)
+{      
+       driver_unregister(&drv->driver);
+       ibmebus_remove_devices_by_id(drv->id_table);
+}
+EXPORT_SYMBOL(ibmebus_unregister_driver);
+
+int ibmebus_request_irq(struct ibmebus_dev *dev,
+                       u32 ist, 
+                       irqreturn_t (*handler)(int, void*, struct pt_regs *),
+                       unsigned long irq_flags, const char * devname,
+                       void *dev_id)
+{
+       unsigned int irq = virt_irq_create_mapping(ist);
+       
+       if (irq == NO_IRQ)
+               return -EINVAL;
+       
+       irq = irq_offset_up(irq);
+       
+       return request_irq(irq, handler,
+                          irq_flags, devname, dev_id);
+}
+EXPORT_SYMBOL(ibmebus_request_irq);
+
+void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
+{
+       unsigned int irq = virt_irq_create_mapping(ist);
+       
+       irq = irq_offset_up(irq);
+       free_irq(irq, dev_id);
+       
+       return;
+}
+EXPORT_SYMBOL(ibmebus_free_irq);
+
+static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
+{      
+       const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+       struct ibmebus_driver *ebus_drv    = to_ibmebus_driver(drv);
+       const struct of_device_id *ids     = ebus_drv->id_table;
+       const struct of_device_id *found_id;
+       
+       if (!ids)
+               return 0;
+       
+       found_id = of_match_device(ids, &ebus_dev->ofdev);
+       if (found_id)
+               return 1;
+       
+       return 0;
+}
+
+struct bus_type ibmebus_bus_type = {
+       .name = "ibmebus",
+       .match = ibmebus_bus_match,
+};
+EXPORT_SYMBOL(ibmebus_bus_type);
+
+static int __init ibmebus_bus_init(void)
+{
+       int err;
+       
+       printk(KERN_INFO "IBM eBus Device Driver\n");
+       
+       err = bus_register(&ibmebus_bus_type);
+       if (err) {
+               printk(KERN_ERR ":%s: failed to register IBM eBus.\n",
+                      __FUNCTION__);
+               return err;
+       }
+       
+       err = device_register(&ibmebus_bus_device.ofdev.dev);
+       if (err) {
+               printk(KERN_WARNING "%s: device_register returned %i\n", 
+                      __FUNCTION__, err);
+               bus_unregister(&ibmebus_bus_type);
+
+               return err;
+       }
+       
+       return 0;
+}
+__initcall(ibmebus_bus_init);
index 5a71ed9612fec6e90ff3f81bad91e2b501e16ecf..5651032d870620d7a72eaeea7dca93ef5790c251 100644 (file)
@@ -31,7 +31,6 @@
  * to reduce code space and undefined function references.
  */
 
-#include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/threads.h>
 #include <linux/kernel_stat.h>
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/proc_fs.h>
-#include <linux/random.h>
 #include <linux/seq_file.h>
 #include <linux/cpumask.h>
 #include <linux/profile.h>
 #include <linux/bitops.h>
-#ifdef CONFIG_PPC64
-#include <linux/kallsyms.h>
-#endif
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -66,8 +59,7 @@
 #include <asm/prom.h>
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
-#ifdef CONFIG_PPC64
-#include <asm/iseries/it_lp_queue.h>
+#ifdef CONFIG_PPC_ISERIES
 #include <asm/paca.h>
 #endif
 
@@ -78,10 +70,6 @@ EXPORT_SYMBOL(__irq_offset_value);
 
 static int ppc_spurious_interrupts;
 
-#if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP)
-extern void iSeries_smp_message_recv(struct pt_regs *);
-#endif
-
 #ifdef CONFIG_PPC32
 #define NR_MASK_WORDS  ((NR_IRQS + 31) / 32)
 
@@ -195,49 +183,6 @@ void fixup_irqs(cpumask_t map)
 }
 #endif
 
-#ifdef CONFIG_PPC_ISERIES
-void do_IRQ(struct pt_regs *regs)
-{
-       struct paca_struct *lpaca;
-
-       irq_enter();
-
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
-       /* Debugging check for stack overflow: is there less than 2KB free? */
-       {
-               long sp;
-
-               sp = __get_SP() & (THREAD_SIZE-1);
-
-               if (unlikely(sp < (sizeof(struct thread_info) + 2048))) {
-                       printk("do_IRQ: stack overflow: %ld\n",
-                               sp - sizeof(struct thread_info));
-                       dump_stack();
-               }
-       }
-#endif
-
-       lpaca = get_paca();
-#ifdef CONFIG_SMP
-       if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
-               lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
-               iSeries_smp_message_recv(regs);
-       }
-#endif /* CONFIG_SMP */
-       if (hvlpevent_is_pending())
-               process_hvlpevents(regs);
-
-       irq_exit();
-
-       if (lpaca->lppaca.int_dword.fields.decr_int) {
-               lpaca->lppaca.int_dword.fields.decr_int = 0;
-               /* Signal a fake decrementer interrupt */
-               timer_interrupt(regs);
-       }
-}
-
-#else  /* CONFIG_PPC_ISERIES */
-
 void do_IRQ(struct pt_regs *regs)
 {
        int irq;
@@ -286,16 +231,24 @@ void do_IRQ(struct pt_regs *regs)
                } else
 #endif
                        __do_IRQ(irq, regs);
-       } else
-#ifdef CONFIG_PPC32
-               if (irq != -2)
-#endif
-                       /* That's not SMP safe ... but who cares ? */
-                       ppc_spurious_interrupts++;
+       } else if (irq != -2)
+               /* That's not SMP safe ... but who cares ? */
+               ppc_spurious_interrupts++;
+
         irq_exit();
-}
 
-#endif /* CONFIG_PPC_ISERIES */
+#ifdef CONFIG_PPC_ISERIES
+       {
+               struct paca_struct *lpaca = get_paca();
+
+               if (lpaca->lppaca.int_dword.fields.decr_int) {
+                       lpaca->lppaca.int_dword.fields.decr_int = 0;
+                       /* Signal a fake decrementer interrupt */
+                       timer_interrupt(regs);
+               }
+       }
+#endif
+}
 
 void __init init_IRQ(void)
 {
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
new file mode 100644 (file)
index 0000000..f970ace
--- /dev/null
@@ -0,0 +1,557 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/prom.h>
+#include <asm/serial.h>
+#include <asm/udbg.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+#define MAX_LEGACY_SERIAL_PORTS        8
+
+static struct plat_serial8250_port
+legacy_serial_ports[MAX_LEGACY_SERIAL_PORTS+1];
+static struct legacy_serial_info {
+       struct device_node              *np;
+       unsigned int                    speed;
+       unsigned int                    clock;
+       phys_addr_t                     taddr;
+} legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];
+static unsigned int legacy_serial_count;
+static int legacy_serial_console = -1;
+
+static int __init add_legacy_port(struct device_node *np, int want_index,
+                                 int iotype, phys_addr_t base,
+                                 phys_addr_t taddr, unsigned long irq,
+                                 unsigned int flags)
+{
+       u32 *clk, *spd, clock = BASE_BAUD * 16;
+       int index;
+
+       /* get clock freq. if present */
+       clk = (u32 *)get_property(np, "clock-frequency", NULL);
+       if (clk && *clk)
+               clock = *clk;
+
+       /* get default speed if present */
+       spd = (u32 *)get_property(np, "current-speed", NULL);
+
+       /* If we have a location index, then try to use it */
+       if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
+               index = want_index;
+       else
+               index = legacy_serial_count;
+
+       /* if our index is still out of range, that mean that
+        * array is full, we could scan for a free slot but that
+        * make little sense to bother, just skip the port
+        */
+       if (index >= MAX_LEGACY_SERIAL_PORTS)
+               return -1;
+       if (index >= legacy_serial_count)
+               legacy_serial_count = index + 1;
+
+       /* Check if there is a port who already claimed our slot */
+       if (legacy_serial_infos[index].np != 0) {
+               /* if we still have some room, move it, else override */
+               if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) {
+                       printk(KERN_INFO "Moved legacy port %d -> %d\n",
+                              index, legacy_serial_count);
+                       legacy_serial_ports[legacy_serial_count] =
+                               legacy_serial_ports[index];
+                       legacy_serial_infos[legacy_serial_count] =
+                               legacy_serial_infos[index];
+                       legacy_serial_count++;
+               } else {
+                       printk(KERN_INFO "Replacing legacy port %d\n", index);
+               }
+       }
+
+       /* Now fill the entry */
+       memset(&legacy_serial_ports[index], 0,
+              sizeof(struct plat_serial8250_port));
+       if (iotype == UPIO_PORT)
+               legacy_serial_ports[index].iobase = base;
+       else
+               legacy_serial_ports[index].mapbase = base;
+       legacy_serial_ports[index].iotype = iotype;
+       legacy_serial_ports[index].uartclk = clock;
+       legacy_serial_ports[index].irq = irq;
+       legacy_serial_ports[index].flags = flags;
+       legacy_serial_infos[index].taddr = taddr;
+       legacy_serial_infos[index].np = of_node_get(np);
+       legacy_serial_infos[index].clock = clock;
+       legacy_serial_infos[index].speed = spd ? *spd : 0;
+
+       printk(KERN_INFO "Found legacy serial port %d for %s\n",
+              index, np->full_name);
+       printk(KERN_INFO "  %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",
+              (iotype == UPIO_PORT) ? "port" : "mem",
+              (unsigned long long)base, (unsigned long long)taddr, irq,
+              legacy_serial_ports[index].uartclk,
+              legacy_serial_infos[index].speed);
+
+       return index;
+}
+
+static int __init add_legacy_soc_port(struct device_node *np,
+                                     struct device_node *soc_dev)
+{
+       phys_addr_t addr;
+       u32 *addrp;
+       unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+
+       /* We only support ports that have a clock frequency properly
+        * encoded in the device-tree.
+        */
+       if (get_property(np, "clock-frequency", NULL) == NULL)
+               return -1;
+
+       /* Get the address */
+       addrp = of_get_address(soc_dev, 0, NULL, NULL);
+       if (addrp == NULL)
+               return -1;
+
+       addr = of_translate_address(soc_dev, addrp);
+
+       /* Add port, irq will be dealt with later. We passed a translated
+        * IO port value. It will be fixed up later along with the irq
+        */
+       return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags);
+}
+
+#ifdef CONFIG_ISA
+static int __init add_legacy_isa_port(struct device_node *np,
+                                     struct device_node *isa_brg)
+{
+       u32 *reg;
+       char *typep;
+       int index = -1;
+       phys_addr_t taddr;
+
+       /* Get the ISA port number */
+       reg = (u32 *)get_property(np, "reg", NULL);
+       if (reg == NULL)
+               return -1;
+
+       /* Verify it's an IO port, we don't support anything else */
+       if (!(reg[0] & 0x00000001))
+               return -1;
+
+       /* Now look for an "ibm,aix-loc" property that gives us ordering
+        * if any...
+        */
+       typep = (char *)get_property(np, "ibm,aix-loc", NULL);
+
+       /* If we have a location index, then use it */
+       if (typep && *typep == 'S')
+               index = simple_strtol(typep+1, NULL, 0) - 1;
+
+       /* Translate ISA address */
+       taddr = of_translate_address(np, reg);
+
+       /* Add port, irq will be dealt with later */
+       return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ, UPF_BOOT_AUTOCONF);
+
+}
+#endif
+
+#ifdef CONFIG_PCI
+static int __init add_legacy_pci_port(struct device_node *np,
+                                     struct device_node *pci_dev)
+{
+       phys_addr_t addr, base;
+       u32 *addrp;
+       unsigned int flags;
+       int iotype, index = -1, lindex = 0;
+
+       /* We only support ports that have a clock frequency properly
+        * encoded in the device-tree (that is have an fcode). Anything
+        * else can't be used that early and will be normally probed by
+        * the generic 8250_pci driver later on. The reason is that 8250
+        * compatible UARTs on PCI need all sort of quirks (port offsets
+        * etc...) that this code doesn't know about
+        */
+       if (get_property(np, "clock-frequency", NULL) == NULL)
+               return -1;
+
+       /* Get the PCI address. Assume BAR 0 */
+       addrp = of_get_pci_address(pci_dev, 0, NULL, &flags);
+       if (addrp == NULL)
+               return -1;
+
+       /* We only support BAR 0 for now */
+       iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT;
+       addr = of_translate_address(pci_dev, addrp);
+
+       /* Set the IO base to the same as the translated address for MMIO,
+        * or to the domain local IO base for PIO (it will be fixed up later)
+        */
+       if (iotype == UPIO_MEM)
+               base = addr;
+       else
+               base = addrp[2];
+
+       /* Try to guess an index... If we have subdevices of the pci dev,
+        * we get to their "reg" property
+        */
+       if (np != pci_dev) {
+               u32 *reg = (u32 *)get_property(np, "reg", NULL);
+               if (reg && (*reg < 4))
+                       index = lindex = *reg;
+       }
+
+       /* Local index means it's the Nth port in the PCI chip. Unfortunately
+        * the offset to add here is device specific. We know about those
+        * EXAR ports and we default to the most common case. If your UART
+        * doesn't work for these settings, you'll have to add your own special
+        * cases here
+        */
+       if (device_is_compatible(pci_dev, "pci13a8,152") ||
+           device_is_compatible(pci_dev, "pci13a8,154") ||
+           device_is_compatible(pci_dev, "pci13a8,158")) {
+               addr += 0x200 * lindex;
+               base += 0x200 * lindex;
+       } else {
+               addr += 8 * lindex;
+               base += 8 * lindex;
+       }
+
+       /* Add port, irq will be dealt with later. We passed a translated
+        * IO port value. It will be fixed up later along with the irq
+        */
+       return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF);
+}
+#endif
+
+/*
+ * This is called very early, as part of setup_system() or eventually
+ * setup_arch(), basically before anything else in this file. This function
+ * will try to build a list of all the available 8250-compatible serial ports
+ * in the machine using the Open Firmware device-tree. It currently only deals
+ * with ISA and PCI busses but could be extended. It allows a very early boot
+ * console to be initialized, that list is also used later to provide 8250 with
+ * the machine non-PCI ports and to properly pick the default console port
+ */
+void __init find_legacy_serial_ports(void)
+{
+       struct device_node *np, *stdout = NULL;
+       char *path;
+       int index;
+
+       DBG(" -> find_legacy_serial_port()\n");
+
+       /* Now find out if one of these is out firmware console */
+       path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+       if (path != NULL) {
+               stdout = of_find_node_by_path(path);
+               if (stdout)
+                       DBG("stdout is %s\n", stdout->full_name);
+       } else {
+               DBG(" no linux,stdout-path !\n");
+       }
+
+       /* First fill our array with SOC ports */
+       for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) {
+               struct device_node *soc = of_get_parent(np);
+               if (soc && !strcmp(soc->type, "soc")) {
+                       index = add_legacy_soc_port(np, np);
+                       if (index >= 0 && np == stdout)
+                               legacy_serial_console = index;
+               }
+               of_node_put(soc);
+       }
+
+#ifdef CONFIG_ISA
+       /* First fill our array with ISA ports */
+       for (np = NULL; (np = of_find_node_by_type(np, "serial"));) {
+               struct device_node *isa = of_get_parent(np);
+               if (isa && !strcmp(isa->name, "isa")) {
+                       index = add_legacy_isa_port(np, isa);
+                       if (index >= 0 && np == stdout)
+                               legacy_serial_console = index;
+               }
+               of_node_put(isa);
+       }
+#endif
+
+#ifdef CONFIG_PCI
+       /* Next, try to locate PCI ports */
+       for (np = NULL; (np = of_find_all_nodes(np));) {
+               struct device_node *pci, *parent = of_get_parent(np);
+               if (parent && !strcmp(parent->name, "isa")) {
+                       of_node_put(parent);
+                       continue;
+               }
+               if (strcmp(np->name, "serial") && strcmp(np->type, "serial")) {
+                       of_node_put(parent);
+                       continue;
+               }
+               /* Check for known pciclass, and also check wether we have
+                * a device with child nodes for ports or not
+                */
+               if (device_is_compatible(np, "pciclass,0700") ||
+                   device_is_compatible(np, "pciclass,070002"))
+                       pci = np;
+               else if (device_is_compatible(parent, "pciclass,0700") ||
+                        device_is_compatible(parent, "pciclass,070002"))
+                       pci = parent;
+               else {
+                       of_node_put(parent);
+                       continue;
+               }
+               index = add_legacy_pci_port(np, pci);
+               if (index >= 0 && np == stdout)
+                       legacy_serial_console = index;
+               of_node_put(parent);
+       }
+#endif
+
+       DBG("legacy_serial_console = %d\n", legacy_serial_console);
+
+       /* udbg is 64 bits only for now, that will change soon though ... */
+       while (legacy_serial_console >= 0) {
+               struct legacy_serial_info *info =
+                       &legacy_serial_infos[legacy_serial_console];
+               void __iomem *addr;
+
+               if (info->taddr == 0)
+                       break;
+               addr = ioremap(info->taddr, 0x1000);
+               if (addr == NULL)
+                       break;
+               if (info->speed == 0)
+                       info->speed = udbg_probe_uart_speed(addr, info->clock);
+               DBG("default console speed = %d\n", info->speed);
+               udbg_init_uart(addr, info->speed, info->clock);
+               break;
+       }
+
+       DBG(" <- find_legacy_serial_port()\n");
+}
+
+static struct platform_device serial_device = {
+       .name   = "serial8250",
+       .id     = PLAT8250_DEV_PLATFORM,
+       .dev    = {
+               .platform_data = legacy_serial_ports,
+       },
+};
+
+static void __init fixup_port_irq(int index,
+                                 struct device_node *np,
+                                 struct plat_serial8250_port *port)
+{
+       DBG("fixup_port_irq(%d)\n", index);
+
+       /* Check for interrupts in that node */
+       if (np->n_intrs > 0) {
+               port->irq = np->intrs[0].line;
+               DBG(" port %d (%s), irq=%d\n",
+                   index, np->full_name, port->irq);
+               return;
+       }
+
+       /* Check for interrupts in the parent */
+       np = of_get_parent(np);
+       if (np == NULL)
+               return;
+
+       if (np->n_intrs > 0) {
+               port->irq = np->intrs[0].line;
+               DBG(" port %d (%s), irq=%d\n",
+                   index, np->full_name, port->irq);
+       }
+       of_node_put(np);
+}
+
+static void __init fixup_port_pio(int index,
+                                 struct device_node *np,
+                                 struct plat_serial8250_port *port)
+{
+#ifdef CONFIG_PCI
+       struct pci_controller *hose;
+
+       DBG("fixup_port_pio(%d)\n", index);
+
+       hose = pci_find_hose_for_OF_device(np);
+       if (hose) {
+               unsigned long offset = (unsigned long)hose->io_base_virt -
+#ifdef CONFIG_PPC64
+                       pci_io_base;
+#else
+                       isa_io_base;
+#endif
+               DBG("port %d, IO %lx -> %lx\n",
+                   index, port->iobase, port->iobase + offset);
+               port->iobase += offset;
+       }
+#endif
+}
+
+static void __init fixup_port_mmio(int index,
+                                  struct device_node *np,
+                                  struct plat_serial8250_port *port)
+{
+       DBG("fixup_port_mmio(%d)\n", index);
+
+       port->membase = ioremap(port->mapbase, 0x100);
+}
+
+/*
+ * This is called as an arch initcall, hopefully before the PCI bus is
+ * probed and/or the 8250 driver loaded since we need to register our
+ * platform devices before 8250 PCI ones are detected as some of them
+ * must properly "override" the platform ones.
+ *
+ * This function fixes up the interrupt value for platform ports as it
+ * couldn't be done earlier before interrupt maps have been parsed. It
+ * also "corrects" the IO address for PIO ports for the same reason,
+ * since earlier, the PHBs virtual IO space wasn't assigned yet. It then
+ * registers all those platform ports for use by the 8250 driver when it
+ * finally loads.
+ */
+static int __init serial_dev_init(void)
+{
+       int i;
+
+       if (legacy_serial_count == 0)
+               return -ENODEV;
+
+       /*
+        * Before we register the platfrom serial devices, we need
+        * to fixup their interrutps and their IO ports.
+        */
+       DBG("Fixing serial ports interrupts and IO ports ...\n");
+
+       for (i = 0; i < legacy_serial_count; i++) {
+               struct plat_serial8250_port *port = &legacy_serial_ports[i];
+               struct device_node *np = legacy_serial_infos[i].np;
+
+               if (port->irq == NO_IRQ)
+                       fixup_port_irq(i, np, port);
+               if (port->iotype == UPIO_PORT)
+                       fixup_port_pio(i, np, port);
+               if (port->iotype == UPIO_MEM)
+                       fixup_port_mmio(i, np, port);
+       }
+
+       DBG("Registering platform serial ports\n");
+
+       return platform_device_register(&serial_device);
+}
+arch_initcall(serial_dev_init);
+
+
+/*
+ * This is called very early, as part of console_init() (typically just after
+ * time_init()). This function is respondible for trying to find a good
+ * default console on serial ports. It tries to match the open firmware
+ * default output with one of the available serial console drivers, either
+ * one of the platform serial ports that have been probed earlier by
+ * find_legacy_serial_ports() or some more platform specific ones.
+ */
+static int __init check_legacy_serial_console(void)
+{
+       struct device_node *prom_stdout = NULL;
+       int speed = 0, offset = 0;
+       char *name;
+       u32 *spd;
+
+       DBG(" -> check_legacy_serial_console()\n");
+
+       /* The user has requested a console so this is already set up. */
+       if (strstr(saved_command_line, "console=")) {
+               DBG(" console was specified !\n");
+               return -EBUSY;
+       }
+
+       if (!of_chosen) {
+               DBG(" of_chosen is NULL !\n");
+               return -ENODEV;
+       }
+
+       if (legacy_serial_console < 0) {
+               DBG(" legacy_serial_console not found !\n");
+               return -ENODEV;
+       }
+       /* We are getting a weird phandle from OF ... */
+       /* ... So use the full path instead */
+       name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+       if (name == NULL) {
+               DBG(" no linux,stdout-path !\n");
+               return -ENODEV;
+       }
+       prom_stdout = of_find_node_by_path(name);
+       if (!prom_stdout) {
+               DBG(" can't find stdout package %s !\n", name);
+               return -ENODEV;
+       }
+       DBG("stdout is %s\n", prom_stdout->full_name);
+
+       name = (char *)get_property(prom_stdout, "name", NULL);
+       if (!name) {
+               DBG(" stdout package has no name !\n");
+               goto not_found;
+       }
+       spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
+       if (spd)
+               speed = *spd;
+
+       if (0)
+               ;
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       else if (strcmp(name, "serial") == 0) {
+               int i;
+               /* Look for it in probed array */
+               for (i = 0; i < legacy_serial_count; i++) {
+                       if (prom_stdout != legacy_serial_infos[i].np)
+                               continue;
+                       offset = i;
+                       speed = legacy_serial_infos[i].speed;
+                       break;
+               }
+               if (i >= legacy_serial_count)
+                       goto not_found;
+       }
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+       else if (strcmp(name, "ch-a") == 0)
+               offset = 0;
+       else if (strcmp(name, "ch-b") == 0)
+               offset = 1;
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+       else
+               goto not_found;
+       of_node_put(prom_stdout);
+
+       DBG("Found serial console at ttyS%d\n", offset);
+
+       if (speed) {
+               static char __initdata opt[16];
+               sprintf(opt, "%d", speed);
+               return add_preferred_console("ttyS", offset, opt);
+       } else
+               return add_preferred_console("ttyS", offset, NULL);
+
+ not_found:
+       DBG("No preferred console found !\n");
+       of_node_put(prom_stdout);
+       return -ENODEV;
+}
+console_initcall(check_legacy_serial_console);
+
index 5a05a797485fea898e35b215501dd1f2e85c1a76..584d1e3c013d24cac3a2eb5d17a7eb66a52d8e85 100644 (file)
@@ -7,7 +7,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <asm/mmu.h>
-#include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/iseries/lpar_map.h>
 
 const struct LparMap __attribute__((__section__(".text"))) xLparMap = {
@@ -16,16 +16,16 @@ const struct LparMap __attribute__((__section__(".text"))) xLparMap = {
        .xSegmentTableOffs = STAB0_PAGE,
 
        .xEsids = {
-               { .xKernelEsid = GET_ESID(KERNELBASE),
-                 .xKernelVsid = KERNEL_VSID(KERNELBASE), },
-               { .xKernelEsid = GET_ESID(VMALLOCBASE),
-                 .xKernelVsid = KERNEL_VSID(VMALLOCBASE), },
+               { .xKernelEsid = GET_ESID(PAGE_OFFSET),
+                 .xKernelVsid = KERNEL_VSID(PAGE_OFFSET), },
+               { .xKernelEsid = GET_ESID(VMALLOC_START),
+                 .xKernelVsid = KERNEL_VSID(VMALLOC_START), },
        },
 
        .xRanges = {
                { .xPages = HvPagesToMap,
                  .xOffset = 0,
-                 .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - HW_PAGE_SHIFT),
+                 .xVPN = KERNEL_VSID(PAGE_OFFSET) << (SID_SHIFT - HW_PAGE_SHIFT),
                },
        },
 };
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
new file mode 100644 (file)
index 0000000..a91e40c
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Code to handle transition of Linux booting another kernel.
+ *
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ * Copyright (C) 2005 IBM Corporation.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/kexec.h>
+#include <linux/reboot.h>
+#include <linux/threads.h>
+#include <asm/machdep.h>
+
+/*
+ * Provide a dummy crash_notes definition until crash dump is implemented.
+ * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
+ */
+note_buf_t crash_notes[NR_CPUS];
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+       if (ppc_md.machine_crash_shutdown)
+               ppc_md.machine_crash_shutdown(regs);
+}
+
+/*
+ * Do what every setup is needed on image and the
+ * reboot code buffer to allow us to avoid allocations
+ * later.
+ */
+int machine_kexec_prepare(struct kimage *image)
+{
+       if (ppc_md.machine_kexec_prepare)
+               return ppc_md.machine_kexec_prepare(image);
+       /*
+        * Fail if platform doesn't provide its own machine_kexec_prepare
+        * implementation.
+        */
+       return -ENOSYS;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+       if (ppc_md.machine_kexec_cleanup)
+               ppc_md.machine_kexec_cleanup(image);
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+       if (ppc_md.machine_kexec)
+               ppc_md.machine_kexec(image);
+       else {
+               /*
+                * Fall back to normal restart if platform doesn't provide
+                * its own kexec function, and user insist to kexec...
+                */
+               machine_restart(NULL);
+       }
+       for(;;);
+}
diff --git a/arch/powerpc/kernel/machine_kexec_32.c b/arch/powerpc/kernel/machine_kexec_32.c
new file mode 100644 (file)
index 0000000..4436061
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * PPC32 code to handle Linux booting another kernel.
+ *
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ * Copyright (C) 2005 IBM Corporation.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/kexec.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <asm/cacheflush.h>
+#include <asm/hw_irq.h>
+#include <asm/io.h>
+
+typedef NORET_TYPE void (*relocate_new_kernel_t)(
+                               unsigned long indirection_page,
+                               unsigned long reboot_code_buffer,
+                               unsigned long start_address) ATTRIB_NORET;
+
+/*
+ * This is a generic machine_kexec function suitable at least for
+ * non-OpenFirmware embedded platforms.
+ * It merely copies the image relocation code to the control page and
+ * jumps to it.
+ * A platform specific function may just call this one.
+ */
+void default_machine_kexec(struct kimage *image)
+{
+       const extern unsigned char relocate_new_kernel[];
+       const extern unsigned int relocate_new_kernel_size;
+       unsigned long page_list;
+       unsigned long reboot_code_buffer, reboot_code_buffer_phys;
+       relocate_new_kernel_t rnk;
+
+       /* Interrupts aren't acceptable while we reboot */
+       local_irq_disable();
+
+       page_list = image->head;
+
+       /* we need both effective and real address here */
+       reboot_code_buffer =
+                       (unsigned long)page_address(image->control_code_page);
+       reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer);
+
+       /* copy our kernel relocation code to the control code page */
+       memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+                                               relocate_new_kernel_size);
+
+       flush_icache_range(reboot_code_buffer,
+                               reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
+       printk(KERN_INFO "Bye!\n");
+
+       /* now call it */
+       rnk = (relocate_new_kernel_t) reboot_code_buffer;
+       (*rnk)(page_list, reboot_code_buffer_phys, image->start);
+}
+
+int default_machine_kexec_prepare(struct kimage *image)
+{
+       return 0;
+}
index 97c51e452be74c16fb8cfca957c8ca5b7bf00f75..d6431440c54fe881415c5d1a8ec15ebefd4c6104 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * machine_kexec.c - handle transition of Linux booting another kernel
+ * PPC64 code to handle Linux booting another kernel.
  *
  * Copyright (C) 2004-2005, IBM Corp.
  *
 
 #define HASH_GROUP_SIZE 0x80   /* size of each hash group, asm/mmu.h */
 
-/* Have this around till we move it into crash specific file */
-note_buf_t crash_notes[NR_CPUS];
-
-/* Dummy for now. Not sure if we need to have a crash shutdown in here
- * and if what it will achieve. Letting it be now to compile the code
- * in generic kexec environment
- */
-void machine_crash_shutdown(struct pt_regs *regs)
-{
-       /* do nothing right now */
-       /* smp_relase_cpus() if we want smp on panic kernel */
-       /* cpu_irq_down to isolate us until we are ready */
-}
-
-int machine_kexec_prepare(struct kimage *image)
+int default_machine_kexec_prepare(struct kimage *image)
 {
        int i;
        unsigned long begin, end;       /* limits of segment */
@@ -111,11 +97,6 @@ int machine_kexec_prepare(struct kimage *image)
        return 0;
 }
 
-void machine_kexec_cleanup(struct kimage *image)
-{
-       /* we do nothing in prepare that needs to be undone */
-}
-
 #define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE)
 
 static void copy_segments(unsigned long ind)
@@ -172,9 +153,8 @@ void kexec_copy_flush(struct kimage *image)
         * including ones that were in place on the original copy
         */
        for (i = 0; i < nr_segments; i++)
-               flush_icache_range(ranges[i].mem + KERNELBASE,
-                               ranges[i].mem + KERNELBASE +
-                               ranges[i].memsz);
+               flush_icache_range((unsigned long)__va(ranges[i].mem),
+                       (unsigned long)__va(ranges[i].mem + ranges[i].memsz));
 }
 
 #ifdef CONFIG_SMP
@@ -283,13 +263,20 @@ extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
                                        void (*clear_all)(void)) ATTRIB_NORET;
 
 /* too late to fail here */
-void machine_kexec(struct kimage *image)
+void default_machine_kexec(struct kimage *image)
 {
-
        /* prepare control code if any */
 
-       /* shutdown other cpus into our wait loop and quiesce interrupts */
-       kexec_prepare_cpus();
+       /*
+        * If the kexec boot is the normal one, need to shutdown other cpus
+        * into our wait loop and quiesce interrupts.
+        * Otherwise, in the case of crashed mode (crashing_cpu >= 0),
+        * stopping other CPUs and collecting their pt_regs is done before
+        * using debugger IPI.
+        */
+
+       if (crashing_cpu == -1)
+               kexec_prepare_cpus();
 
        /* switch to a staticly allocated stack.  Based on irq stack code.
         * XXX: the task struct will likely be invalid once we do the copy!
index 624a983a9676776fc6e7b7a05cd8c50297efee2b..01d0d97a16e1e657363e2410de6a3f9918c31a5a 100644 (file)
@@ -5,6 +5,10 @@
  * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
  * and Paul Mackerras.
  *
+ * kexec bits:
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
  * 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
@@ -24,6 +28,8 @@
 #include <asm/ppc_asm.h>
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
+#include <asm/processor.h>
+#include <asm/kexec.h>
 
        .text
 
@@ -1006,3 +1012,110 @@ _GLOBAL(execve)
  */
 _GLOBAL(__main)
        blr
+
+#ifdef CONFIG_KEXEC
+       /*
+        * Must be relocatable PIC code callable as a C function.
+        */
+       .globl relocate_new_kernel
+relocate_new_kernel:
+       /* r3 = page_list   */
+       /* r4 = reboot_code_buffer */
+       /* r5 = start_address      */
+
+       li      r0, 0
+
+       /*
+        * Set Machine Status Register to a known status,
+        * switch the MMU off and jump to 1: in a single step.
+        */
+
+       mr      r8, r0
+       ori     r8, r8, MSR_RI|MSR_ME
+       mtspr   SPRN_SRR1, r8
+       addi    r8, r4, 1f - relocate_new_kernel
+       mtspr   SPRN_SRR0, r8
+       sync
+       rfi
+
+1:
+       /* from this point address translation is turned off */
+       /* and interrupts are disabled */
+
+       /* set a new stack at the bottom of our page... */
+       /* (not really needed now) */
+       addi    r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
+       stw     r0, 0(r1)
+
+       /* Do the copies */
+       li      r6, 0 /* checksum */
+       mr      r0, r3
+       b       1f
+
+0:     /* top, read another word for the indirection page */
+       lwzu    r0, 4(r3)
+
+1:
+       /* is it a destination page? (r8) */
+       rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
+       beq     2f
+
+       rlwinm  r8, r0, 0, 0, 19 /* clear kexec flags, page align */
+       b       0b
+
+2:     /* is it an indirection page? (r3) */
+       rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
+       beq     2f
+
+       rlwinm  r3, r0, 0, 0, 19 /* clear kexec flags, page align */
+       subi    r3, r3, 4
+       b       0b
+
+2:     /* are we done? */
+       rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
+       beq     2f
+       b       3f
+
+2:     /* is it a source page? (r9) */
+       rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
+       beq     0b
+
+       rlwinm  r9, r0, 0, 0, 19 /* clear kexec flags, page align */
+
+       li      r7, PAGE_SIZE / 4
+       mtctr   r7
+       subi    r9, r9, 4
+       subi    r8, r8, 4
+9:
+       lwzu    r0, 4(r9)  /* do the copy */
+       xor     r6, r6, r0
+       stwu    r0, 4(r8)
+       dcbst   0, r8
+       sync
+       icbi    0, r8
+       bdnz    9b
+
+       addi    r9, r9, 4
+       addi    r8, r8, 4
+       b       0b
+
+3:
+
+       /* To be certain of avoiding problems with self-modifying code
+        * execute a serializing instruction here.
+        */
+       isync
+       sync
+
+       /* jump to the entry point, usually the setup routine */
+       mtlr    r5
+       blrl
+
+1:     b       1b
+
+relocate_new_kernel_end:
+
+       .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+       .long relocate_new_kernel_end - relocate_new_kernel
+#endif
index c0fcd29918cec0b3fea13b26177877807f076e24..fd7db8d542db0a75dd9da1f34d10c525c6723bcc 100644 (file)
@@ -80,80 +80,74 @@ static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
 static ssize_t dev_nvram_read(struct file *file, char __user *buf,
                          size_t count, loff_t *ppos)
 {
-       ssize_t len;
-       char *tmp_buffer;
-       int size;
+       ssize_t ret;
+       char *tmp = NULL;
+       ssize_t size;
 
-       if (ppc_md.nvram_size == NULL)
-               return -ENODEV;
+       ret = -ENODEV;
+       if (!ppc_md.nvram_size)
+               goto out;
+
+       ret = 0;
        size = ppc_md.nvram_size();
+       if (*ppos >= size || size < 0)
+               goto out;
 
-       if (!access_ok(VERIFY_WRITE, buf, count))
-               return -EFAULT;
-       if (*ppos >= size)
-               return 0;
-       if (count > size) 
-               count = size;
+       count = min_t(size_t, count, size - *ppos);
+       count = min(count, PAGE_SIZE);
 
-       tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
-       if (!tmp_buffer) {
-               printk(KERN_ERR "dev_read_nvram: kmalloc failed\n");
-               return -ENOMEM;
-       }
+       ret = -ENOMEM;
+       tmp = kmalloc(count, GFP_KERNEL);
+       if (!tmp)
+               goto out;
 
-       len = ppc_md.nvram_read(tmp_buffer, count, ppos);
-       if ((long)len <= 0) {
-               kfree(tmp_buffer);
-               return len;
-       }
+       ret = ppc_md.nvram_read(tmp, count, ppos);
+       if (ret <= 0)
+               goto out;
 
-       if (copy_to_user(buf, tmp_buffer, len)) {
-               kfree(tmp_buffer);
-               return -EFAULT;
-       }
+       if (copy_to_user(buf, tmp, ret))
+               ret = -EFAULT;
 
-       kfree(tmp_buffer);
-       return len;
+out:
+       kfree(tmp);
+       return ret;
 
 }
 
 static ssize_t dev_nvram_write(struct file *file, const char __user *buf,
-                          size_t count, loff_t *ppos)
+                         size_t count, loff_t *ppos)
 {
-       ssize_t len;
-       char * tmp_buffer;
-       int size;
+       ssize_t ret;
+       char *tmp = NULL;
+       ssize_t size;
 
-       if (ppc_md.nvram_size == NULL)
-               return -ENODEV;
+       ret = -ENODEV;
+       if (!ppc_md.nvram_size)
+               goto out;
+
+       ret = 0;
        size = ppc_md.nvram_size();
+       if (*ppos >= size || size < 0)
+               goto out;
 
-       if (!access_ok(VERIFY_READ, buf, count))
-               return -EFAULT;
-       if (*ppos >= size)
-               return 0;
-       if (count > size)
-               count = size;
+       count = min_t(size_t, count, size - *ppos);
+       count = min(count, PAGE_SIZE);
 
-       tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
-       if (!tmp_buffer) {
-               printk(KERN_ERR "dev_nvram_write: kmalloc failed\n");
-               return -ENOMEM;
-       }
-       
-       if (copy_from_user(tmp_buffer, buf, count)) {
-               kfree(tmp_buffer);
-               return -EFAULT;
-       }
+       ret = -ENOMEM;
+       tmp = kmalloc(count, GFP_KERNEL);
+       if (!tmp)
+               goto out;
 
-       len = ppc_md.nvram_write(tmp_buffer, count, ppos);
-       if ((long)len <= 0) {
-               kfree(tmp_buffer);
-               return len;
-       }
+       ret = -EFAULT;
+       if (copy_from_user(tmp, buf, count))
+               goto out;
+
+       ret = ppc_md.nvram_write(tmp, count, ppos);
+
+out:
+       kfree(tmp);
+       return ret;
 
-       kfree(tmp_buffer);
-       return len;
 }
 
 static int dev_nvram_ioctl(struct inode *inode, struct file *file,
index a7b68f911eb130b0dcadf2fce7840ef9a12aa0bd..999bdd816769ba1f63fbf332f2dc0e224630a410 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/page.h>
 #include <asm/lppaca.h>
 #include <asm/iseries/it_lp_queue.h>
+#include <asm/iseries/it_lp_reg_save.h>
 #include <asm/paca.h>
 
 
@@ -26,8 +27,7 @@ extern unsigned long __toc_start;
 
 /* The Paca is an array with one entry per processor.  Each contains an
  * lppaca, which contains the information shared between the
- * hypervisor and Linux.  Each also contains an ItLpRegSave area which
- * is used by the hypervisor to save registers.
+ * hypervisor and Linux.
  * On systems with hardware multi-threading, there are two threads
  * per processor.  The Paca array must contain an entry for each thread.
  * The VPD Areas will give a max logical processors = 2 * max physical
@@ -37,7 +37,6 @@ extern unsigned long __toc_start;
 #define PACA_INIT_COMMON(number, start, asrr, asrv)                        \
        .lock_token = 0x8000,                                               \
        .paca_index = (number),         /* Paca Index */                    \
-       .default_decr = 0x00ff0000,     /* Initial Decr */                  \
        .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL,             \
        .stab_real = (asrr),            /* Real pointer to segment table */ \
        .stab_addr = (asrv),            /* Virt pointer to segment table */ \
@@ -57,11 +56,7 @@ extern unsigned long __toc_start;
 #ifdef CONFIG_PPC_ISERIES
 #define PACA_INIT_ISERIES(number)                                          \
        .lppaca_ptr = &paca[number].lppaca,                                 \
-       .reg_save_ptr = &paca[number].reg_save,                             \
-       .reg_save = {                                                       \
-               .xDesc = 0xd397d9e2,    /* "LpRS" */                        \
-               .xSize = sizeof(struct ItLpRegSave)                         \
-       }
+       .reg_save_ptr = &iseries_reg_save[number],
 
 #define PACA_INIT(number)                                                  \
 {                                                                          \
index 8b6008ab217d4f1d4b481defbeb3b1b871115aeb..fc60a773af7db3a4652ded23e5f0e9ada5e0cb63 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifdef DEBUG
 #include <asm/udbg.h>
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG(fmt...) printk(fmt)
 #else
 #define DBG(fmt...)
 #endif
@@ -251,7 +251,7 @@ void pcibios_free_controller(struct pci_controller *phb)
                kfree(phb);
 }
 
-static void __init pcibios_claim_one_bus(struct pci_bus *b)
+void __devinit pcibios_claim_one_bus(struct pci_bus *b)
 {
        struct pci_dev *dev;
        struct pci_bus *child_bus;
@@ -323,6 +323,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
        addrs = (u32 *) get_property(node, "assigned-addresses", &proplen);
        if (!addrs)
                return;
+       DBG("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
        for (; proplen >= 20; proplen -= 20, addrs += 5) {
                flags = pci_parse_of_flags(addrs[0]);
                if (!flags)
@@ -332,6 +333,9 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
                if (!size)
                        continue;
                i = addrs[0] & 0xff;
+               DBG("  base: %llx, size: %llx, i: %x\n",
+                   (unsigned long long)base, (unsigned long long)size, i);
+
                if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
                        res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
                } else if (i == dev->rom_base_reg) {
@@ -362,6 +366,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
        if (type == NULL)
                type = "";
 
+       DBG("    create device, devfn: %x, type: %s\n", devfn, type);
+
        memset(dev, 0, sizeof(struct pci_dev));
        dev->bus = bus;
        dev->sysdata = node;
@@ -381,6 +387,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
                dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
        dev->class = get_int_prop(node, "class-code", 0);
 
+       DBG("    class: 0x%x\n", dev->class);
+
        dev->current_state = 4;         /* unknown power state */
 
        if (!strcmp(type, "pci")) {
@@ -402,6 +410,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
 
        pci_parse_of_addrs(node, dev);
 
+       DBG("    adding to system ...\n");
+
        pci_device_add(dev, bus);
 
        /* XXX pci_scan_msi_device(dev); */
@@ -418,15 +428,21 @@ void __devinit of_scan_bus(struct device_node *node,
        int reglen, devfn;
        struct pci_dev *dev;
 
+       DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number);
+
        while ((child = of_get_next_child(node, child)) != NULL) {
+               DBG("  * %s\n", child->full_name);
                reg = (u32 *) get_property(child, "reg", &reglen);
                if (reg == NULL || reglen < 20)
                        continue;
                devfn = (reg[0] >> 8) & 0xff;
+
                /* create a new pci_dev for this device */
                dev = of_create_pci_dev(child, bus, devfn);
                if (!dev)
                        continue;
+               DBG("dev header type: %x\n", dev->hdr_type);
+
                if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
                    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
                        of_scan_pci_bridge(child, dev);
@@ -446,16 +462,18 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
        unsigned int flags;
        u64 size;
 
+       DBG("of_scan_pci_bridge(%s)\n", node->full_name);
+
        /* parse bus-range property */
        busrange = (u32 *) get_property(node, "bus-range", &len);
        if (busrange == NULL || len != 8) {
-               printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n",
+               printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
                       node->full_name);
                return;
        }
        ranges = (u32 *) get_property(node, "ranges", &len);
        if (ranges == NULL) {
-               printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n",
+               printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
                       node->full_name);
                return;
        }
@@ -509,10 +527,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
        }
        sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
                bus->number);
+       DBG("    bus name: %s\n", bus->name);
 
        mode = PCI_PROBE_NORMAL;
        if (ppc_md.pci_probe_mode)
                mode = ppc_md.pci_probe_mode(bus);
+       DBG("    probe mode: %d\n", mode);
+
        if (mode == PCI_PROBE_DEVTREE)
                of_scan_bus(node, bus);
        else if (mode == PCI_PROBE_NORMAL)
@@ -528,6 +549,8 @@ void __devinit scan_phb(struct pci_controller *hose)
        int i, mode;
        struct resource *res;
 
+       DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
+
        bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node);
        if (bus == NULL) {
                printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
@@ -552,8 +575,9 @@ void __devinit scan_phb(struct pci_controller *hose)
 
        mode = PCI_PROBE_NORMAL;
 #ifdef CONFIG_PPC_MULTIPLATFORM
-       if (ppc_md.pci_probe_mode)
+       if (node && ppc_md.pci_probe_mode)
                mode = ppc_md.pci_probe_mode(bus);
+       DBG("    probe mode: %d\n", mode);
        if (mode == PCI_PROBE_DEVTREE) {
                bus->subordinate = hose->last_busno;
                of_scan_bus(node, bus);
@@ -842,8 +866,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
  * Returns a negative error code on failure, zero on success.
  */
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
-                       enum pci_mmap_state mmap_state,
-                       int write_combine)
+                       enum pci_mmap_state mmap_state, int write_combine)
 {
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        struct resource *rp;
@@ -896,6 +919,25 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
                                      unsigned long phb_io_base_phys,
                                      void __iomem * phb_io_base_virt)
 {
+       /* Remove these asap */
+
+       struct pci_address {
+               u32 a_hi;
+               u32 a_mid;
+               u32 a_lo;
+       };
+
+       struct isa_address {
+               u32 a_hi;
+               u32 a_lo;
+       };
+
+       struct isa_range {
+               struct isa_address isa_addr;
+               struct pci_address pci_addr;
+               unsigned int size;
+       };
+
        struct isa_range *range;
        unsigned long pci_addr;
        unsigned int isa_addr;
@@ -1223,6 +1265,7 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,
 }
 EXPORT_SYMBOL(pcibios_fixup_device_resources);
 
+
 static void __devinit do_bus_setup(struct pci_bus *bus)
 {
        struct pci_dev *dev;
@@ -1306,8 +1349,38 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
        *end = rsrc->end + offset;
 }
 
+struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
+{
+       if (!have_of)
+               return NULL;
+       while(node) {
+               struct pci_controller *hose, *tmp;
+               list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+                       if (hose->arch_data == node)
+                               return hose;
+               node = node->parent;
+       }
+       return NULL;
+}
+
 #endif /* CONFIG_PPC_MULTIPLATFORM */
 
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       struct pci_controller *hose, *tmp;
+
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+               if (address >= hose->io_base_phys &&
+                   address < (hose->io_base_phys + hose->pci_io_size)) {
+                       unsigned long base =
+                               (unsigned long)hose->io_base_virt - pci_io_base;
+                       return base + (address - hose->io_base_phys);
+               }
+       }
+       return (unsigned int)-1;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
 
 #define IOBASE_BRIDGE_NUMBER   0
 #define IOBASE_MEMORY          1
index 2d333cc84082a3e483700a7fc4d01e52b726d10d..e6fb194fe537dfb941261641f8d33b1eb92e5c4f 100644 (file)
@@ -43,8 +43,13 @@ static void dummy_perf(struct pt_regs *regs)
        mtspr(SPRN_MMCR0, mmcr0);
 }
 #else
+/* Ensure exceptions are disabled */
 static void dummy_perf(struct pt_regs *regs)
 {
+       unsigned int mmcr0 = mfspr(SPRN_MMCR0);
+
+       mmcr0 &= ~(MMCR0_PMXE);
+       mtspr(SPRN_MMCR0, mmcr0);
 }
 #endif
 
index 94db25708456857995cbe42c1a41a1936442617f..b2758148a0de54461b04d735e8fb347ec1884b55 100644 (file)
@@ -76,11 +76,6 @@ EXPORT_SYMBOL(single_step_exception);
 EXPORT_SYMBOL(sys_sigreturn);
 #endif
 
-#if defined(CONFIG_PPC_PREP)
-EXPORT_SYMBOL(_prep_type);
-EXPORT_SYMBOL(ucSystemType);
-#endif
-
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
index 3bf968e740950bf041d65dff2b01c0795e94a153..977ee3adaf2d23eed404ba0bffc4b926c5d48895 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/initrd.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
+#include <linux/kexec.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -37,6 +38,7 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/kdump.h>
 #include <asm/smp.h>
 #include <asm/system.h>
 #include <asm/mmu.h>
 #define DBG(fmt...)
 #endif
 
-struct pci_reg_property {
-       struct pci_address addr;
-       u32 size_hi;
-       u32 size_lo;
-};
-
-struct isa_reg_property {
-       u32 space;
-       u32 address;
-       u32 size;
-};
-
-
-typedef int interpret_func(struct device_node *, unsigned long *,
-                          int, int, int);
 
 static int __initdata dt_root_addr_cells;
 static int __initdata dt_root_size_cells;
@@ -311,6 +298,16 @@ static int __devinit finish_node_interrupts(struct device_node *np,
        int i, j, n, sense;
        unsigned int *irq, virq;
        struct device_node *ic;
+       int trace = 0;
+
+       //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0)
+#define TRACE(fmt...)
+
+       if (!strcmp(np->name, "smu-doorbell"))
+               trace = 1;
+
+       TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n",
+             num_interrupt_controllers);
 
        if (num_interrupt_controllers == 0) {
                /*
@@ -345,11 +342,12 @@ static int __devinit finish_node_interrupts(struct device_node *np,
        }
 
        ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+       TRACE("ints=%p, intlen=%d\n", ints, intlen);
        if (ints == NULL)
                return 0;
        intrcells = prom_n_intr_cells(np);
        intlen /= intrcells * sizeof(unsigned int);
-
+       TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen);
        np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
        if (!np->intrs)
                return -ENOMEM;
@@ -360,6 +358,7 @@ static int __devinit finish_node_interrupts(struct device_node *np,
        intrcount = 0;
        for (i = 0; i < intlen; ++i, ints += intrcells) {
                n = map_interrupt(&irq, &ic, np, ints, intrcells);
+               TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n);
                if (n <= 0)
                        continue;
 
@@ -370,6 +369,7 @@ static int __devinit finish_node_interrupts(struct device_node *np,
                        np->intrs[intrcount].sense = map_isa_senses[sense];
                } else {
                        virq = virt_irq_create_mapping(irq[0]);
+                       TRACE("virq=%d\n", virq);
 #ifdef CONFIG_PPC64
                        if (virq == NO_IRQ) {
                                printk(KERN_CRIT "Could not allocate interrupt"
@@ -379,6 +379,12 @@ static int __devinit finish_node_interrupts(struct device_node *np,
 #endif
                        np->intrs[intrcount].line = irq_offset_up(virq);
                        sense = (n > 1)? (irq[1] & 3): 1;
+
+                       /* Apple uses bits in there in a different way, let's
+                        * only keep the real sense bit on macs
+                        */
+                       if (_machine == PLATFORM_POWERMAC)
+                               sense &= 0x1;
                        np->intrs[intrcount].sense = map_mpic_senses[sense];
                }
 
@@ -388,12 +394,13 @@ static int __devinit finish_node_interrupts(struct device_node *np,
                        char *name = get_property(ic->parent, "name", NULL);
                        if (name && !strcmp(name, "u3"))
                                np->intrs[intrcount].line += 128;
-                       else if (!(name && !strcmp(name, "mac-io")))
+                       else if (!(name && (!strcmp(name, "mac-io") ||
+                                           !strcmp(name, "u4"))))
                                /* ignore other cascaded controllers, such as
                                   the k2-sata-root */
                                break;
                }
-#endif
+#endif /* CONFIG_PPC64 */
                if (n > 2) {
                        printk("hmmm, got %d intr cells for %s:", n,
                               np->full_name);
@@ -408,234 +415,19 @@ static int __devinit finish_node_interrupts(struct device_node *np,
        return 0;
 }
 
-static int __devinit interpret_pci_props(struct device_node *np,
-                                        unsigned long *mem_start,
-                                        int naddrc, int nsizec,
-                                        int measure_only)
-{
-       struct address_range *adr;
-       struct pci_reg_property *pci_addrs;
-       int i, l, n_addrs;
-
-       pci_addrs = (struct pci_reg_property *)
-               get_property(np, "assigned-addresses", &l);
-       if (!pci_addrs)
-               return 0;
-
-       n_addrs = l / sizeof(*pci_addrs);
-
-       adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
-       if (!adr)
-               return -ENOMEM;
-
-       if (measure_only)
-               return 0;
-
-       np->addrs = adr;
-       np->n_addrs = n_addrs;
-
-       for (i = 0; i < n_addrs; i++) {
-               adr[i].space = pci_addrs[i].addr.a_hi;
-               adr[i].address = pci_addrs[i].addr.a_lo |
-                       ((u64)pci_addrs[i].addr.a_mid << 32);
-               adr[i].size = pci_addrs[i].size_lo;
-       }
-
-       return 0;
-}
-
-static int __init interpret_dbdma_props(struct device_node *np,
-                                       unsigned long *mem_start,
-                                       int naddrc, int nsizec,
-                                       int measure_only)
-{
-       struct reg_property32 *rp;
-       struct address_range *adr;
-       unsigned long base_address;
-       int i, l;
-       struct device_node *db;
-
-       base_address = 0;
-       if (!measure_only) {
-               for (db = np->parent; db != NULL; db = db->parent) {
-                       if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
-                               base_address = db->addrs[0].address;
-                               break;
-                       }
-               }
-       }
-
-       rp = (struct reg_property32 *) get_property(np, "reg", &l);
-       if (rp != 0 && l >= sizeof(struct reg_property32)) {
-               i = 0;
-               adr = (struct address_range *) (*mem_start);
-               while ((l -= sizeof(struct reg_property32)) >= 0) {
-                       if (!measure_only) {
-                               adr[i].space = 2;
-                               adr[i].address = rp[i].address + base_address;
-                               adr[i].size = rp[i].size;
-                       }
-                       ++i;
-               }
-               np->addrs = adr;
-               np->n_addrs = i;
-               (*mem_start) += i * sizeof(struct address_range);
-       }
-
-       return 0;
-}
-
-static int __init interpret_macio_props(struct device_node *np,
-                                       unsigned long *mem_start,
-                                       int naddrc, int nsizec,
-                                       int measure_only)
-{
-       struct reg_property32 *rp;
-       struct address_range *adr;
-       unsigned long base_address;
-       int i, l;
-       struct device_node *db;
-
-       base_address = 0;
-       if (!measure_only) {
-               for (db = np->parent; db != NULL; db = db->parent) {
-                       if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
-                               base_address = db->addrs[0].address;
-                               break;
-                       }
-               }
-       }
-
-       rp = (struct reg_property32 *) get_property(np, "reg", &l);
-       if (rp != 0 && l >= sizeof(struct reg_property32)) {
-               i = 0;
-               adr = (struct address_range *) (*mem_start);
-               while ((l -= sizeof(struct reg_property32)) >= 0) {
-                       if (!measure_only) {
-                               adr[i].space = 2;
-                               adr[i].address = rp[i].address + base_address;
-                               adr[i].size = rp[i].size;
-                       }
-                       ++i;
-               }
-               np->addrs = adr;
-               np->n_addrs = i;
-               (*mem_start) += i * sizeof(struct address_range);
-       }
-
-       return 0;
-}
-
-static int __init interpret_isa_props(struct device_node *np,
-                                     unsigned long *mem_start,
-                                     int naddrc, int nsizec,
-                                     int measure_only)
-{
-       struct isa_reg_property *rp;
-       struct address_range *adr;
-       int i, l;
-
-       rp = (struct isa_reg_property *) get_property(np, "reg", &l);
-       if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
-               i = 0;
-               adr = (struct address_range *) (*mem_start);
-               while ((l -= sizeof(struct isa_reg_property)) >= 0) {
-                       if (!measure_only) {
-                               adr[i].space = rp[i].space;
-                               adr[i].address = rp[i].address;
-                               adr[i].size = rp[i].size;
-                       }
-                       ++i;
-               }
-               np->addrs = adr;
-               np->n_addrs = i;
-               (*mem_start) += i * sizeof(struct address_range);
-       }
-
-       return 0;
-}
-
-static int __init interpret_root_props(struct device_node *np,
-                                      unsigned long *mem_start,
-                                      int naddrc, int nsizec,
-                                      int measure_only)
-{
-       struct address_range *adr;
-       int i, l;
-       unsigned int *rp;
-       int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
-
-       rp = (unsigned int *) get_property(np, "reg", &l);
-       if (rp != 0 && l >= rpsize) {
-               i = 0;
-               adr = (struct address_range *) (*mem_start);
-               while ((l -= rpsize) >= 0) {
-                       if (!measure_only) {
-                               adr[i].space = 0;
-                               adr[i].address = rp[naddrc - 1];
-                               adr[i].size = rp[naddrc + nsizec - 1];
-                       }
-                       ++i;
-                       rp += naddrc + nsizec;
-               }
-               np->addrs = adr;
-               np->n_addrs = i;
-               (*mem_start) += i * sizeof(struct address_range);
-       }
-
-       return 0;
-}
-
 static int __devinit finish_node(struct device_node *np,
                                 unsigned long *mem_start,
-                                interpret_func *ifunc,
-                                int naddrc, int nsizec,
                                 int measure_only)
 {
        struct device_node *child;
-       int *ip, rc = 0;
-
-       /* get the device addresses and interrupts */
-       if (ifunc != NULL)
-               rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
-       if (rc)
-               goto out;
+       int rc = 0;
 
        rc = finish_node_interrupts(np, mem_start, measure_only);
        if (rc)
                goto out;
 
-       /* Look for #address-cells and #size-cells properties. */
-       ip = (int *) get_property(np, "#address-cells", NULL);
-       if (ip != NULL)
-               naddrc = *ip;
-       ip = (int *) get_property(np, "#size-cells", NULL);
-       if (ip != NULL)
-               nsizec = *ip;
-
-       if (!strcmp(np->name, "device-tree") || np->parent == NULL)
-               ifunc = interpret_root_props;
-       else if (np->type == 0)
-               ifunc = NULL;
-       else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
-               ifunc = interpret_pci_props;
-       else if (!strcmp(np->type, "dbdma"))
-               ifunc = interpret_dbdma_props;
-       else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
-               ifunc = interpret_macio_props;
-       else if (!strcmp(np->type, "isa"))
-               ifunc = interpret_isa_props;
-       else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
-               ifunc = interpret_root_props;
-       else if (!((ifunc == interpret_dbdma_props
-                   || ifunc == interpret_macio_props)
-                  && (!strcmp(np->type, "escc")
-                      || !strcmp(np->type, "media-bay"))))
-               ifunc = NULL;
-
        for (child = np->child; child != NULL; child = child->sibling) {
-               rc = finish_node(child, mem_start, ifunc,
-                                naddrc, nsizec, measure_only);
+               rc = finish_node(child, mem_start, measure_only);
                if (rc)
                        goto out;
        }
@@ -697,10 +489,10 @@ void __init finish_device_tree(void)
         * reason and then remove those additional 16 bytes
         */
        size = 16;
-       finish_node(allnodes, &size, NULL, 0, 0, 1);
+       finish_node(allnodes, &size, 1);
        size -= 16;
        end = start = (unsigned long) __va(lmb_alloc(size, 128));
-       finish_node(allnodes, &end, NULL, 0, 0, 0);
+       finish_node(allnodes, &end, 0);
        BUG_ON(end != start + size);
 
        DBG(" <- finish_device_tree\n");
@@ -1197,6 +989,16 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
        }
 #endif /* CONFIG_PPC_RTAS */
 
+#ifdef CONFIG_KEXEC
+       lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL);
+       if (lprop)
+               crashk_res.start = *lprop;
+
+       lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL);
+       if (lprop)
+               crashk_res.end = crashk_res.start + *lprop - 1;
+#endif
+
        /* break now */
        return 1;
 }
@@ -1263,7 +1065,9 @@ static int __init early_init_dt_scan_memory(unsigned long node,
        } else if (strcmp(type, "memory") != 0)
                return 0;
 
-       reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
+       reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l);
+       if (reg == NULL)
+               reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
        if (reg == NULL)
                return 0;
 
@@ -1335,11 +1139,14 @@ void __init early_init_devtree(void *params)
        of_scan_flat_dt(early_init_dt_scan_memory, NULL);
        lmb_enforce_memory_limit(memory_limit);
        lmb_analyze();
-       lmb_reserve(0, __pa(klimit));
 
        DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
 
        /* Reserve LMB regions used by kernel, initrd, dt, etc... */
+       lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
+#ifdef CONFIG_CRASH_DUMP
+       lmb_reserve(0, KDUMP_RESERVE_LIMIT);
+#endif
        early_reserve_mem();
 
        DBG("Scanning CPUs ...\n");
@@ -1802,7 +1609,6 @@ static void of_node_release(struct kref *kref)
                prop = next;
        }
        kfree(node->intrs);
-       kfree(node->addrs);
        kfree(node->full_name);
        kfree(node->data);
        kfree(node);
@@ -1884,9 +1690,7 @@ void of_detach_node(const struct device_node *np)
  * This should probably be split up into smaller chunks.
  */
 
-static int of_finish_dynamic_node(struct device_node *node,
-                                 unsigned long *unused1, int unused2,
-                                 int unused3, int unused4)
+static int of_finish_dynamic_node(struct device_node *node)
 {
        struct device_node *parent = of_get_parent(node);
        int err = 0;
@@ -1907,7 +1711,8 @@ static int of_finish_dynamic_node(struct device_node *node,
                return -ENODEV;
 
        /* fix up new node's linux_phandle field */
-       if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
+       if ((ibm_phandle = (unsigned int *)get_property(node,
+                                                       "ibm,phandle", NULL)))
                node->linux_phandle = *ibm_phandle;
 
 out:
@@ -1922,7 +1727,9 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
 
        switch (action) {
        case PSERIES_RECONFIG_ADD:
-               err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0);
+               err = of_finish_dynamic_node(node);
+               if (!err)
+                       finish_node(node, NULL, 0);
                if (err < 0) {
                        printk(KERN_ERR "finish_node returned %d\n", err);
                        err = NOTIFY_BAD;
@@ -1996,175 +1803,4 @@ int prom_add_property(struct device_node* np, struct property* prop)
        return 0;
 }
 
-/* I quickly hacked that one, check against spec ! */
-static inline unsigned long
-bus_space_to_resource_flags(unsigned int bus_space)
-{
-       u8 space = (bus_space >> 24) & 0xf;
-       if (space == 0)
-               space = 0x02;
-       if (space == 0x02)
-               return IORESOURCE_MEM;
-       else if (space == 0x01)
-               return IORESOURCE_IO;
-       else {
-               printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
-                       bus_space);
-               return 0;
-       }
-}
-
-#ifdef CONFIG_PCI
-static struct resource *find_parent_pci_resource(struct pci_dev* pdev,
-                                                struct address_range *range)
-{
-       unsigned long mask;
-       int i;
-
-       /* Check this one */
-       mask = bus_space_to_resource_flags(range->space);
-       for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
-               if ((pdev->resource[i].flags & mask) == mask &&
-                       pdev->resource[i].start <= range->address &&
-                       pdev->resource[i].end > range->address) {
-                               if ((range->address + range->size - 1) > pdev->resource[i].end) {
-                                       /* Add better message */
-                                       printk(KERN_WARNING "PCI/OF resource overlap !\n");
-                                       return NULL;
-                               }
-                               break;
-                       }
-       }
-       if (i == DEVICE_COUNT_RESOURCE)
-               return NULL;
-       return &pdev->resource[i];
-}
-
-/*
- * Request an OF device resource. Currently handles child of PCI devices,
- * or other nodes attached to the root node. Ultimately, put some
- * link to resources in the OF node.
- */
-struct resource *request_OF_resource(struct device_node* node, int index,
-                                    const char* name_postfix)
-{
-       struct pci_dev* pcidev;
-       u8 pci_bus, pci_devfn;
-       unsigned long iomask;
-       struct device_node* nd;
-       struct resource* parent;
-       struct resource *res = NULL;
-       int nlen, plen;
-
-       if (index >= node->n_addrs)
-               goto fail;
-
-       /* Sanity check on bus space */
-       iomask = bus_space_to_resource_flags(node->addrs[index].space);
-       if (iomask & IORESOURCE_MEM)
-               parent = &iomem_resource;
-       else if (iomask & IORESOURCE_IO)
-               parent = &ioport_resource;
-       else
-               goto fail;
-
-       /* Find a PCI parent if any */
-       nd = node;
-       pcidev = NULL;
-       while (nd) {
-               if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
-                       pcidev = pci_find_slot(pci_bus, pci_devfn);
-               if (pcidev) break;
-               nd = nd->parent;
-       }
-       if (pcidev)
-               parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
-       if (!parent) {
-               printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
-                       node->name);
-               goto fail;
-       }
 
-       res = __request_region(parent, node->addrs[index].address,
-                              node->addrs[index].size, NULL);
-       if (!res)
-               goto fail;
-       nlen = strlen(node->name);
-       plen = name_postfix ? strlen(name_postfix) : 0;
-       res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
-       if (res->name) {
-               strcpy((char *)res->name, node->name);
-               if (plen)
-                       strcpy((char *)res->name+nlen, name_postfix);
-       }
-       return res;
-fail:
-       return NULL;
-}
-EXPORT_SYMBOL(request_OF_resource);
-
-int release_OF_resource(struct device_node *node, int index)
-{
-       struct pci_dev* pcidev;
-       u8 pci_bus, pci_devfn;
-       unsigned long iomask, start, end;
-       struct device_node* nd;
-       struct resource* parent;
-       struct resource *res = NULL;
-
-       if (index >= node->n_addrs)
-               return -EINVAL;
-
-       /* Sanity check on bus space */
-       iomask = bus_space_to_resource_flags(node->addrs[index].space);
-       if (iomask & IORESOURCE_MEM)
-               parent = &iomem_resource;
-       else if (iomask & IORESOURCE_IO)
-               parent = &ioport_resource;
-       else
-               return -EINVAL;
-
-       /* Find a PCI parent if any */
-       nd = node;
-       pcidev = NULL;
-       while(nd) {
-               if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
-                       pcidev = pci_find_slot(pci_bus, pci_devfn);
-               if (pcidev) break;
-               nd = nd->parent;
-       }
-       if (pcidev)
-               parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
-       if (!parent) {
-               printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
-                       node->name);
-               return -ENODEV;
-       }
-
-       /* Find us in the parent and its childs */
-       res = parent->child;
-       start = node->addrs[index].address;
-       end = start + node->addrs[index].size - 1;
-       while (res) {
-               if (res->start == start && res->end == end &&
-                   (res->flags & IORESOURCE_BUSY))
-                       break;
-               if (res->start <= start && res->end >= end)
-                       res = res->child;
-               else
-                       res = res->sibling;
-       }
-       if (!res)
-               return -ENODEV;
-
-       if (res->name) {
-               kfree(res->name);
-               res->name = NULL;
-       }
-       release_resource(res);
-       kfree(res);
-
-       return 0;
-}
-EXPORT_SYMBOL(release_OF_resource);
-#endif /* CONFIG_PCI */
index bcdc209dca8525b5337678a1fdb80ac09f58871f..e381f2fc121c5782d04b20a270503efded1d0b46 100644 (file)
@@ -192,6 +192,11 @@ static unsigned long __initdata alloc_bottom;
 static unsigned long __initdata rmo_top;
 static unsigned long __initdata ram_top;
 
+#ifdef CONFIG_KEXEC
+static unsigned long __initdata prom_crashk_base;
+static unsigned long __initdata prom_crashk_size;
+#endif
+
 static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
 static int __initdata mem_reserve_cnt;
 
@@ -553,7 +558,8 @@ unsigned long prom_memparse(const char *ptr, const char **retptr)
 static void __init early_cmdline_parse(void)
 {
        struct prom_t *_prom = &RELOC(prom);
-       char *opt, *p;
+       const char *opt;
+       char *p;
        int l = 0;
 
        RELOC(prom_cmd_line[0]) = 0;
@@ -590,6 +596,34 @@ static void __init early_cmdline_parse(void)
                RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
 #endif
        }
+
+#ifdef CONFIG_KEXEC
+       /*
+        * crashkernel=size@addr specifies the location to reserve for
+        * crash kernel.
+        */
+       opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel="));
+       if (opt) {
+               opt += 12;
+               RELOC(prom_crashk_size) = prom_memparse(opt, &opt);
+
+               if (ALIGN(RELOC(prom_crashk_size), 0x1000000) !=
+                       RELOC(prom_crashk_size)) {
+                       prom_printf("Warning: crashkernel size is not "
+                                       "aligned to 16MB\n");
+               }
+
+               /*
+                * At present, the crash kernel always run at 32MB.
+                * Just ignore whatever user passed.
+                */
+               RELOC(prom_crashk_base) = 0x2000000;
+               if (*opt == '@') {
+                       prom_printf("Warning: PPC64 kdump kernel always runs "
+                                       "at 32 MB\n");
+               }
+       }
+#endif
 }
 
 #ifdef CONFIG_PPC_PSERIES
@@ -1011,6 +1045,12 @@ static void __init prom_init_mem(void)
        prom_printf("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
        prom_printf("  rmo_top      : %x\n", RELOC(rmo_top));
        prom_printf("  ram_top      : %x\n", RELOC(ram_top));
+#ifdef CONFIG_KEXEC
+       if (RELOC(prom_crashk_base)) {
+               prom_printf("  crashk_base  : %x\n",  RELOC(prom_crashk_base));
+               prom_printf("  crashk_size  : %x\n", RELOC(prom_crashk_size));
+       }
+#endif
 }
 
 
@@ -1500,6 +1540,8 @@ static int __init prom_find_machine_type(void)
 #ifdef CONFIG_PPC64
                        if (strstr(p, RELOC("Momentum,Maple")))
                                return PLATFORM_MAPLE;
+                       if (strstr(p, RELOC("IBM,CPB")))
+                               return PLATFORM_CELL;
 #endif
                        i += sl + 1;
                }
@@ -1994,7 +2036,7 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
        if (r3 && r4 && r4 != 0xdeadbeef) {
                unsigned long val;
 
-               RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3;
+               RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3;
                RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
 
                val = RELOC(prom_initrd_start);
@@ -2094,6 +2136,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         */
        prom_init_mem();
 
+#ifdef CONFIG_KEXEC
+       if (RELOC(prom_crashk_base))
+               reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size));
+#endif
        /*
         * Determine which cpu is actually running right _now_
         */
@@ -2150,6 +2196,16 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        }
 #endif
 
+#ifdef CONFIG_KEXEC
+       if (RELOC(prom_crashk_base)) {
+               prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base",
+                       PTRRELOC(&prom_crashk_base),
+                       sizeof(RELOC(prom_crashk_base)));
+               prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size",
+                       PTRRELOC(&prom_crashk_size),
+                       sizeof(RELOC(prom_crashk_size)));
+       }
+#endif
        /*
         * Fixup any known bugs in the device-tree
         */
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
new file mode 100644 (file)
index 0000000..309ae1d
--- /dev/null
@@ -0,0 +1,547 @@
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/pci_regs.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+#ifdef CONFIG_PPC64
+#define PRu64  "%lx"
+#else
+#define PRu64  "%llx"
+#endif
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS      4
+#define OF_CHECK_COUNTS(na, ns)        ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
+                       (ns) > 0)
+
+/* Debug utility */
+#ifdef DEBUG
+static void of_dump_addr(const char *s, u32 *addr, int na)
+{
+       printk("%s", s);
+       while(na--)
+               printk(" %08x", *(addr++));
+       printk("\n");
+}
+#else
+static void of_dump_addr(const char *s, u32 *addr, int na) { }
+#endif
+
+/* Read a big address */
+static inline u64 of_read_addr(u32 *cell, int size)
+{
+       u64 r = 0;
+       while (size--)
+               r = (r << 32) | *(cell++);
+       return r;
+}
+
+/* Callbacks for bus specific translators */
+struct of_bus {
+       const char      *name;
+       const char      *addresses;
+       int             (*match)(struct device_node *parent);
+       void            (*count_cells)(struct device_node *child,
+                                      int *addrc, int *sizec);
+       u64             (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
+       int             (*translate)(u32 *addr, u64 offset, int na);
+       unsigned int    (*get_flags)(u32 *addr);
+};
+
+
+/*
+ * Default translator (generic bus)
+ */
+
+static void of_bus_default_count_cells(struct device_node *dev,
+                                      int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = prom_n_addr_cells(dev);
+       if (sizec)
+               *sizec = prom_n_size_cells(dev);
+}
+
+static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+       u64 cp, s, da;
+
+       cp = of_read_addr(range, na);
+       s  = of_read_addr(range + na + pna, ns);
+       da = of_read_addr(addr, na);
+
+       DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
+           cp, s, da);
+
+       if (da < cp || da >= (cp + s))
+               return OF_BAD_ADDR;
+       return da - cp;
+}
+
+static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+       u64 a = of_read_addr(addr, na);
+       memset(addr, 0, na * 4);
+       a += offset;
+       if (na > 1)
+               addr[na - 2] = a >> 32;
+       addr[na - 1] = a & 0xffffffffu;
+
+       return 0;
+}
+
+static unsigned int of_bus_default_get_flags(u32 *addr)
+{
+       return IORESOURCE_MEM;
+}
+
+
+/*
+ * PCI bus specific translator
+ */
+
+static int of_bus_pci_match(struct device_node *np)
+{
+       return !strcmp(np->type, "pci");
+}
+
+static void of_bus_pci_count_cells(struct device_node *np,
+                                  int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = 3;
+       if (sizec)
+               *sizec = 2;
+}
+
+static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+       u64 cp, s, da;
+
+       /* Check address type match */
+       if ((addr[0] ^ range[0]) & 0x03000000)
+               return OF_BAD_ADDR;
+
+       /* Read address values, skipping high cell */
+       cp = of_read_addr(range + 1, na - 1);
+       s  = of_read_addr(range + na + pna, ns);
+       da = of_read_addr(addr + 1, na - 1);
+
+       DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
+
+       if (da < cp || da >= (cp + s))
+               return OF_BAD_ADDR;
+       return da - cp;
+}
+
+static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+       return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_pci_get_flags(u32 *addr)
+{
+       unsigned int flags = 0;
+       u32 w = addr[0];
+
+       switch((w >> 24) & 0x03) {
+       case 0x01:
+               flags |= IORESOURCE_IO;
+       case 0x02: /* 32 bits */
+       case 0x03: /* 64 bits */
+               flags |= IORESOURCE_MEM;
+       }
+       if (w & 0x40000000)
+               flags |= IORESOURCE_PREFETCH;
+       return flags;
+}
+
+/*
+ * ISA bus specific translator
+ */
+
+static int of_bus_isa_match(struct device_node *np)
+{
+       return !strcmp(np->name, "isa");
+}
+
+static void of_bus_isa_count_cells(struct device_node *child,
+                                  int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = 2;
+       if (sizec)
+               *sizec = 1;
+}
+
+static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+       u64 cp, s, da;
+
+       /* Check address type match */
+       if ((addr[0] ^ range[0]) & 0x00000001)
+               return OF_BAD_ADDR;
+
+       /* Read address values, skipping high cell */
+       cp = of_read_addr(range + 1, na - 1);
+       s  = of_read_addr(range + na + pna, ns);
+       da = of_read_addr(addr + 1, na - 1);
+
+       DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
+
+       if (da < cp || da >= (cp + s))
+               return OF_BAD_ADDR;
+       return da - cp;
+}
+
+static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
+{
+       return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_isa_get_flags(u32 *addr)
+{
+       unsigned int flags = 0;
+       u32 w = addr[0];
+
+       if (w & 1)
+               flags |= IORESOURCE_IO;
+       else
+               flags |= IORESOURCE_MEM;
+       return flags;
+}
+
+
+/*
+ * Array of bus specific translators
+ */
+
+static struct of_bus of_busses[] = {
+       /* PCI */
+       {
+               .name = "pci",
+               .addresses = "assigned-addresses",
+               .match = of_bus_pci_match,
+               .count_cells = of_bus_pci_count_cells,
+               .map = of_bus_pci_map,
+               .translate = of_bus_pci_translate,
+               .get_flags = of_bus_pci_get_flags,
+       },
+       /* ISA */
+       {
+               .name = "isa",
+               .addresses = "reg",
+               .match = of_bus_isa_match,
+               .count_cells = of_bus_isa_count_cells,
+               .map = of_bus_isa_map,
+               .translate = of_bus_isa_translate,
+               .get_flags = of_bus_isa_get_flags,
+       },
+       /* Default */
+       {
+               .name = "default",
+               .addresses = "reg",
+               .match = NULL,
+               .count_cells = of_bus_default_count_cells,
+               .map = of_bus_default_map,
+               .translate = of_bus_default_translate,
+               .get_flags = of_bus_default_get_flags,
+       },
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
+               if (!of_busses[i].match || of_busses[i].match(np))
+                       return &of_busses[i];
+       BUG();
+       return NULL;
+}
+
+static int of_translate_one(struct device_node *parent, struct of_bus *bus,
+                           struct of_bus *pbus, u32 *addr,
+                           int na, int ns, int pna)
+{
+       u32 *ranges;
+       unsigned int rlen;
+       int rone;
+       u64 offset = OF_BAD_ADDR;
+
+       /* Normally, an absence of a "ranges" property means we are
+        * crossing a non-translatable boundary, and thus the addresses
+        * below the current not cannot be converted to CPU physical ones.
+        * Unfortunately, while this is very clear in the spec, it's not
+        * what Apple understood, and they do have things like /uni-n or
+        * /ht nodes with no "ranges" property and a lot of perfectly
+        * useable mapped devices below them. Thus we treat the absence of
+        * "ranges" as equivalent to an empty "ranges" property which means
+        * a 1:1 translation at that level. It's up to the caller not to try
+        * to translate addresses that aren't supposed to be translated in
+        * the first place. --BenH.
+        */
+       ranges = (u32 *)get_property(parent, "ranges", &rlen);
+       if (ranges == NULL || rlen == 0) {
+               offset = of_read_addr(addr, na);
+               memset(addr, 0, pna * 4);
+               DBG("OF: no ranges, 1:1 translation\n");
+               goto finish;
+       }
+
+       DBG("OF: walking ranges...\n");
+
+       /* Now walk through the ranges */
+       rlen /= 4;
+       rone = na + pna + ns;
+       for (; rlen >= rone; rlen -= rone, ranges += rone) {
+               offset = bus->map(addr, ranges, na, ns, pna);
+               if (offset != OF_BAD_ADDR)
+                       break;
+       }
+       if (offset == OF_BAD_ADDR) {
+               DBG("OF: not found !\n");
+               return 1;
+       }
+       memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+       of_dump_addr("OF: parent translation for:", addr, pna);
+       DBG("OF: with offset: "PRu64"\n", offset);
+
+       /* Translate it into parent bus space */
+       return pbus->translate(addr, offset, pna);
+}
+
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+u64 of_translate_address(struct device_node *dev, u32 *in_addr)
+{
+       struct device_node *parent = NULL;
+       struct of_bus *bus, *pbus;
+       u32 addr[OF_MAX_ADDR_CELLS];
+       int na, ns, pna, pns;
+       u64 result = OF_BAD_ADDR;
+
+       DBG("OF: ** translation for device %s **\n", dev->full_name);
+
+       /* Increase refcount at current level */
+       of_node_get(dev);
+
+       /* Get parent & match bus type */
+       parent = of_get_parent(dev);
+       if (parent == NULL)
+               goto bail;
+       bus = of_match_bus(parent);
+
+       /* Cound address cells & copy address locally */
+       bus->count_cells(dev, &na, &ns);
+       if (!OF_CHECK_COUNTS(na, ns)) {
+               printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+                      dev->full_name);
+               goto bail;
+       }
+       memcpy(addr, in_addr, na * 4);
+
+       DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
+           bus->name, na, ns, parent->full_name);
+       of_dump_addr("OF: translating address:", addr, na);
+
+       /* Translate */
+       for (;;) {
+               /* Switch to parent bus */
+               of_node_put(dev);
+               dev = parent;
+               parent = of_get_parent(dev);
+
+               /* If root, we have finished */
+               if (parent == NULL) {
+                       DBG("OF: reached root node\n");
+                       result = of_read_addr(addr, na);
+                       break;
+               }
+
+               /* Get new parent bus and counts */
+               pbus = of_match_bus(parent);
+               pbus->count_cells(dev, &pna, &pns);
+               if (!OF_CHECK_COUNTS(pna, pns)) {
+                       printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+                              dev->full_name);
+                       break;
+               }
+
+               DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
+                   pbus->name, pna, pns, parent->full_name);
+
+               /* Apply bus translation */
+               if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
+                       break;
+
+               /* Complete the move up one level */
+               na = pna;
+               ns = pns;
+               bus = pbus;
+
+               of_dump_addr("OF: one level translation:", addr, na);
+       }
+ bail:
+       of_node_put(parent);
+       of_node_put(dev);
+
+       return result;
+}
+EXPORT_SYMBOL(of_translate_address);
+
+u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+                   unsigned int *flags)
+{
+       u32 *prop;
+       unsigned int psize;
+       struct device_node *parent;
+       struct of_bus *bus;
+       int onesize, i, na, ns;
+
+       /* Get parent & match bus type */
+       parent = of_get_parent(dev);
+       if (parent == NULL)
+               return NULL;
+       bus = of_match_bus(parent);
+       bus->count_cells(dev, &na, &ns);
+       of_node_put(parent);
+       if (!OF_CHECK_COUNTS(na, ns))
+               return NULL;
+
+       /* Get "reg" or "assigned-addresses" property */
+       prop = (u32 *)get_property(dev, bus->addresses, &psize);
+       if (prop == NULL)
+               return NULL;
+       psize /= 4;
+
+       onesize = na + ns;
+       for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+               if (i == index) {
+                       if (size)
+                               *size = of_read_addr(prop + na, ns);
+                       if (flags)
+                               *flags = bus->get_flags(prop);
+                       return prop;
+               }
+       return NULL;
+}
+EXPORT_SYMBOL(of_get_address);
+
+u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+                       unsigned int *flags)
+{
+       u32 *prop;
+       unsigned int psize;
+       struct device_node *parent;
+       struct of_bus *bus;
+       int onesize, i, na, ns;
+
+       /* Get parent & match bus type */
+       parent = of_get_parent(dev);
+       if (parent == NULL)
+               return NULL;
+       bus = of_match_bus(parent);
+       if (strcmp(bus->name, "pci"))
+               return NULL;
+       bus->count_cells(dev, &na, &ns);
+       of_node_put(parent);
+       if (!OF_CHECK_COUNTS(na, ns))
+               return NULL;
+
+       /* Get "reg" or "assigned-addresses" property */
+       prop = (u32 *)get_property(dev, bus->addresses, &psize);
+       if (prop == NULL)
+               return NULL;
+       psize /= 4;
+
+       onesize = na + ns;
+       for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+               if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
+                       if (size)
+                               *size = of_read_addr(prop + na, ns);
+                       if (flags)
+                               *flags = bus->get_flags(prop);
+                       return prop;
+               }
+       return NULL;
+}
+EXPORT_SYMBOL(of_get_pci_address);
+
+static int __of_address_to_resource(struct device_node *dev, u32 *addrp,
+                                   u64 size, unsigned int flags,
+                                   struct resource *r)
+{
+       u64 taddr;
+
+       if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
+               return -EINVAL;
+       taddr = of_translate_address(dev, addrp);
+       if (taddr == OF_BAD_ADDR)
+               return -EINVAL;
+       memset(r, 0, sizeof(struct resource));
+       if (flags & IORESOURCE_IO) {
+               unsigned long port;
+               port = pci_address_to_pio(taddr);
+               if (port == (unsigned long)-1)
+                       return -EINVAL;
+               r->start = port;
+               r->end = port + size - 1;
+       } else {
+               r->start = taddr;
+               r->end = taddr + size - 1;
+       }
+       r->flags = flags;
+       r->name = dev->name;
+       return 0;
+}
+
+int of_address_to_resource(struct device_node *dev, int index,
+                          struct resource *r)
+{
+       u32             *addrp;
+       u64             size;
+       unsigned int    flags;
+
+       addrp = of_get_address(dev, index, &size, &flags);
+       if (addrp == NULL)
+               return -EINVAL;
+       return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_address_to_resource);
+
+int of_pci_address_to_resource(struct device_node *dev, int bar,
+                              struct resource *r)
+{
+       u32             *addrp;
+       u64             size;
+       unsigned int    flags;
+
+       addrp = of_get_pci_address(dev, bar, &size, &flags);
+       if (addrp == NULL)
+               return -EINVAL;
+       return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
index 61762640b8775ea1d1bfb7acb9f22c5b865708b5..826ee3d056de09c8618b8671e8684a5e1b1c3edd 100644 (file)
@@ -45,33 +45,19 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                       unsigned long data)
 {
        struct task_struct *child;
-       int ret = -EPERM;
+       int ret;
 
        lock_kernel();
        if (request == PTRACE_TRACEME) {
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
-                       goto out;
-               ret = security_ptrace(current->parent, current);
-               if (ret)
-                       goto out;
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
-               ret = 0;
+               ret = ptrace_traceme();
                goto out;
        }
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
-               goto out;
 
-       ret = -EPERM;
-       if (pid == 1)           /* you may not mess with init */
-               goto out_tsk;
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
+               goto out;
+       }
 
        if (request == PTRACE_ATTACH) {
                ret = ptrace_attach(child);
index 60dec2401c26dc7225c0a3b7bfefefdca3f42e46..45b8109951fe49d74aa11e986428ee05e5d60f85 100644 (file)
@@ -188,39 +188,19 @@ int is_python(struct device_node *dev)
        return 0;
 }
 
-static int get_phb_reg_prop(struct device_node *dev,
-                           unsigned int addr_size_words,
-                           struct reg_property64 *reg)
+static void python_countermeasures(struct device_node *dev)
 {
-       unsigned int *ui_ptr = NULL, len;
-
-       /* Found a PHB, now figure out where his registers are mapped. */
-       ui_ptr = (unsigned int *)get_property(dev, "reg", &len);
-       if (ui_ptr == NULL)
-               return 1;
-
-       if (addr_size_words == 1) {
-               reg->address = ((struct reg_property32 *)ui_ptr)->address;
-               reg->size    = ((struct reg_property32 *)ui_ptr)->size;
-       } else {
-               *reg = *((struct reg_property64 *)ui_ptr);
-       }
-
-       return 0;
-}
-
-static void python_countermeasures(struct device_node *dev,
-                                  unsigned int addr_size_words)
-{
-       struct reg_property64 reg_struct;
+       struct resource registers;
        void __iomem *chip_regs;
        volatile u32 val;
 
-       if (get_phb_reg_prop(dev, addr_size_words, &reg_struct))
+       if (of_address_to_resource(dev, 0, &registers)) {
+               printk(KERN_ERR "Can't get address for Python workarounds !\n");
                return;
+       }
 
        /* Python's register file is 1 MB in size. */
-       chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000);
+       chip_regs = ioremap(registers.start & ~(0xfffffUL), 0x100000);
 
        /*
         * Firmware doesn't always clear this bit which is critical
@@ -301,11 +281,10 @@ static int phb_set_bus_ranges(struct device_node *dev,
 }
 
 static int __devinit setup_phb(struct device_node *dev,
-                              struct pci_controller *phb,
-                              unsigned int addr_size_words)
+                              struct pci_controller *phb)
 {
        if (is_python(dev))
-               python_countermeasures(dev, addr_size_words);
+               python_countermeasures(dev);
 
        if (phb_set_bus_ranges(dev, phb))
                return 1;
@@ -320,8 +299,8 @@ unsigned long __init find_and_init_phbs(void)
 {
        struct device_node *node;
        struct pci_controller *phb;
-       unsigned int root_size_cells = 0;
        unsigned int index;
+       unsigned int root_size_cells = 0;
        unsigned int *opprop = NULL;
        struct device_node *root = of_find_node_by_path("/");
 
@@ -343,10 +322,11 @@ unsigned long __init find_and_init_phbs(void)
                phb = pcibios_alloc_controller(node);
                if (!phb)
                        continue;
-               setup_phb(node, phb, root_size_cells);
+               setup_phb(node, phb);
                pci_process_bridge_OF_ranges(phb, node, 0);
                pci_setup_phb_io(phb, index == 0);
 #ifdef CONFIG_PPC_PSERIES
+               /* XXX This code need serious fixing ... --BenH */
                if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) {
                        int addr = root_size_cells * (index + 2) - 1;
                        mpic_assign_isu(pSeries_mpic, index, opprop[addr]);
@@ -381,22 +361,17 @@ unsigned long __init find_and_init_phbs(void)
 
 struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
 {
-       struct device_node *root = of_find_node_by_path("/");
-       unsigned int root_size_cells = 0;
        struct pci_controller *phb;
        int primary;
 
-       root_size_cells = prom_n_size_cells(root);
-
        primary = list_empty(&hose_list);
        phb = pcibios_alloc_controller(dn);
        if (!phb)
                return NULL;
-       setup_phb(dn, phb, root_size_cells);
+       setup_phb(dn, phb);
        pci_process_bridge_OF_ranges(phb, dn, primary);
 
        pci_setup_phb_io_dynamic(phb, primary);
-       of_node_put(root);
 
        pci_devs_phb_init_dynamic(phb);
        scan_phb(phb);
index bd3eb4292b53e6ea06096be111989bbe7718a10f..d5c52fae023a1b996f71f5e38a1ed0d5964c9d3e 100644 (file)
@@ -93,8 +93,8 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs);
 /* also used by kexec */
 void machine_shutdown(void)
 {
-       if (ppc_md.nvram_sync)
-               ppc_md.nvram_sync();
+       if (ppc_md.machine_shutdown)
+               ppc_md.machine_shutdown();
 }
 
 void machine_restart(char *cmd)
@@ -294,129 +294,6 @@ struct seq_operations cpuinfo_op = {
        .show = show_cpuinfo,
 };
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
-static int __init set_preferred_console(void)
-{
-       struct device_node *prom_stdout = NULL;
-       char *name;
-       u32 *spd;
-       int offset = 0;
-
-       DBG(" -> set_preferred_console()\n");
-
-       /* The user has requested a console so this is already set up. */
-       if (strstr(saved_command_line, "console=")) {
-               DBG(" console was specified !\n");
-               return -EBUSY;
-       }
-
-       if (!of_chosen) {
-               DBG(" of_chosen is NULL !\n");
-               return -ENODEV;
-       }
-       /* We are getting a weird phandle from OF ... */
-       /* ... So use the full path instead */
-       name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
-       if (name == NULL) {
-               DBG(" no linux,stdout-path !\n");
-               return -ENODEV;
-       }
-       prom_stdout = of_find_node_by_path(name);
-       if (!prom_stdout) {
-               DBG(" can't find stdout package %s !\n", name);
-               return -ENODEV;
-       }       
-       DBG("stdout is %s\n", prom_stdout->full_name);
-
-       name = (char *)get_property(prom_stdout, "name", NULL);
-       if (!name) {
-               DBG(" stdout package has no name !\n");
-               goto not_found;
-       }
-       spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
-
-       if (0)
-               ;
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-       else if (strcmp(name, "serial") == 0) {
-               int i;
-               u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
-               if (i > 8) {
-                       switch (reg[1]) {
-                               case 0x3f8:
-                                       offset = 0;
-                                       break;
-                               case 0x2f8:
-                                       offset = 1;
-                                       break;
-                               case 0x898:
-                                       offset = 2;
-                                       break;
-                               case 0x890:
-                                       offset = 3;
-                                       break;
-                               default:
-                                       /* We dont recognise the serial port */
-                                       goto not_found;
-                       }
-               }
-       }
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-#ifdef CONFIG_PPC_PSERIES
-       else if (strcmp(name, "vty") == 0) {
-               u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL);
-               char *compat = (char *)get_property(prom_stdout, "compatible", NULL);
-
-               if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) {
-                       /* Host Virtual Serial Interface */
-                       switch (reg[0]) {
-                               case 0x30000000:
-                                       offset = 0;
-                                       break;
-                               case 0x30000001:
-                                       offset = 1;
-                                       break;
-                               default:
-                                       goto not_found;
-                       }
-                       of_node_put(prom_stdout);
-                       DBG("Found hvsi console at offset %d\n", offset);
-                       return add_preferred_console("hvsi", offset, NULL);
-               } else {
-                       /* pSeries LPAR virtual console */
-                       of_node_put(prom_stdout);
-                       DBG("Found hvc console\n");
-                       return add_preferred_console("hvc", 0, NULL);
-               }
-       }
-#endif /* CONFIG_PPC_PSERIES */
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
-       else if (strcmp(name, "ch-a") == 0)
-               offset = 0;
-       else if (strcmp(name, "ch-b") == 0)
-               offset = 1;
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-       else
-               goto not_found;
-       of_node_put(prom_stdout);
-
-       DBG("Found serial console at ttyS%d\n", offset);
-
-       if (spd) {
-               static char __initdata opt[16];
-               sprintf(opt, "%d", *spd);
-               return add_preferred_console("ttyS", offset, opt);
-       } else
-               return add_preferred_console("ttyS", offset, NULL);
-
- not_found:
-       DBG("No preferred console found !\n");
-       of_node_put(prom_stdout);
-       return -ENODEV;
-}
-console_initcall(set_preferred_console);
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
 void __init check_for_initrd(void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -442,7 +319,7 @@ void __init check_for_initrd(void)
        /* If we were passed an initrd, set the ROOT_DEV properly if the values
         * look sensible. If not, clear initrd reference.
         */
-       if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
+       if (is_kernel_addr(initrd_start) && is_kernel_addr(initrd_end) &&
            initrd_end > initrd_start)
                ROOT_DEV = Root_RAM0;
        else
index e5694335bf10ef63f1b0b7d4988b623c085b252a..e5d285adb49687534680d6797e7fd43f4c125f6d 100644 (file)
@@ -39,6 +39,8 @@
 #include <asm/nvram.h>
 #include <asm/xmon.h>
 #include <asm/time.h>
+#include <asm/serial.h>
+#include <asm/udbg.h>
 
 #include "setup.h"
 
@@ -172,12 +174,23 @@ void __init platform_init(void)
  */
 void __init machine_init(unsigned long dt_ptr, unsigned long phys)
 {
+       /* If btext is enabled, we might have a BAT setup for early display,
+        * thus we do enable some very basic udbg output
+        */
+#ifdef CONFIG_BOOTX_TEXT
+       udbg_putc = btext_drawchar;
+#endif
+
+       /* Do some early initialization based on the flat device tree */
        early_init_devtree(__va(dt_ptr));
 
+       /* Check default command line */
 #ifdef CONFIG_CMDLINE
-       strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
+       if (cmd_line[0] == 0)
+               strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
 #endif /* CONFIG_CMDLINE */
 
+       /* Base init based on machine type */
        platform_init();
 
 #ifdef CONFIG_6xx
@@ -282,25 +295,22 @@ void __init setup_arch(char **cmdline_p)
 
        unflatten_device_tree();
        check_for_initrd();
-       finish_device_tree();
 
-       smp_setup_cpu_maps();
+       if (ppc_md.init_early)
+               ppc_md.init_early();
 
-#ifdef CONFIG_BOOTX_TEXT
-       init_boot_display();
+#ifdef CONFIG_SERIAL_8250
+       find_legacy_serial_ports();
 #endif
+       finish_device_tree();
 
-#ifdef CONFIG_PPC_PMAC
-       /* This could be called "early setup arch", it must be done
-        * now because xmon need it
-        */
-       if (_machine == _MACH_Pmac)
-               pmac_feature_init();    /* New cool way */
-#endif
+       smp_setup_cpu_maps();
 
 #ifdef CONFIG_XMON_DEFAULT
        xmon_init(1);
 #endif
+       /* Register early console */
+       register_early_udbg_console();
 
 #if defined(CONFIG_KGDB)
        if (ppc_md.kgdb_map_scc)
index e3fb78397dc6d2b84e1f6fd8d0b7e9fc89e92ffe..98e9f0595dd8096a1935867203ee87487379eaf1 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <asm/io.h>
+#include <asm/kdump.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
@@ -268,6 +269,10 @@ void __init early_setup(unsigned long dt_ptr)
        }
        ppc_md = **mach;
 
+#ifdef CONFIG_CRASH_DUMP
+       kdump_setup();
+#endif
+
        DBG("Found, Initializing memory management...\n");
 
        /*
@@ -317,6 +322,7 @@ void early_setup_secondary(void)
 void smp_release_cpus(void)
 {
        extern unsigned long __secondary_hold_spinloop;
+       unsigned long *ptr;
 
        DBG(" -> smp_release_cpus()\n");
 
@@ -327,7 +333,9 @@ void smp_release_cpus(void)
         * This is useless but harmless on iSeries, secondaries are already
         * waiting on their paca spinloops. */
 
-       __secondary_hold_spinloop = 1;
+       ptr  = (unsigned long *)((unsigned long)&__secondary_hold_spinloop
+                       - PHYSICAL_START);
+       *ptr = 1;
        mb();
 
        DBG(" <- smp_release_cpus()\n");
@@ -459,16 +467,21 @@ void __init setup_system(void)
         */
        ppc_md.init_early();
 
+       /*
+        * We can discover serial ports now since the above did setup the
+        * hash table management for us, thus ioremap works. We do that early
+        * so that further code can be debugged
+        */
+#ifdef CONFIG_SERIAL_8250
+       find_legacy_serial_ports();
+#endif
+
        /*
         * "Finish" the device-tree, that is do the actual parsing of
         * some of the properties like the interrupt map
         */
        finish_device_tree();
 
-#ifdef CONFIG_BOOTX_TEXT
-       init_boot_display();
-#endif
-
        /*
         * Initialize xmon
         */
@@ -507,6 +520,9 @@ void __init setup_system(void)
               ppc64_caches.iline_size);
        printk("htab_address                  = 0x%p\n", htab_address);
        printk("htab_hash_mask                = 0x%lx\n", htab_hash_mask);
+#if PHYSICAL_START > 0
+       printk("physical_start                = 0x%x\n", PHYSICAL_START);
+#endif
        printk("-----------------------------------------------------\n");
 
        mm_init_ppc64();
@@ -657,187 +673,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg)
        printk("[terminate]%04x %s\n", src, msg);
 }
 
-#ifndef CONFIG_PPC_ISERIES
-/*
- * This function can be used by platforms to "find" legacy serial ports.
- * It works for "serial" nodes under an "isa" node, and will try to
- * respect the "ibm,aix-loc" property if any. It works with up to 8
- * ports.
- */
-
-#define MAX_LEGACY_SERIAL_PORTS        8
-static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1];
-static unsigned int old_serial_count;
-
-void __init generic_find_legacy_serial_ports(u64 *physport,
-               unsigned int *default_speed)
-{
-       struct device_node *np;
-       u32 *sizeprop;
-
-       struct isa_reg_property {
-               u32 space;
-               u32 address;
-               u32 size;
-       };
-       struct pci_reg_property {
-               struct pci_address addr;
-               u32 size_hi;
-               u32 size_lo;
-       };                                                                        
-
-       DBG(" -> generic_find_legacy_serial_port()\n");
-
-       *physport = 0;
-       if (default_speed)
-               *default_speed = 0;
-
-       np = of_find_node_by_path("/");
-       if (!np)
-               return;
-
-       /* First fill our array */
-       for (np = NULL; (np = of_find_node_by_type(np, "serial"));) {
-               struct device_node *isa, *pci;
-               struct isa_reg_property *reg;
-               unsigned long phys_size, addr_size, io_base;
-               u32 *rangesp;
-               u32 *interrupts, *clk, *spd;
-               char *typep;
-               int index, rlen, rentsize;
-
-               /* Ok, first check if it's under an "isa" parent */
-               isa = of_get_parent(np);
-               if (!isa || strcmp(isa->name, "isa")) {
-                       DBG("%s: no isa parent found\n", np->full_name);
-                       continue;
-               }
-               
-               /* Now look for an "ibm,aix-loc" property that gives us ordering
-                * if any...
-                */
-               typep = (char *)get_property(np, "ibm,aix-loc", NULL);
-
-               /* Get the ISA port number */
-               reg = (struct isa_reg_property *)get_property(np, "reg", NULL); 
-               if (reg == NULL)
-                       goto next_port;
-               /* We assume the interrupt number isn't translated ... */
-               interrupts = (u32 *)get_property(np, "interrupts", NULL);
-               /* get clock freq. if present */
-               clk = (u32 *)get_property(np, "clock-frequency", NULL);
-               /* get default speed if present */
-               spd = (u32 *)get_property(np, "current-speed", NULL);
-               /* Default to locate at end of array */
-               index = old_serial_count; /* end of the array by default */
-
-               /* If we have a location index, then use it */
-               if (typep && *typep == 'S') {
-                       index = simple_strtol(typep+1, NULL, 0) - 1;
-                       /* if index is out of range, use end of array instead */
-                       if (index >= MAX_LEGACY_SERIAL_PORTS)
-                               index = old_serial_count;
-                       /* if our index is still out of range, that mean that
-                        * array is full, we could scan for a free slot but that
-                        * make little sense to bother, just skip the port
-                        */
-                       if (index >= MAX_LEGACY_SERIAL_PORTS)
-                               goto next_port;
-                       if (index >= old_serial_count)
-                               old_serial_count = index + 1;
-                       /* Check if there is a port who already claimed our slot */
-                       if (serial_ports[index].iobase != 0) {
-                               /* if we still have some room, move it, else override */
-                               if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) {
-                                       DBG("Moved legacy port %d -> %d\n", index,
-                                           old_serial_count);
-                                       serial_ports[old_serial_count++] =
-                                               serial_ports[index];
-                               } else {
-                                       DBG("Replacing legacy port %d\n", index);
-                               }
-                       }
-               }
-               if (index >= MAX_LEGACY_SERIAL_PORTS)
-                       goto next_port;
-               if (index >= old_serial_count)
-                       old_serial_count = index + 1;
-
-               /* Now fill the entry */
-               memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port));
-               serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16;
-               serial_ports[index].iobase = reg->address;
-               serial_ports[index].irq = interrupts ? interrupts[0] : 0;
-               serial_ports[index].flags = ASYNC_BOOT_AUTOCONF;
-
-               DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n",
-                   index,
-                   serial_ports[index].iobase,
-                   serial_ports[index].irq,
-                   serial_ports[index].uartclk);
-
-               /* Get phys address of IO reg for port 1 */
-               if (index != 0)
-                       goto next_port;
-
-               pci = of_get_parent(isa);
-               if (!pci) {
-                       DBG("%s: no pci parent found\n", np->full_name);
-                       goto next_port;
-               }
-
-               rangesp = (u32 *)get_property(pci, "ranges", &rlen);
-               if (rangesp == NULL) {
-                       of_node_put(pci);
-                       goto next_port;
-               }
-               rlen /= 4;
-
-               /* we need the #size-cells of the PCI bridge node itself */
-               phys_size = 1;
-               sizeprop = (u32 *)get_property(pci, "#size-cells", NULL);
-               if (sizeprop != NULL)
-                       phys_size = *sizeprop;
-               /* we need the parent #addr-cells */
-               addr_size = prom_n_addr_cells(pci);
-               rentsize = 3 + addr_size + phys_size;
-               io_base = 0;
-               for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) {
-                       if (((rangesp[0] >> 24) & 0x3) != 1)
-                               continue; /* not IO space */
-                       io_base = rangesp[3];
-                       if (addr_size == 2)
-                               io_base = (io_base << 32) | rangesp[4];
-               }
-               if (io_base != 0) {
-                       *physport = io_base + reg->address;
-                       if (default_speed && spd)
-                               *default_speed = *spd;
-               }
-               of_node_put(pci);
-       next_port:
-               of_node_put(isa);
-       }
-
-       DBG(" <- generic_find_legacy_serial_port()\n");
-}
-
-static struct platform_device serial_device = {
-       .name   = "serial8250",
-       .id     = PLAT8250_DEV_PLATFORM,
-       .dev    = {
-               .platform_data = serial_ports,
-       },
-};
-
-static int __init serial_dev_init(void)
-{
-       return platform_device_register(&serial_device);
-}
-arch_initcall(serial_dev_init);
-
-#endif /* CONFIG_PPC_ISERIES */
-
 int check_legacy_ioport(unsigned long base_port)
 {
        if (ppc_md.check_legacy_ioport == NULL)
index 5a2eba60dd390c939f9532f9f3384469d8b40fa5..d3f0b6d452fb71d906a56fd87980f65c229c5bda 100644 (file)
@@ -76,7 +76,6 @@
  * registers from *regs.  This is what we need
  * to do when a signal has been delivered.
  */
-#define sigreturn_exit(regs)   return 0
 
 #define GP_REGS_SIZE   min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32))
 #undef __SIGNAL_FRAMESIZE
@@ -156,9 +155,17 @@ static inline int save_general_regs(struct pt_regs *regs,
        elf_greg_t64 *gregs = (elf_greg_t64 *)regs;
        int i;
 
-       for (i = 0; i <= PT_RESULT; i ++)
+       if (!FULL_REGS(regs)) {
+               set_thread_flag(TIF_SAVE_NVGPRS);
+               current_thread_info()->nvgprs_frame = frame->mc_gregs;
+       }
+
+       for (i = 0; i <= PT_RESULT; i ++) {
+               if (i == 14 && !FULL_REGS(regs))
+                       i = 32;
                if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i]))
                        return -EFAULT;
+       }
        return 0;
 }
 
@@ -179,8 +186,6 @@ static inline int restore_general_regs(struct pt_regs *regs,
 
 #else /* CONFIG_PPC64 */
 
-extern void sigreturn_exit(struct pt_regs *);
-
 #define GP_REGS_SIZE   min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
 
 static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set)
@@ -214,6 +219,15 @@ static inline int get_old_sigaction(struct k_sigaction *new_ka,
 static inline int save_general_regs(struct pt_regs *regs,
                struct mcontext __user *frame)
 {
+       if (!FULL_REGS(regs)) {
+               /* Zero out the unsaved GPRs to avoid information
+                  leak, and set TIF_SAVE_NVGPRS to ensure that the
+                  registers do actually get saved later. */
+               memset(&regs->gpr[14], 0, 18 * sizeof(unsigned long));
+               current_thread_info()->nvgprs_frame = &frame->mc_gregs;
+               set_thread_flag(TIF_SAVE_NVGPRS);
+       }
+
        return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE);
 }
 
@@ -256,8 +270,10 @@ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                schedule();
-               if (do_signal(&saveset, regs))
-                       sigreturn_exit(regs);
+               if (do_signal(&saveset, regs)) {
+                       set_thread_flag(TIF_RESTOREALL);
+                       return 0;
+               }
        }
 }
 
@@ -292,8 +308,10 @@ long sys_rt_sigsuspend(
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                schedule();
-               if (do_signal(&saveset, regs))
-                       sigreturn_exit(regs);
+               if (do_signal(&saveset, regs)) {
+                       set_thread_flag(TIF_RESTOREALL);
+                       return 0;
+               }
        }
 }
 
@@ -391,9 +409,6 @@ struct rt_sigframe {
 static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
                int sigret)
 {
-#ifdef CONFIG_PPC32
-       CHECK_FULL_REGS(regs);
-#endif
        /* Make sure floating point registers are stored in regs */
        flush_fp_to_thread(current);
 
@@ -828,12 +843,6 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
        regs->gpr[6] = (unsigned long) rt_sf;
        regs->nip = (unsigned long) ka->sa.sa_handler;
        regs->trap = 0;
-#ifdef CONFIG_PPC64
-       regs->result = 0;
-
-       if (test_thread_flag(TIF_SINGLESTEP))
-               ptrace_notify(SIGTRAP);
-#endif
        return 1;
 
 badframe:
@@ -911,8 +920,8 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
         */
        if (do_setcontext(new_ctx, regs, 0))
                do_exit(SIGSEGV);
-       sigreturn_exit(regs);
-       /* doesn't actually return back to here */
+
+       set_thread_flag(TIF_RESTOREALL);
        return 0;
 }
 
@@ -945,12 +954,11 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
         * nobody does any...
         */
        compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs);
-       return (int)regs->result;
 #else
        do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]);
-       sigreturn_exit(regs);           /* doesn't return here */
-       return 0;
 #endif
+       set_thread_flag(TIF_RESTOREALL);
+       return 0;
 
  bad:
        force_sig(SIGSEGV, current);
@@ -1041,9 +1049,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
         */
        do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]);
 
-       sigreturn_exit(regs);
-       /* doesn't actually return back to here */
-
+       set_thread_flag(TIF_RESTOREALL);
  out:
        return 0;
 }
@@ -1107,12 +1113,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
        regs->gpr[4] = (unsigned long) sc;
        regs->nip = (unsigned long) ka->sa.sa_handler;
        regs->trap = 0;
-#ifdef CONFIG_PPC64
-       regs->result = 0;
-
-       if (test_thread_flag(TIF_SINGLESTEP))
-               ptrace_notify(SIGTRAP);
-#endif
 
        return 1;
 
@@ -1160,12 +1160,8 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
            || restore_user_regs(regs, sr, 1))
                goto badframe;
 
-#ifdef CONFIG_PPC64
-       return (int)regs->result;
-#else
-       sigreturn_exit(regs);           /* doesn't return */
+       set_thread_flag(TIF_RESTOREALL);
        return 0;
-#endif
 
 badframe:
        force_sig(SIGSEGV, current);
index 1decf2785530e13397bd7196f680addc247bfff2..5462bef898f6101d5b838f52e8380978e75f2c52 100644 (file)
@@ -96,8 +96,10 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                schedule();
-               if (do_signal(&saveset, regs))
+               if (do_signal(&saveset, regs)) {
+                       set_thread_flag(TIF_RESTOREALL);
                        return 0;
+               }
        }
 }
 
@@ -152,6 +154,14 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
        err |= __put_user(0, &sc->v_regs);
 #endif /* CONFIG_ALTIVEC */
        err |= __put_user(&sc->gp_regs, &sc->regs);
+       if (!FULL_REGS(regs)) {
+               /* Zero out the unsaved GPRs to avoid information
+                  leak, and set TIF_SAVE_NVGPRS to ensure that the
+                  registers do actually get saved later. */
+               memset(&regs->gpr[14], 0, 18 * sizeof(unsigned long));
+               set_thread_flag(TIF_SAVE_NVGPRS);
+               current_thread_info()->nvgprs_frame = &sc->gp_regs;
+       }
        err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
        err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
        err |= __put_user(signr, &sc->signal);
@@ -340,6 +350,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx,
                do_exit(SIGSEGV);
 
        /* This returns like rt_sigreturn */
+       set_thread_flag(TIF_RESTOREALL);
        return 0;
 }
 
@@ -372,7 +383,8 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
         */
        do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]);
 
-       return regs->result;
+       set_thread_flag(TIF_RESTOREALL);
+       return 0;
 
 badframe:
 #if DEBUG_SIG
@@ -454,9 +466,6 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
        if (err)
                goto badframe;
 
-       if (test_thread_flag(TIF_SINGLESTEP))
-               ptrace_notify(SIGTRAP);
-
        return 1;
 
 badframe:
@@ -502,6 +511,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
                 * we only get here if there is a handler, we dont restart.
                 */
                regs->result = -EINTR;
+               regs->gpr[3] = EINTR;
+               regs->ccr |= 0x10000000;
                break;
        case -ERESTARTSYS:
                /* ERESTARTSYS means to restart the syscall if there is no
@@ -509,6 +520,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
                 */
                if (!(ka->sa.sa_flags & SA_RESTART)) {
                        regs->result = -EINTR;
+                       regs->gpr[3] = EINTR;
+                       regs->ccr |= 0x10000000;
                        break;
                }
                /* fallthrough */
index 30374d2f88e5c47eb34bed23bec01628ea387b42..d381ec90b759e27fe5242d9f7c3e66bb4b7ca939 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/sysdev.h>
 #include <linux/cpu.h>
 #include <linux/notifier.h>
+#include <linux/topology.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -75,6 +76,8 @@ void smp_call_function_interrupt(void);
 
 int smt_enabled_at_boot = 1;
 
+static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
+
 #ifdef CONFIG_MPIC
 int __init smp_mpic_probe(void)
 {
@@ -123,11 +126,16 @@ void smp_message_recv(int msg, struct pt_regs *regs)
                /* XXX Do we have to do this? */
                set_need_resched();
                break;
-#ifdef CONFIG_DEBUGGER
        case PPC_MSG_DEBUGGER_BREAK:
+               if (crash_ipi_function_ptr) {
+                       crash_ipi_function_ptr(regs);
+                       break;
+               }
+#ifdef CONFIG_DEBUGGER
                debugger_ipi(regs);
                break;
-#endif
+#endif /* CONFIG_DEBUGGER */
+               /* FALLTHROUGH */
        default:
                printk("SMP %d: smp_message_recv(): unknown msg %d\n",
                       smp_processor_id(), msg);
@@ -147,6 +155,17 @@ void smp_send_debugger_break(int cpu)
 }
 #endif
 
+#ifdef CONFIG_KEXEC
+void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
+{
+       crash_ipi_function_ptr = crash_ipi_callback;
+       if (crash_ipi_callback) {
+               mb();
+               smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
+       }
+}
+#endif
+
 static void stop_this_cpu(void *dummy)
 {
        local_irq_disable();
@@ -452,10 +471,6 @@ int __devinit __cpu_up(unsigned int cpu)
        if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))
                return -EINVAL;
 
-#ifdef CONFIG_PPC64
-       paca[cpu].default_decr = tb_ticks_per_jiffy;
-#endif
-
        /* Make sure callin-map entry is 0 (can be leftover a CPU
         * hotplug
         */
@@ -554,6 +569,8 @@ void __init smp_cpus_done(unsigned int max_cpus)
        smp_ops->setup_cpu(boot_cpuid);
 
        set_cpus_allowed(current, old_mask);
+
+       dump_numa_cpu_topology();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
index 91b93d917b64aea53aa5ccc54ff8bdfb9c2441b9..ad895c99813be0d5c9fea05244fe79b0ad91b3e1 100644 (file)
@@ -43,9 +43,6 @@
 #include <asm/time.h>
 #include <asm/unistd.h>
 
-extern unsigned long wall_jiffies;
-
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -311,31 +308,6 @@ int sys_olduname(struct oldold_utsname __user *name)
        return error? -EFAULT: 0;
 }
 
-#ifdef CONFIG_PPC64
-time_t sys64_time(time_t __user * tloc)
-{
-       time_t secs;
-       time_t usecs;
-
-       long tb_delta = tb_ticks_since(tb_last_stamp);
-       tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
-
-       secs  = xtime.tv_sec;  
-       usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec;
-       while (usecs >= USEC_PER_SEC) {
-               ++secs;
-               usecs -= USEC_PER_SEC;
-       }
-
-       if (tloc) {
-               if (put_user(secs,tloc))
-                       secs = -EFAULT;
-       }
-
-       return secs;
-}
-#endif
-
 long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low,
                      u32 len_high, u32 len_low)
 {
index 65eaea91b499ee96787c4755c10ad70f426950e0..65463a1076e8afc5e3abbe3e17726784ad27fb43 100644 (file)
@@ -54,7 +54,7 @@ SYSCALL(link)
 SYSCALL(unlink)
 COMPAT_SYS(execve)
 SYSCALL(chdir)
-SYSX(sys64_time,compat_sys_time,sys_time)
+COMPAT_SYS(time)
 SYSCALL(mknod)
 SYSCALL(chmod)
 SYSCALL(lchown)
@@ -113,7 +113,7 @@ SYSCALL(sgetmask)
 COMPAT_SYS(ssetmask)
 SYSCALL(setreuid)
 SYSCALL(setregid)
-SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend)
+SYS32ONLY(sigsuspend)
 COMPAT_SYS(sigpending)
 COMPAT_SYS(sethostname)
 COMPAT_SYS(setrlimit)
@@ -160,7 +160,7 @@ SYSCALL(swapoff)
 COMPAT_SYS(sysinfo)
 COMPAT_SYS(ipc)
 SYSCALL(fsync)
-SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn)
+SYS32ONLY(sigreturn)
 PPC_SYS(clone)
 COMPAT_SYS(setdomainname)
 PPC_SYS(newuname)
@@ -213,13 +213,13 @@ COMPAT_SYS(nfsservctl)
 SYSCALL(setresgid)
 SYSCALL(getresgid)
 COMPAT_SYS(prctl)
-SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn)
+COMPAT_SYS(rt_sigreturn)
 COMPAT_SYS(rt_sigaction)
 COMPAT_SYS(rt_sigprocmask)
 COMPAT_SYS(rt_sigpending)
 COMPAT_SYS(rt_sigtimedwait)
 COMPAT_SYS(rt_sigqueueinfo)
-SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend)
+COMPAT_SYS(rt_sigsuspend)
 COMPAT_SYS(pread64)
 COMPAT_SYS(pwrite64)
 SYSCALL(chown)
@@ -290,7 +290,7 @@ COMPAT_SYS(clock_settime)
 COMPAT_SYS(clock_gettime)
 COMPAT_SYS(clock_getres)
 COMPAT_SYS(clock_nanosleep)
-SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext)
+COMPAT_SYS(swapcontext)
 COMPAT_SYS(tgkill)
 COMPAT_SYS(utimes)
 COMPAT_SYS(statfs64)
@@ -319,3 +319,5 @@ COMPAT_SYS(ioprio_get)
 SYSCALL(inotify_init)
 SYSCALL(inotify_add_watch)
 SYSCALL(inotify_rm_watch)
+SYSCALL(spu_run)
+SYSCALL(spu_create)
index de8479769bb729cf3068e42d7b1488b462c0ff68..56f50e91bddbcb612201fdc4d34d0a2dd8b7b633 100644 (file)
@@ -699,10 +699,6 @@ void __init time_init(void)
        div128_by_32(1024*1024, 0, tb_ticks_per_sec, &res);
        tb_to_xs = res.result_low;
 
-#ifdef CONFIG_PPC64
-       get_paca()->default_decr = tb_ticks_per_jiffy;
-#endif
-
        /*
         * Compute scale factor for sched_clock.
         * The calibrate_decr() function has set tb_ticks_per_sec,
index 1511454c4690bafd1a9020afb4c3059180d068c2..7509aa6474f2e7c03deb7fa896b658fd31f6247f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/prctl.h>
 #include <linux/delay.h>
 #include <linux/kprobes.h>
+#include <linux/kexec.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -95,7 +96,7 @@ static DEFINE_SPINLOCK(die_lock);
 
 int die(const char *str, struct pt_regs *regs, long err)
 {
-       static int die_counter;
+       static int die_counter, crash_dump_start = 0;
        int nl = 0;
 
        if (debugger(regs))
@@ -156,7 +157,21 @@ int die(const char *str, struct pt_regs *regs, long err)
        print_modules();
        show_regs(regs);
        bust_spinlocks(0);
+
+       if (!crash_dump_start && kexec_should_crash(current)) {
+               crash_dump_start = 1;
+               spin_unlock_irq(&die_lock);
+               crash_kexec(regs);
+               /* NOTREACHED */
+       }
        spin_unlock_irq(&die_lock);
+       if (crash_dump_start)
+               /*
+                * Only for soft-reset: Other CPUs will be responded to an IPI
+                * sent by first kexec CPU.
+                */
+               for(;;)
+                       ;
 
        if (in_interrupt())
                panic("Fatal exception in interrupt");
@@ -215,8 +230,10 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 void system_reset_exception(struct pt_regs *regs)
 {
        /* See if any machine dependent calls */
-       if (ppc_md.system_reset_exception)
-               ppc_md.system_reset_exception(regs);
+       if (ppc_md.system_reset_exception) {
+               if (ppc_md.system_reset_exception(regs))
+                       return;
+       }
 
        die("System Reset", regs, SIGABRT);
 
@@ -886,12 +903,10 @@ void altivec_unavailable_exception(struct pt_regs *regs)
        die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
 }
 
-#if defined(CONFIG_PPC64) || defined(CONFIG_E500)
 void performance_monitor_exception(struct pt_regs *regs)
 {
        perf_irq(regs);
 }
-#endif
 
 #ifdef CONFIG_8xx
 void SoftwareEmulation(struct pt_regs *regs)
index 0d878e72fc449257623c78a778434becd0aa6eda..558c1ceb2b93fb046b96971235af929a00247dc2 100644 (file)
@@ -16,8 +16,8 @@
 #include <linux/console.h>
 #include <asm/processor.h>
 
-void (*udbg_putc)(unsigned char c);
-unsigned char (*udbg_getc)(void);
+void (*udbg_putc)(char c);
+int (*udbg_getc)(void);
 int (*udbg_getc_poll)(void);
 
 /* udbg library, used by xmon et al */
@@ -57,8 +57,8 @@ int udbg_write(const char *s, int n)
 
 int udbg_read(char *buf, int buflen)
 {
-       char c, *p = buf;
-       int i;
+       char *p = buf;
+       int i, c;
 
        if (!udbg_getc)
                return 0;
@@ -66,8 +66,11 @@ int udbg_read(char *buf, int buflen)
        for (i = 0; i < buflen; ++i) {
                do {
                        c = udbg_getc();
+                       if (c == -1 && i == 0)
+                               return -1;
+
                } while (c == 0x11 || c == 0x13);
-               if (c == 0)
+               if (c == 0 || c == -1)
                        break;
                *p++ = c;
        }
@@ -78,7 +81,7 @@ int udbg_read(char *buf, int buflen)
 #define UDBG_BUFSIZE 256
 void udbg_printf(const char *fmt, ...)
 {
-       unsigned char buf[UDBG_BUFSIZE];
+       char buf[UDBG_BUFSIZE];
        va_list args;
 
        va_start(args, fmt);
@@ -87,6 +90,12 @@ void udbg_printf(const char *fmt, ...)
        va_end(args);
 }
 
+void __init udbg_progress(char *s, unsigned short hex)
+{
+       udbg_puts(s);
+       udbg_puts("\n");
+}
+
 /*
  * Early boot console based on udbg
  */
@@ -99,7 +108,7 @@ static void udbg_console_write(struct console *con, const char *s,
 static struct console udbg_console = {
        .name   = "udbg",
        .write  = udbg_console_write,
-       .flags  = CON_PRINTBUFFER,
+       .flags  = CON_PRINTBUFFER | CON_ENABLED,
        .index  = -1,
 };
 
@@ -107,15 +116,19 @@ static int early_console_initialized;
 
 void __init disable_early_printk(void)
 {
+#if 1
        if (!early_console_initialized)
                return;
        unregister_console(&udbg_console);
        early_console_initialized = 0;
+#endif
 }
 
 /* called by setup_system */
 void register_early_udbg_console(void)
 {
+       if (early_console_initialized)
+               return;
        early_console_initialized = 1;
        register_console(&udbg_console);
 }
index 9313574ab935c422a0b823436284d66f5f2eedc1..7541bf44d2da5e95ce7a7cc9a789e7e7db67c817 100644 (file)
@@ -43,9 +43,11 @@ struct NS16550 {
 #define LSR_TEMT 0x40  /* Xmitter empty */
 #define LSR_ERR  0x80  /* Error */
 
+#define LCR_DLAB 0x80
+
 static volatile struct NS16550 __iomem *udbg_comport;
 
-static void udbg_550_putc(unsigned char c)
+static void udbg_550_putc(char c)
 {
        if (udbg_comport) {
                while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
@@ -67,39 +69,80 @@ static int udbg_550_getc_poll(void)
        return -1;
 }
 
-static unsigned char udbg_550_getc(void)
+static int udbg_550_getc(void)
 {
        if (udbg_comport) {
                while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
                        /* wait for char */;
                return in_8(&udbg_comport->rbr);
        }
-       return 0;
+       return -1;
 }
 
-void udbg_init_uart(void __iomem *comport, unsigned int speed)
+void udbg_init_uart(void __iomem *comport, unsigned int speed,
+                   unsigned int clock)
 {
-       u16 dll = speed ? (115200 / speed) : 12;
+       unsigned int dll, base_bauds = clock / 16;
+
+       if (speed == 0)
+               speed = 9600;
+       dll = base_bauds / speed;
 
        if (comport) {
                udbg_comport = (struct NS16550 __iomem *)comport;
                out_8(&udbg_comport->lcr, 0x00);
                out_8(&udbg_comport->ier, 0xff);
                out_8(&udbg_comport->ier, 0x00);
-               out_8(&udbg_comport->lcr, 0x80);        /* Access baud rate */
-               out_8(&udbg_comport->dll, dll & 0xff);  /* 1 = 115200,  2 = 57600,
-                                                          3 = 38400, 12 = 9600 baud */
-               out_8(&udbg_comport->dlm, dll >> 8);    /* dll >> 8 which should be zero
-                                                          for fast rates; */
-               out_8(&udbg_comport->lcr, 0x03);        /* 8 data, 1 stop, no parity */
-               out_8(&udbg_comport->mcr, 0x03);        /* RTS/DTR */
-               out_8(&udbg_comport->fcr ,0x07);        /* Clear & enable FIFOs */
+               out_8(&udbg_comport->lcr, LCR_DLAB);
+               out_8(&udbg_comport->dll, dll & 0xff);
+               out_8(&udbg_comport->dlm, dll >> 8);
+               /* 8 data, 1 stop, no parity */
+               out_8(&udbg_comport->lcr, 0x03);
+               /* RTS/DTR */
+               out_8(&udbg_comport->mcr, 0x03);
+               /* Clear & enable FIFOs */
+               out_8(&udbg_comport->fcr ,0x07);
                udbg_putc = udbg_550_putc;
                udbg_getc = udbg_550_getc;
                udbg_getc_poll = udbg_550_getc_poll;
        }
 }
 
+unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
+{
+       unsigned int dll, dlm, divisor, prescaler, speed;
+       u8 old_lcr;
+       volatile struct NS16550 __iomem *port = comport;
+
+       old_lcr = in_8(&port->lcr);
+
+       /* select divisor latch registers.  */
+       out_8(&port->lcr, LCR_DLAB);
+
+       /* now, read the divisor */
+       dll = in_8(&port->dll);
+       dlm = in_8(&port->dlm);
+       divisor = dlm << 8 | dll;
+
+       /* check prescaling */
+       if (in_8(&port->mcr) & 0x80)
+               prescaler = 4;
+       else
+               prescaler = 1;
+
+       /* restore the LCR */
+       out_8(&port->lcr, old_lcr);
+
+       /* calculate speed */
+       speed = (clock / prescaler) / (divisor * 16);
+
+       /* sanity check */
+       if (speed < 0 || speed > (clock / 16))
+               speed = 9600;
+
+       return speed;
+}
+
 #ifdef CONFIG_PPC_MAPLE
 void udbg_maple_real_putc(unsigned char c)
 {
index 93d4fbfdb724a137ee6ab385d880e79e80795f75..a4815d316722cddcf9c614b4524f57238f7a4c9f 100644 (file)
@@ -81,7 +81,8 @@ static int store_updates_sp(struct pt_regs *regs)
 }
 
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
-static void do_dabr(struct pt_regs *regs, unsigned long error_code)
+static void do_dabr(struct pt_regs *regs, unsigned long address,
+                   unsigned long error_code)
 {
        siginfo_t info;
 
@@ -99,7 +100,7 @@ static void do_dabr(struct pt_regs *regs, unsigned long error_code)
        info.si_signo = SIGTRAP;
        info.si_errno = 0;
        info.si_code = TRAP_HWBKPT;
-       info.si_addr = (void __user *)regs->nip;
+       info.si_addr = (void __user *)address;
        force_sig_info(SIGTRAP, &info, current);
 }
 #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/
@@ -159,7 +160,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
        if (error_code & DSISR_DABRMATCH) {
                /* DABR match */
-               do_dabr(regs, error_code);
+               do_dabr(regs, address, error_code);
                return 0;
        }
 #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/
index a606504678bd5aa318d3af992c4a117d96e41c66..5bb433cbe41b38d93e1a503640790fc86d6aa518 100644 (file)
@@ -456,7 +456,7 @@ void __init htab_initialize(void)
 
        /* create bolted the linear mapping in the hash table */
        for (i=0; i < lmb.memory.cnt; i++) {
-               base = lmb.memory.region[i].base + KERNELBASE;
+               base = (unsigned long)__va(lmb.memory.region[i].base);
                size = lmb.memory.region[i].size;
 
                DBG("creating mapping for region: %lx : %lx\n", base, size);
@@ -498,8 +498,8 @@ void __init htab_initialize(void)
         * for either 4K or 16MB pages.
         */
        if (tce_alloc_start) {
-               tce_alloc_start += KERNELBASE;
-               tce_alloc_end += KERNELBASE;
+               tce_alloc_start = (unsigned long)__va(tce_alloc_start);
+               tce_alloc_end = (unsigned long)__va(tce_alloc_end);
 
                if (base + size >= tce_alloc_start)
                        tce_alloc_start = base + size + 1;
@@ -644,6 +644,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
        DBG_LOW(" -> rc=%d\n", rc);
        return rc;
 }
+EXPORT_SYMBOL_GPL(hash_page);
 
 void hash_preload(struct mm_struct *mm, unsigned long ea,
                  unsigned long access, unsigned long trap)
index 54131b877da36cb3a827000d802ca76ce82507ad..b51bb28c054bbb5e14007af0d9efee7be0806a3a 100644 (file)
@@ -549,6 +549,17 @@ fail:
        return addr;
 }
 
+static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
+{
+       struct vm_area_struct *vma;
+
+       vma = find_vma(current->mm, addr);
+       if (!vma || ((addr + len) <= vma->vm_start))
+               return 0;
+
+       return -ENOMEM;
+}
+
 static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
 {
        unsigned long addr = 0;
@@ -618,15 +629,28 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
        if (!cpu_has_feature(CPU_FTR_16M_PAGE))
                return -EINVAL;
 
+       /* Paranoia, caller should have dealt with this */
+       BUG_ON((addr + len)  < addr);
+
        if (test_thread_flag(TIF_32BIT)) {
+               /* Paranoia, caller should have dealt with this */
+               BUG_ON((addr + len) > 0x100000000UL);
+
                curareas = current->mm->context.low_htlb_areas;
 
-               /* First see if we can do the mapping in the existing
-                * low areas */
+               /* First see if we can use the hint address */
+               if (addr && (htlb_check_hinted_area(addr, len) == 0)) {
+                       areamask = LOW_ESID_MASK(addr, len);
+                       if (open_low_hpage_areas(current->mm, areamask) == 0)
+                               return addr;
+               }
+
+               /* Next see if we can map in the existing low areas */
                addr = htlb_get_low_area(len, curareas);
                if (addr != -ENOMEM)
                        return addr;
 
+               /* Finally go looking for areas to open */
                lastshift = 0;
                for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
                     ! lastshift; areamask >>=1) {
@@ -641,12 +665,22 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
        } else {
                curareas = current->mm->context.high_htlb_areas;
 
-               /* First see if we can do the mapping in the existing
-                * high areas */
+               /* First see if we can use the hint address */
+               /* We discourage 64-bit processes from doing hugepage
+                * mappings below 4GB (must use MAP_FIXED) */
+               if ((addr >= 0x100000000UL)
+                   && (htlb_check_hinted_area(addr, len) == 0)) {
+                       areamask = HTLB_AREA_MASK(addr, len);
+                       if (open_high_hpage_areas(current->mm, areamask) == 0)
+                               return addr;
+               }
+
+               /* Next see if we can map in the existing high areas */
                addr = htlb_get_high_area(len, curareas);
                if (addr != -ENOMEM)
                        return addr;
 
+               /* Finally go looking for areas to open */
                lastshift = 0;
                for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
                     ! lastshift; areamask >>=1) {
index f9587bcc6a48f89f375269db28f4d827174e1e38..8b0c132bc163f174b512b7d48515e12d071f3732 100644 (file)
@@ -107,6 +107,7 @@ static int im_region_status(unsigned long v_addr, unsigned long size,
                if (v_addr < (unsigned long) tmp->addr + tmp->size)
                        break;
 
+       *vm = NULL;
        if (tmp) {
                if (im_region_overlaps(v_addr, size, tmp))
                        return IM_REGION_OVERLAP;
@@ -127,7 +128,6 @@ static int im_region_status(unsigned long v_addr, unsigned long size,
                }
        }
 
-       *vm = NULL;
        return IM_REGION_UNUSED;
 }
 
index 7d4b8b5f06063cdf41e1fe56c06fe207974d22a8..7d0d75c11848ec7ca0e1c8b0468e7958e47a1331 100644 (file)
@@ -188,6 +188,11 @@ void __init MMU_init(void)
 
        if (ppc_md.progress)
                ppc_md.progress("MMU:exit", 0x211);
+
+       /* From now on, btext is no longer BAT mapped if it was at all */
+#ifdef CONFIG_BOOTX_TEXT
+       btext_unmap();
+#endif
 }
 
 /* This is only called until mem_init is done. */
index ed6ed2e30daccaf09ff4967468fff97a312f5a02..15aac0d78dfa7bd9c1a7de3ab6c4f15fdefe2e9a 100644 (file)
@@ -114,19 +114,18 @@ void online_page(struct page *page)
        num_physpages++;
 }
 
-/*
- * This works only for the non-NUMA case.  Later, we'll need a lookup
- * to convert from real physical addresses to nid, that doesn't use
- * pfn_to_nid().
- */
 int __devinit add_memory(u64 start, u64 size)
 {
-       struct pglist_data *pgdata = NODE_DATA(0);
+       struct pglist_data *pgdata;
        struct zone *zone;
+       int nid;
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
 
-       start += KERNELBASE;
+       nid = hot_add_scn_to_nid(start);
+       pgdata = NODE_DATA(nid);
+
+       start = __va(start);
        create_section_mapping(start, start + size);
 
        /* this should work for most non-highmem platforms */
index ba7a3055a9fc42f20b70f80b7bc298f40137a559..2863a912bcd0950d3841d62c035110aa0f5b8d3a 100644 (file)
@@ -37,6 +37,7 @@ EXPORT_SYMBOL(node_data);
 
 static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
 static int min_common_depth;
+static int n_mem_addr_cells, n_mem_size_cells;
 
 /*
  * We need somewhere to store start/end/node for each region until we have
@@ -254,32 +255,20 @@ static int __init find_min_common_depth(void)
        return depth;
 }
 
-static int __init get_mem_addr_cells(void)
+static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
 {
        struct device_node *memory = NULL;
-       int rc;
 
        memory = of_find_node_by_type(memory, "memory");
        if (!memory)
-               return 0; /* it won't matter */
+               panic("numa.c: No memory nodes found!");
 
-       rc = prom_n_addr_cells(memory);
-       return rc;
+       *n_addr_cells = prom_n_addr_cells(memory);
+       *n_size_cells = prom_n_size_cells(memory);
+       of_node_put(memory);
 }
 
-static int __init get_mem_size_cells(void)
-{
-       struct device_node *memory = NULL;
-       int rc;
-
-       memory = of_find_node_by_type(memory, "memory");
-       if (!memory)
-               return 0; /* it won't matter */
-       rc = prom_n_size_cells(memory);
-       return rc;
-}
-
-static unsigned long __init read_n_cells(int n, unsigned int **buf)
+static unsigned long __devinit read_n_cells(int n, unsigned int **buf)
 {
        unsigned long result = 0;
 
@@ -386,7 +375,6 @@ static int __init parse_numa_properties(void)
 {
        struct device_node *cpu = NULL;
        struct device_node *memory = NULL;
-       int addr_cells, size_cells;
        int max_domain;
        unsigned long i;
 
@@ -425,8 +413,7 @@ static int __init parse_numa_properties(void)
                }
        }
 
-       addr_cells = get_mem_addr_cells();
-       size_cells = get_mem_size_cells();
+       get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);
        memory = NULL;
        while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
                unsigned long start;
@@ -436,15 +423,21 @@ static int __init parse_numa_properties(void)
                unsigned int *memcell_buf;
                unsigned int len;
 
-               memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+               memcell_buf = (unsigned int *)get_property(memory,
+                       "linux,usable-memory", &len);
+               if (!memcell_buf || len <= 0)
+                       memcell_buf =
+                               (unsigned int *)get_property(memory, "reg",
+                                       &len);
                if (!memcell_buf || len <= 0)
                        continue;
 
-               ranges = memory->n_addrs;
+               /* ranges in cell */
+               ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
 new_range:
                /* these are order-sensitive, and modify the buffer pointer */
-               start = read_n_cells(addr_cells, &memcell_buf);
-               size = read_n_cells(size_cells, &memcell_buf);
+               start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+               size = read_n_cells(n_mem_size_cells, &memcell_buf);
 
                numa_domain = of_node_numa_domain(memory);
 
@@ -497,7 +490,41 @@ static void __init setup_nonnuma(void)
        node_set_online(0);
 }
 
-static void __init dump_numa_topology(void)
+void __init dump_numa_cpu_topology(void)
+{
+       unsigned int node;
+       unsigned int cpu, count;
+
+       if (min_common_depth == -1 || !numa_enabled)
+               return;
+
+       for_each_online_node(node) {
+               printk(KERN_INFO "Node %d CPUs:", node);
+
+               count = 0;
+               /*
+                * If we used a CPU iterator here we would miss printing
+                * the holes in the cpumap.
+                */
+               for (cpu = 0; cpu < NR_CPUS; cpu++) {
+                       if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) {
+                               if (count == 0)
+                                       printk(" %u", cpu);
+                               ++count;
+                       } else {
+                               if (count > 1)
+                                       printk("-%u", cpu - 1);
+                               count = 0;
+                       }
+               }
+
+               if (count > 1)
+                       printk("-%u", NR_CPUS - 1);
+               printk("\n");
+       }
+}
+
+static void __init dump_numa_memory_topology(void)
 {
        unsigned int node;
        unsigned int count;
@@ -529,7 +556,6 @@ static void __init dump_numa_topology(void)
                        printk("-0x%lx", i);
                printk("\n");
        }
-       return;
 }
 
 /*
@@ -591,7 +617,7 @@ void __init do_init_bootmem(void)
        if (parse_numa_properties())
                setup_nonnuma();
        else
-               dump_numa_topology();
+               dump_numa_memory_topology();
 
        register_cpu_notifier(&ppc64_numa_nb);
 
@@ -730,3 +756,60 @@ static int __init early_numa(char *p)
        return 0;
 }
 early_param("numa", early_numa);
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * Find the node associated with a hot added memory section.  Section
+ * corresponds to a SPARSEMEM section, not an LMB.  It is assumed that
+ * sections are fully contained within a single LMB.
+ */
+int hot_add_scn_to_nid(unsigned long scn_addr)
+{
+       struct device_node *memory = NULL;
+       nodemask_t nodes;
+       int numa_domain = 0;
+
+       if (!numa_enabled || (min_common_depth < 0))
+               return numa_domain;
+
+       while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+               unsigned long start, size;
+               int ranges;
+               unsigned int *memcell_buf;
+               unsigned int len;
+
+               memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+               if (!memcell_buf || len <= 0)
+                       continue;
+
+               /* ranges in cell */
+               ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
+ha_new_range:
+               start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+               size = read_n_cells(n_mem_size_cells, &memcell_buf);
+               numa_domain = of_node_numa_domain(memory);
+
+               /* Domains not present at boot default to 0 */
+               if (!node_online(numa_domain))
+                       numa_domain = any_online_node(NODE_MASK_ALL);
+
+               if ((scn_addr >= start) && (scn_addr < (start + size))) {
+                       of_node_put(memory);
+                       goto got_numa_domain;
+               }
+
+               if (--ranges)           /* process all ranges in cell */
+                       goto ha_new_range;
+       }
+       BUG();  /* section address should be found above */
+
+       /* Temporary code to ensure that returned node is not empty */
+got_numa_domain:
+       nodes_setall(nodes);
+       while (NODE_DATA(numa_domain)->node_spanned_pages == 0) {
+               node_clear(numa_domain, nodes);
+               numa_domain = any_online_node(nodes);
+       }
+       return numa_domain;
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
index 60e852f2f8e59de68fe63b8b43df3e4d7ee28d1a..ffc8ed4de62d655aae5a63812492e017d3f06801 100644 (file)
@@ -75,7 +75,7 @@ static void slb_flush_and_rebolt(void)
        vflags = SLB_VSID_KERNEL | virtual_llp;
 
        ksp_esid_data = mk_esid_data(get_paca()->kstack, 2);
-       if ((ksp_esid_data & ESID_MASK) == KERNELBASE)
+       if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET)
                ksp_esid_data &= ~SLB_ESID_V;
 
        /* We need to do this all in asm, so we're sure we don't touch
@@ -87,8 +87,8 @@ static void slb_flush_and_rebolt(void)
                     /* Slot 2 - kernel stack */
                     "slbmte    %2,%3\n"
                     "isync"
-                    :: "r"(mk_vsid_data(VMALLOCBASE, vflags)),
-                       "r"(mk_esid_data(VMALLOCBASE, 1)),
+                    :: "r"(mk_vsid_data(VMALLOC_START, vflags)),
+                       "r"(mk_esid_data(VMALLOC_START, 1)),
                        "r"(mk_vsid_data(ksp_esid_data, lflags)),
                        "r"(ksp_esid_data)
                     : "memory");
@@ -134,14 +134,14 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
        else
                unmapped_base = TASK_UNMAPPED_BASE_USER64;
 
-       if (pc >= KERNELBASE)
+       if (is_kernel_addr(pc))
                return;
        slb_allocate(pc);
 
        if (GET_ESID(pc) == GET_ESID(stack))
                return;
 
-       if (stack >= KERNELBASE)
+       if (is_kernel_addr(stack))
                return;
        slb_allocate(stack);
 
@@ -149,7 +149,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
            || (GET_ESID(stack) == GET_ESID(unmapped_base)))
                return;
 
-       if (unmapped_base >= KERNELBASE)
+       if (is_kernel_addr(unmapped_base))
                return;
        slb_allocate(unmapped_base);
 }
@@ -213,10 +213,10 @@ void slb_initialize(void)
        asm volatile("isync":::"memory");
        asm volatile("slbmte  %0,%0"::"r" (0) : "memory");
        asm volatile("isync; slbia; isync":::"memory");
-       create_slbe(KERNELBASE, lflags, 0);
+       create_slbe(PAGE_OFFSET, lflags, 0);
 
        /* VMALLOC space has 4K pages always for now */
-       create_slbe(VMALLOCBASE, vflags, 1);
+       create_slbe(VMALLOC_START, vflags, 1);
 
        /* We don't bolt the stack for the time being - we're in boot,
         * so the stack is in the bolted segment.  By the time it goes
index 950ffc5848c7950e1d449615aa61fb5782dde2cc..d1acee38f16326c55e615626be75cdef5daef049 100644 (file)
@@ -37,9 +37,9 @@ _GLOBAL(slb_allocate_realmode)
 
        srdi    r9,r3,60                /* get region */
        srdi    r10,r3,28               /* get esid */
-       cmpldi  cr7,r9,0xc              /* cmp KERNELBASE for later use */
+       cmpldi  cr7,r9,0xc              /* cmp PAGE_OFFSET for later use */
 
-       /* r3 = address, r10 = esid, cr7 = <>KERNELBASE */
+       /* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */
        blt     cr7,0f                  /* user or kernel? */
 
        /* kernel address: proto-VSID = ESID */
@@ -166,7 +166,7 @@ _GLOBAL(slb_allocate_user)
 /*
  * Finish loading of an SLB entry and return
  *
- * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <>KERNELBASE
+ * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET
  */
 slb_finish_load:
        ASM_VSID_SCRAMBLE(r10,r9)
index 51e7951414e5ca561b1d51257be70efe52a84139..82e4951826bc7985869687a449a9a818e56d9803 100644 (file)
@@ -40,7 +40,7 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
        unsigned long entry, group, old_esid, castout_entry, i;
        unsigned int global_entry;
        struct stab_entry *ste, *castout_ste;
-       unsigned long kernel_segment = (esid << SID_SHIFT) >= KERNELBASE;
+       unsigned long kernel_segment = (esid << SID_SHIFT) >= PAGE_OFFSET;
 
        vsid_data = vsid << STE_VSID_SHIFT;
        esid_data = esid << SID_SHIFT | STE_ESID_KP | STE_ESID_V;
@@ -83,7 +83,7 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
                }
 
                /* Dont cast out the first kernel segment */
-               if ((castout_ste->esid_data & ESID_MASK) != KERNELBASE)
+               if ((castout_ste->esid_data & ESID_MASK) != PAGE_OFFSET)
                        break;
 
                castout_entry = (castout_entry + 1) & 0xf;
@@ -122,7 +122,7 @@ static int __ste_allocate(unsigned long ea, struct mm_struct *mm)
        unsigned long offset;
 
        /* Kernel or user address? */
-       if (ea >= KERNELBASE) {
+       if (is_kernel_addr(ea)) {
                vsid = get_kernel_vsid(ea);
        } else {
                if ((ea >= TASK_SIZE_USER64) || (! mm))
@@ -133,7 +133,7 @@ static int __ste_allocate(unsigned long ea, struct mm_struct *mm)
 
        stab_entry = make_ste(get_paca()->stab_addr, GET_ESID(ea), vsid);
 
-       if (ea < KERNELBASE) {
+       if (!is_kernel_addr(ea)) {
                offset = __get_cpu_var(stab_cache_ptr);
                if (offset < NR_STAB_CACHE_ENTRIES)
                        __get_cpu_var(stab_cache[offset++]) = stab_entry;
@@ -190,7 +190,7 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm)
                     entry++, ste++) {
                        unsigned long ea;
                        ea = ste->esid_data & ESID_MASK;
-                       if (ea < KERNELBASE) {
+                       if (!is_kernel_addr(ea)) {
                                ste->esid_data = 0;
                        }
                }
@@ -251,7 +251,7 @@ void stabs_alloc(void)
                        panic("Unable to allocate segment table for CPU %d.\n",
                              cpu);
 
-               newstab += KERNELBASE;
+               newstab = (unsigned long)__va(newstab);
 
                memset((void *)newstab, 0, HW_PAGE_SIZE);
 
@@ -270,11 +270,11 @@ void stabs_alloc(void)
  */
 void stab_initialize(unsigned long stab)
 {
-       unsigned long vsid = get_kernel_vsid(KERNELBASE);
+       unsigned long vsid = get_kernel_vsid(PAGE_OFFSET);
        unsigned long stabreal;
 
        asm volatile("isync; slbia; isync":::"memory");
-       make_ste(stab, GET_ESID(KERNELBASE), vsid);
+       make_ste(stab, GET_ESID(PAGE_OFFSET), vsid);
 
        /* Order update */
        asm volatile("sync":::"memory");
index 859d29a0cac5c58c53752efd0df59477c14ea2ef..bb3afb6e631778f64e0ccb8dc6d1801b5ac3ea60 100644 (file)
@@ -168,7 +168,7 @@ void hpte_update(struct mm_struct *mm, unsigned long addr,
                batch->mm = mm;
                batch->psize = psize;
        }
-       if (addr < KERNELBASE) {
+       if (!is_kernel_addr(addr)) {
                vsid = get_vsid(mm->context.id, addr);
                WARN_ON(vsid == 0);
        } else
index 0782d0cca89cb9e6db24244d5fa83dc23835f7b6..554cd7c75321b0be99bfb53d44f363ebefb9e691 100644 (file)
@@ -9,3 +9,4 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
 oprofile-y := $(DRIVER_OBJS) common.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
+oprofile-$(CONFIG_PPC32) += op_model_7450.o
index af2c05d20ba57aaf3c39e06da889f97ad974c403..71615eb70b2be53975e6c83bca0665107ed6bc48 100644 (file)
@@ -14,9 +14,6 @@
  */
 
 #include <linux/oprofile.h>
-#ifndef __powerpc64__
-#include <linux/slab.h>
-#endif /* ! __powerpc64__ */
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/errno.h>
@@ -31,10 +28,6 @@ static struct op_powerpc_model *model;
 static struct op_counter_config ctr[OP_MAX_COUNTER];
 static struct op_system_config sys;
 
-#ifndef __powerpc64__
-static char *cpu_type;
-#endif /* ! __powerpc64__ */
-
 static void op_handle_interrupt(struct pt_regs *regs)
 {
        model->handle_interrupt(regs, ctr);
@@ -53,14 +46,7 @@ static int op_powerpc_setup(void)
        model->reg_setup(ctr, &sys, model->num_counters);
 
        /* Configure the registers on all cpus.  */
-#ifdef __powerpc64__
        on_each_cpu(model->cpu_setup, NULL, 0, 1);
-#else /* __powerpc64__ */
-#if 0
-       /* FIXME: Make multi-cpu work */
-       on_each_cpu(model->reg_setup, NULL, 0, 1);
-#endif
-#endif /* __powerpc64__ */
 
        return 0;
 }
@@ -95,7 +81,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
 {
        int i;
 
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
        /*
         * There is one mmcr0, mmcr1 and mmcra for setting the events for
         * all of the counters.
@@ -103,7 +89,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
        oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0);
        oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1);
        oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra);
-#endif /* __powerpc64__ */
+#endif
 
        for (i = 0; i < model->num_counters; ++i) {
                struct dentry *dir;
@@ -115,65 +101,68 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
                oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
                oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
                oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
-#ifdef __powerpc64__
+
                /*
-                * We dont support per counter user/kernel selection, but
-                * we leave the entries because userspace expects them
+                * Classic PowerPC doesn't support per-counter
+                * control like this, but the options are
+                * expected, so they remain.  For Freescale
+                * Book-E style performance monitors, we do
+                * support them.
                 */
-#endif /* __powerpc64__ */
                oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
                oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
 
-#ifndef __powerpc64__
-               /* FIXME: Not sure if this is used */
-#endif /* ! __powerpc64__ */
                oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
        }
 
        oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
        oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
        oprofilefs_create_ulong(sb, root, "backtrace_spinlocks",
                                &sys.backtrace_spinlocks);
-#endif /* __powerpc64__ */
+#endif
 
        /* Default to tracing both kernel and user */
        sys.enable_kernel = 1;
        sys.enable_user = 1;
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
        /* Turn on backtracing through spinlocks by default */
        sys.backtrace_spinlocks = 1;
-#endif /* __powerpc64__ */
+#endif
 
        return 0;
 }
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-#ifndef __powerpc64__
-#ifdef CONFIG_FSL_BOOKE
-       model = &op_model_fsl_booke;
+       if (!cur_cpu_spec->oprofile_cpu_type)
+               return -ENODEV;
+
+       switch (cur_cpu_spec->oprofile_type) {
+#ifdef CONFIG_PPC64
+               case RS64:
+                       model = &op_model_rs64;
+                       break;
+               case POWER4:
+                       model = &op_model_power4;
+                       break;
 #else
-       return -ENODEV;
+               case G4:
+                       model = &op_model_7450;
+                       break;
 #endif
+#ifdef CONFIG_FSL_BOOKE
+               case BOOKE:
+                       model = &op_model_fsl_booke;
+                       break;
+#endif
+               default:
+                       return -ENODEV;
+       }
 
-       cpu_type = kmalloc(32, GFP_KERNEL);
-       if (NULL == cpu_type)
-               return -ENOMEM;
-
-       sprintf(cpu_type, "ppc/%s", cur_cpu_spec->cpu_name);
-
-       model->num_counters = cur_cpu_spec->num_pmcs;
-
-       ops->cpu_type = cpu_type;
-#else /* __powerpc64__ */
-       if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type)
-               return -ENODEV;
-       model = cur_cpu_spec->oprofile_model;
        model->num_counters = cur_cpu_spec->num_pmcs;
 
        ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
-#endif /* __powerpc64__ */
        ops->create_files = op_powerpc_create_files;
        ops->setup = op_powerpc_setup;
        ops->shutdown = op_powerpc_shutdown;
@@ -188,8 +177,4 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
 
 void oprofile_arch_exit(void)
 {
-#ifndef __powerpc64__
-       kfree(cpu_type);
-       cpu_type = NULL;
-#endif /* ! __powerpc64__ */
 }
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
new file mode 100644 (file)
index 0000000..32abfdb
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * oprofile/op_model_7450.c
+ *
+ * Freescale 745x/744x oprofile support, based on fsl_booke support
+ * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala <galak@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/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/page.h>
+#include <asm/pmc.h>
+#include <asm/oprofile_impl.h>
+
+static unsigned long reset_value[OP_MAX_COUNTER];
+
+static int oprofile_running;
+static u32 mmcr0_val, mmcr1_val, mmcr2_val;
+
+#define MMCR0_PMC1_SHIFT       6
+#define MMCR0_PMC2_SHIFT       0
+#define MMCR1_PMC3_SHIFT       27
+#define MMCR1_PMC4_SHIFT       22
+#define MMCR1_PMC5_SHIFT       17
+#define MMCR1_PMC6_SHIFT       11
+
+#define mmcr0_event1(event) \
+       ((event << MMCR0_PMC1_SHIFT) & MMCR0_PMC1SEL)
+#define mmcr0_event2(event) \
+       ((event << MMCR0_PMC2_SHIFT) & MMCR0_PMC2SEL)
+
+#define mmcr1_event3(event) \
+       ((event << MMCR1_PMC3_SHIFT) & MMCR1_PMC3SEL)
+#define mmcr1_event4(event) \
+       ((event << MMCR1_PMC4_SHIFT) & MMCR1_PMC4SEL)
+#define mmcr1_event5(event) \
+       ((event << MMCR1_PMC5_SHIFT) & MMCR1_PMC5SEL)
+#define mmcr1_event6(event) \
+       ((event << MMCR1_PMC6_SHIFT) & MMCR1_PMC6SEL)
+
+#define MMCR0_INIT (MMCR0_FC | MMCR0_FCS | MMCR0_FCP | MMCR0_FCM1 | MMCR0_FCM0)
+
+/* Unfreezes the counters on this CPU, enables the interrupt,
+ * enables the counters to trigger the interrupt, and sets the
+ * counters to only count when the mark bit is not set.
+ */
+static void pmc_start_ctrs(void)
+{
+       u32 mmcr0 = mfspr(SPRN_MMCR0);
+
+       mmcr0 &= ~(MMCR0_FC | MMCR0_FCM0);
+       mmcr0 |= (MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE);
+
+       mtspr(SPRN_MMCR0, mmcr0);
+}
+
+/* Disables the counters on this CPU, and freezes them */
+static void pmc_stop_ctrs(void)
+{
+       u32 mmcr0 = mfspr(SPRN_MMCR0);
+
+       mmcr0 |= MMCR0_FC;
+       mmcr0 &= ~(MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE);
+
+       mtspr(SPRN_MMCR0, mmcr0);
+}
+
+/* Configures the counters on this CPU based on the global
+ * settings */
+static void fsl7450_cpu_setup(void *unused)
+{
+       /* freeze all counters */
+       pmc_stop_ctrs();
+
+       mtspr(SPRN_MMCR0, mmcr0_val);
+       mtspr(SPRN_MMCR1, mmcr1_val);
+       mtspr(SPRN_MMCR2, mmcr2_val);
+}
+
+#define NUM_CTRS 6
+
+/* Configures the global settings for the countes on all CPUs. */
+static void fsl7450_reg_setup(struct op_counter_config *ctr,
+                            struct op_system_config *sys,
+                            int num_ctrs)
+{
+       int i;
+
+       /* 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
+        * which will give us "count" until overflow.
+        * Then we set the events on the enabled counters */
+       for (i = 0; i < NUM_CTRS; ++i)
+               reset_value[i] = 0x80000000UL - ctr[i].count;
+
+       /* Set events for Counters 1 & 2 */
+       mmcr0_val = MMCR0_INIT | mmcr0_event1(ctr[0].event)
+               | mmcr0_event2(ctr[1].event);
+
+       /* Setup user/kernel bits */
+       if (sys->enable_kernel)
+               mmcr0_val &= ~(MMCR0_FCS);
+
+       if (sys->enable_user)
+               mmcr0_val &= ~(MMCR0_FCP);
+
+       /* Set events for Counters 3-6 */
+       mmcr1_val = mmcr1_event3(ctr[2].event)
+               | mmcr1_event4(ctr[3].event)
+               | mmcr1_event5(ctr[4].event)
+               | mmcr1_event6(ctr[5].event);
+
+       mmcr2_val = 0;
+}
+
+/* Sets the counters on this CPU to the chosen values, and starts them */
+static void fsl7450_start(struct op_counter_config *ctr)
+{
+       int i;
+
+       mtmsr(mfmsr() | MSR_PMM);
+
+       for (i = 0; i < NUM_CTRS; ++i) {
+               if (ctr[i].enabled)
+                       ctr_write(i, reset_value[i]);
+               else
+                       ctr_write(i, 0);
+       }
+
+       /* Clear the freeze bit, and enable the interrupt.
+        * The counters won't actually start until the rfi clears
+        * the PMM bit */
+       pmc_start_ctrs();
+
+       oprofile_running = 1;
+}
+
+/* Stop the counters on this CPU */
+static void fsl7450_stop(void)
+{
+       /* freeze counters */
+       pmc_stop_ctrs();
+
+       oprofile_running = 0;
+
+       mb();
+}
+
+
+/* Handle the interrupt on this CPU, and log a sample for each
+ * event that triggered the interrupt */
+static void fsl7450_handle_interrupt(struct pt_regs *regs,
+                                   struct op_counter_config *ctr)
+{
+       unsigned long pc;
+       int is_kernel;
+       int val;
+       int i;
+
+       /* set the PMM bit (see comment below) */
+       mtmsr(mfmsr() | MSR_PMM);
+
+       pc = mfspr(SPRN_SIAR);
+       is_kernel = (pc >= KERNELBASE);
+
+       for (i = 0; i < NUM_CTRS; ++i) {
+               val = ctr_read(i);
+               if (val < 0) {
+                       if (oprofile_running && ctr[i].enabled) {
+                               oprofile_add_pc(pc, is_kernel, i);
+                               ctr_write(i, reset_value[i]);
+                       } else {
+                               ctr_write(i, 0);
+                       }
+               }
+       }
+
+       /* 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 */
+       pmc_start_ctrs();
+}
+
+struct op_powerpc_model op_model_7450= {
+       .reg_setup              = fsl7450_reg_setup,
+       .cpu_setup              = fsl7450_cpu_setup,
+       .start                  = fsl7450_start,
+       .stop                   = fsl7450_stop,
+       .handle_interrupt       = fsl7450_handle_interrupt,
+};
index a3401b46f3bab2f6da3f6aaa701d1a249320ac00..659a021da0c7b35ab9005c57dd981fce81f04996 100644 (file)
@@ -252,7 +252,7 @@ static unsigned long get_pc(struct pt_regs *regs)
                return (unsigned long)__va(pc);
 
        /* Not sure where we were */
-       if (pc < KERNELBASE)
+       if (!is_kernel_addr(pc))
                /* function descriptor madness */
                return *((unsigned long *)kernel_unknown_bucket);
 
@@ -264,7 +264,7 @@ static int get_kernel(unsigned long pc)
        int is_kernel;
 
        if (!mmcra_has_sihv) {
-               is_kernel = (pc >= KERNELBASE);
+               is_kernel = is_kernel_addr(pc);
        } else {
                unsigned long mmcra = mfspr(SPRN_MMCRA);
                is_kernel = ((mmcra & MMCRA_SIPR) == 0);
index e010b85996e87d7f08db8d991e055ab2be6b3eae..5c909ee609feb1b8daf9cf5722c4ecb4ead8379b 100644 (file)
@@ -178,7 +178,6 @@ static void rs64_handle_interrupt(struct pt_regs *regs,
        int val;
        int i;
        unsigned long pc = mfspr(SPRN_SIAR);
-       int is_kernel = (pc >= KERNELBASE);
 
        /* set the PMM bit (see comment below) */
        mtmsrd(mfmsr() | MSR_PMM);
@@ -187,7 +186,7 @@ static void rs64_handle_interrupt(struct pt_regs *regs,
                val = ctr_read(i);
                if (val < 0) {
                        if (ctr[i].enabled) {
-                               oprofile_add_pc(pc, is_kernel, i);
+                               oprofile_add_pc(pc, is_kernel_addr(pc), i);
                                ctr_write(i, reset_value[i]);
                        } else {
                                ctr_write(i, 0);
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
new file mode 100644 (file)
index 0000000..3157071
--- /dev/null
@@ -0,0 +1,13 @@
+menu "Cell Broadband Engine options"
+       depends on PPC_CELL
+
+config SPU_FS
+       tristate "SPU file system"
+       default m
+       depends on PPC_CELL
+       help
+         The SPU file system is used to access Synergistic Processing
+         Units on machines implementing the Broadband Processor
+         Architecture.
+
+endmenu
index 55e094b96bc0bbe8e1c1d3914762a3928e00371d..16031b565be4d2c0c7ba91fba9404dbc297e15bc 100644 (file)
@@ -1,2 +1,10 @@
 obj-y                  += interrupt.o iommu.o setup.o spider-pic.o
+obj-y                  += pervasive.o
+
 obj-$(CONFIG_SMP)      += smp.o
+obj-$(CONFIG_SPU_FS)   += spufs/ spu-base.o
+
+spu-base-y             += spu_base.o spu_priv1.o
+
+builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o
+obj-y                  += $(builtin-spufs-m)
index 7fbe78a9327db993b5e386ab1d6f8f760852d917..63aa52acf4412171a483e588d70e65080672930a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/types.h>
 
@@ -55,6 +56,7 @@ struct iic_regs {
 
 struct iic {
        struct iic_regs __iomem *regs;
+       u8 target_id;
 };
 
 static DEFINE_PER_CPU(struct iic, iic);
@@ -172,12 +174,11 @@ int iic_get_irq(struct pt_regs *regs)
        return irq;
 }
 
-static struct iic_regs __iomem *find_iic(int cpu)
+static int setup_iic(int cpu, struct iic *iic)
 {
        struct device_node *np;
        int nodeid = cpu / 2;
        unsigned long regs;
-       struct iic_regs __iomem *iic_regs;
 
        for (np = of_find_node_by_type(NULL, "cpu");
             np;
@@ -188,20 +189,23 @@ static struct iic_regs __iomem *find_iic(int cpu)
 
        if (!np) {
                printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
-               iic_regs = NULL;
-       } else {
-               regs = *(long *)get_property(np, "iic", NULL);
-
-               /* hack until we have decided on the devtree info */
-               regs += 0x400;
-               if (cpu & 1)
-                       regs += 0x20;
-
-               printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
-               iic_regs = __ioremap(regs, sizeof(struct iic_regs),
-                                                _PAGE_NO_CACHE);
+               iic->regs = NULL;
+               iic->target_id = 0xff;
+               return -ENODEV;
        }
-       return iic_regs;
+
+       regs = *(long *)get_property(np, "iic", NULL);
+
+       /* hack until we have decided on the devtree info */
+       regs += 0x400;
+       if (cpu & 1)
+               regs += 0x20;
+
+       printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
+       iic->regs = __ioremap(regs, sizeof(struct iic_regs),
+                                        _PAGE_NO_CACHE);
+       iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
+       return 0;
 }
 
 #ifdef CONFIG_SMP
@@ -227,6 +231,12 @@ void iic_cause_IPI(int cpu, int mesg)
        out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
 }
 
+u8 iic_get_target_id(int cpu)
+{
+       return per_cpu(iic, cpu).target_id;
+}
+EXPORT_SYMBOL_GPL(iic_get_target_id);
+
 static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
 {
        smp_message_recv(iic_irq_to_ipi(irq), regs);
@@ -276,7 +286,7 @@ void iic_init_IRQ(void)
        irq_offset = 0;
        for_each_cpu(cpu) {
                iic = &per_cpu(iic, cpu);
-               iic->regs = find_iic(cpu);
+               setup_iic(cpu, iic);
                if (iic->regs)
                        out_be64(&iic->regs->prio, 0xff);
        }
index 37d58e6fd0c6c4f17e14166ec63e29e306df1328..a14bd38791c01f1c3e1f37f5d2a083c251c3e472 100644 (file)
@@ -54,6 +54,7 @@ extern void iic_setup_cpu(void);
 extern void iic_local_enable(void);
 extern void iic_local_disable(void);
 
+extern u8 iic_get_target_id(int cpu);
 
 extern void spider_init_IRQ(void);
 extern int spider_get_irq(unsigned long int_pending);
index 74f999b4ac9e782cbdee477457681b6de4e3639f..46e7cb9c3e648ec0fc7cde3b19f30406728b8b75 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/bootmem.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
 
 #include <asm/sections.h>
 #include <asm/iommu.h>
@@ -40,6 +42,7 @@
 #include <asm/abs_addr.h>
 #include <asm/system.h>
 #include <asm/ppc-pci.h>
+#include <asm/udbg.h>
 
 #include "iommu.h"
 
@@ -220,8 +223,6 @@ set_iopt_cache(void __iomem *base, unsigned long index,
 {
        unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR;
        unsigned long __iomem *p = base + IOC_PT_CACHE_REG;
-       pr_debug("iopt %02lx was v%016lx/t%016lx, store v%016lx/t%016lx\n",
-               index, get_iopt_cache(base, index, &oldtag), oldtag, val, tag);
 
        out_be64(p, val);
        out_be64(&tags[index], tag);
@@ -248,67 +249,176 @@ set_iocmd_config(void __iomem *base)
        out_be64(p, conf | IOCMD_CONF_TE);
 }
 
-/* FIXME: get these from the device tree */
-#define ioc_base       0x20000511000ull
-#define ioc_mmio_base  0x20000510000ull
-#define ioid           0x48a
-#define iopt_phys_offset (- 0x20000000) /* We have a 512MB offset from the SB */
-#define io_page_size   0x1000000
-
-static unsigned long map_iopt_entry(unsigned long address)
+static void enable_mapping(void __iomem *base, void __iomem *mmio_base)
 {
-       switch (address >> 20) {
-       case 0x600:
-               address = 0x24020000000ull; /* spider i/o */
-               break;
-       default:
-               address += iopt_phys_offset;
-               break;
-       }
-
-       return get_iopt_entry(address, ioid, IOPT_PROT_RW);
+       set_iocmd_config(base);
+       set_iost_origin(mmio_base);
 }
 
-static void iommu_bus_setup_null(struct pci_bus *b) { }
 static void iommu_dev_setup_null(struct pci_dev *d) { }
+static void iommu_bus_setup_null(struct pci_bus *b) { }
+
+struct cell_iommu {
+       unsigned long base;
+       unsigned long mmio_base;
+       void __iomem *mapped_base;
+       void __iomem *mapped_mmio_base;
+};
+
+static struct cell_iommu cell_iommus[NR_CPUS];
 
 /* initialize the iommu to support a simple linear mapping
  * for each DMA window used by any device. For now, we
  * happen to know that there is only one DMA window in use,
  * starting at iopt_phys_offset. */
-static void cell_map_iommu(void)
+static void cell_do_map_iommu(struct cell_iommu *iommu,
+                             unsigned int ioid,
+                             unsigned long map_start,
+                             unsigned long map_size)
 {
-       unsigned long address;
-       void __iomem *base;
+       unsigned long io_address, real_address;
+       void __iomem *ioc_base, *ioc_mmio_base;
        ioste ioste;
        unsigned long index;
 
-       base = __ioremap(ioc_base, 0x1000, _PAGE_NO_CACHE);
-       pr_debug("%lx mapped to %p\n", ioc_base, base);
-       set_iocmd_config(base);
-       iounmap(base);
+       /* we pretend the io page table was at a very high address */
+       const unsigned long fake_iopt = 0x10000000000ul;
+       const unsigned long io_page_size = 0x1000000; /* use 16M pages */
+       const unsigned long io_segment_size = 0x10000000; /* 256M */
+
+       ioc_base = iommu->mapped_base;
+       ioc_mmio_base = iommu->mapped_mmio_base;
+
+       for (real_address = 0, io_address = 0;
+            io_address <= map_start + map_size;
+            real_address += io_page_size, io_address += io_page_size) {
+               ioste = get_iost_entry(fake_iopt, io_address, io_page_size);
+               if ((real_address % io_segment_size) == 0) /* segment start */
+                       set_iost_cache(ioc_mmio_base,
+                                      io_address >> 28, ioste);
+               index = get_ioc_hash_1way(ioste, io_address);
+               pr_debug("addr %08lx, index %02lx, ioste %016lx\n",
+                                        io_address, index, ioste.val);
+               set_iopt_cache(ioc_mmio_base,
+                       get_ioc_hash_1way(ioste, io_address),
+                       get_ioc_tag(ioste, io_address),
+                       get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW));
+       }
+}
 
-       base = __ioremap(ioc_mmio_base, 0x1000, _PAGE_NO_CACHE);
-       pr_debug("%lx mapped to %p\n", ioc_mmio_base, base);
+static void iommu_devnode_setup(struct device_node *d)
+{
+       unsigned int *ioid;
+       unsigned long *dma_window, map_start, map_size, token;
+       struct cell_iommu *iommu;
 
-       set_iost_origin(base);
+       ioid = (unsigned int *)get_property(d, "ioid", NULL);
+       if (!ioid)
+               pr_debug("No ioid entry found !\n");
 
-       for (address = 0; address < 0x100000000ul; address += io_page_size) {
-               ioste = get_iost_entry(0x10000000000ul, address, io_page_size);
-               if ((address & 0xfffffff) == 0) /* segment start */
-                       set_iost_cache(base, address >> 28, ioste);
-               index = get_ioc_hash_1way(ioste, address);
-               pr_debug("addr %08lx, index %02lx, ioste %016lx\n",
-                                        address, index, ioste.val);
-               set_iopt_cache(base,
-                       get_ioc_hash_1way(ioste, address),
-                       get_ioc_tag(ioste, address),
-                       map_iopt_entry(address));
-       }
-       iounmap(base);
+       dma_window = (unsigned long *)get_property(d, "ibm,dma-window", NULL);
+       if (!dma_window)
+               pr_debug("No ibm,dma-window entry found !\n");
+
+       map_start = dma_window[1];
+       map_size = dma_window[2];
+       token = dma_window[0] >> 32;
+
+       iommu = &cell_iommus[token];
+
+       cell_do_map_iommu(iommu, *ioid, map_start, map_size);
+}
+
+static void iommu_bus_setup(struct pci_bus *b)
+{
+       struct device_node *d = (struct device_node *)b->sysdata;
+       iommu_devnode_setup(d);
+}
+
+
+static int cell_map_iommu_hardcoded(int num_nodes)
+{
+       struct cell_iommu *iommu = NULL;
+
+       pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
+
+       /* node 0 */
+       iommu = &cell_iommus[0];
+       iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE);
+       iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE);
+
+       enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+       cell_do_map_iommu(iommu, 0x048a,
+                         0x20000000ul,0x20000000ul);
+
+       if (num_nodes < 2)
+               return 0;
+
+       /* node 1 */
+       iommu = &cell_iommus[1];
+       iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE);
+       iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE);
+
+       enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+       cell_do_map_iommu(iommu, 0x048a,
+                         0x20000000,0x20000000ul);
+
+       return 0;
 }
 
 
+static int cell_map_iommu(void)
+{
+       unsigned int num_nodes = 0, *node_id;
+       unsigned long *base, *mmio_base;
+       struct device_node *dn;
+       struct cell_iommu *iommu = NULL;
+
+       /* determine number of nodes (=iommus) */
+       pr_debug("%s(%d): determining number of nodes...", __FUNCTION__, __LINE__);
+       for(dn = of_find_node_by_type(NULL, "cpu");
+           dn;
+           dn = of_find_node_by_type(dn, "cpu")) {
+               node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+
+               if (num_nodes < *node_id)
+                       num_nodes = *node_id;
+               }
+
+       num_nodes++;
+       pr_debug("%i found.\n", num_nodes);
+
+       /* map the iommu registers for each node */
+       pr_debug("%s(%d): Looping through nodes\n", __FUNCTION__, __LINE__);
+       for(dn = of_find_node_by_type(NULL, "cpu");
+           dn;
+           dn = of_find_node_by_type(dn, "cpu")) {
+
+               node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+               base = (unsigned long *)get_property(dn, "ioc-cache", NULL);
+               mmio_base = (unsigned long *)get_property(dn, "ioc-translation", NULL);
+
+               if (!base || !mmio_base || !node_id)
+                       return cell_map_iommu_hardcoded(num_nodes);
+
+               iommu = &cell_iommus[*node_id];
+               iommu->base = *base;
+               iommu->mmio_base = *mmio_base;
+
+               iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE);
+               iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE);
+
+               enable_mapping(iommu->mapped_base,
+                              iommu->mapped_mmio_base);
+
+               /* everything else will be done in iommu_bus_setup */
+       }
+
+       return 1;
+}
+
 static void *cell_alloc_coherent(struct device *hwdev, size_t size,
                           dma_addr_t *dma_handle, gfp_t flag)
 {
@@ -365,11 +475,28 @@ static int cell_dma_supported(struct device *dev, u64 mask)
 
 void cell_init_iommu(void)
 {
-       cell_map_iommu();
-
-       /* Direct I/O, IOMMU off */
-       ppc_md.iommu_dev_setup = iommu_dev_setup_null;
-       ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+       int setup_bus = 0;
+
+       if (of_find_node_by_path("/mambo")) {
+               pr_info("Not using iommu on systemsim\n");
+       } else {
+
+               if (!(of_chosen &&
+                     get_property(of_chosen, "linux,iommu-off", NULL)))
+                       setup_bus = cell_map_iommu();
+
+               if (setup_bus) {
+                       pr_debug("%s: IOMMU mapping activated\n", __FUNCTION__);
+                       ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+                       ppc_md.iommu_bus_setup = iommu_bus_setup;
+               } else {
+                       pr_debug("%s: IOMMU mapping activated, "
+                                "no device action necessary\n", __FUNCTION__);
+                       /* Direct I/O, IOMMU off */
+                       ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+                       ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+               }
+       }
 
        pci_dma_ops.alloc_coherent = cell_alloc_coherent;
        pci_dma_ops.free_coherent = cell_free_coherent;
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
new file mode 100644 (file)
index 0000000..8515254
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * CBE Pervasive Monitor and Debug
+ *
+ * (C) Copyright IBM Corporation 2005
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ *          Michael N. Day (mnday@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, 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.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+#include <linux/kallsyms.h>
+
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/reg.h>
+
+#include "pervasive.h"
+
+static DEFINE_SPINLOCK(cbe_pervasive_lock);
+struct cbe_pervasive {
+       struct pmd_regs __iomem *regs;
+       unsigned int thread;
+};
+
+/* can't use per_cpu from setup_arch */
+static struct cbe_pervasive cbe_pervasive[NR_CPUS];
+
+static void __init cbe_enable_pause_zero(void)
+{
+       unsigned long thread_switch_control;
+       unsigned long temp_register;
+       struct cbe_pervasive *p;
+       int thread;
+
+       spin_lock_irq(&cbe_pervasive_lock);
+       p = &cbe_pervasive[smp_processor_id()];
+
+       if (!cbe_pervasive->regs)
+               goto out;
+
+       pr_debug("Power Management: CPU %d\n", smp_processor_id());
+
+        /* Enable Pause(0) control bit */
+       temp_register = in_be64(&p->regs->pm_control);
+
+       out_be64(&p->regs->pm_control,
+                temp_register|PMD_PAUSE_ZERO_CONTROL);
+
+       /* Enable DEC and EE interrupt request */
+       thread_switch_control  = mfspr(SPRN_TSC_CELL);
+       thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
+
+       switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
+       case CTRL_CT0:
+               thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
+               thread = 0;
+               break;
+       case CTRL_CT1:
+               thread_switch_control |= TSC_CELL_DEC_ENABLE_1;
+               thread = 1;
+               break;
+       default:
+               printk(KERN_WARNING "%s: unknown configuration\n",
+                       __FUNCTION__);
+               thread = -1;
+               break;
+       }
+
+       if (p->thread != thread)
+               printk(KERN_WARNING "%s: device tree inconsistant, "
+                                    "cpu %i: %d/%d\n", __FUNCTION__,
+                                    smp_processor_id(),
+                                    p->thread, thread);
+
+       mtspr(SPRN_TSC_CELL, thread_switch_control);
+
+out:
+       spin_unlock_irq(&cbe_pervasive_lock);
+}
+
+static void cbe_idle(void)
+{
+       unsigned long ctrl;
+
+       cbe_enable_pause_zero();
+
+       while (1) {
+               if (!need_resched()) {
+                       local_irq_disable();
+                       while (!need_resched()) {
+                               /* go into low thread priority */
+                               HMT_low();
+
+                               /*
+                                * atomically disable thread execution
+                                * and runlatch.
+                                * External and Decrementer exceptions
+                                * are still handled when the thread
+                                * is disabled but now enter in
+                                * cbe_system_reset_exception()
+                                */
+                               ctrl = mfspr(SPRN_CTRLF);
+                               ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
+                               mtspr(SPRN_CTRLT, ctrl);
+                       }
+                       /* restore thread prio */
+                       HMT_medium();
+                       local_irq_enable();
+               }
+
+               /*
+                * turn runlatch on again before scheduling the
+                * process we just woke up
+                */
+               ppc64_runlatch_on();
+
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
+}
+
+int cbe_system_reset_exception(struct pt_regs *regs)
+{
+       switch (regs->msr & SRR1_WAKEMASK) {
+       case SRR1_WAKEEE:
+               do_IRQ(regs);
+               break;
+       case SRR1_WAKEDEC:
+               timer_interrupt(regs);
+               break;
+       case SRR1_WAKEMT:
+               /* no action required */
+               break;
+       default:
+               /* do system reset */
+               return 0;
+       }
+       /* everything handled */
+       return 1;
+}
+
+static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p)
+{
+       struct device_node *node;
+       unsigned int *int_servers;
+       char *addr;
+       unsigned long real_address;
+       unsigned int size;
+
+       struct pmd_regs __iomem *pmd_mmio_area;
+       int hardid, thread;
+       int proplen;
+
+       pmd_mmio_area = NULL;
+       hardid = get_hard_smp_processor_id(cpu);
+       for (node = NULL; (node = of_find_node_by_type(node, "cpu"));) {
+               int_servers = (void *) get_property(node,
+                               "ibm,ppc-interrupt-server#s", &proplen);
+               if (!int_servers) {
+                       printk(KERN_WARNING "%s misses "
+                               "ibm,ppc-interrupt-server#s property",
+                               node->full_name);
+                       continue;
+               }
+               for (thread = 0; thread < proplen / sizeof (int); thread++) {
+                       if (hardid == int_servers[thread]) {
+                               addr = get_property(node, "pervasive", NULL);
+                               goto found;
+                       }
+               }
+       }
+
+       printk(KERN_WARNING "%s: CPU %d not found\n", __FUNCTION__, cpu);
+       return -EINVAL;
+
+found:
+       real_address = *(unsigned long*) addr;
+       addr += sizeof (unsigned long);
+       size = *(unsigned int*) addr;
+
+       pr_debug("pervasive area for CPU %d at %lx, size %x\n",
+                       cpu, real_address, size);
+       p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE);
+       p->thread = thread;
+       return 0;
+}
+
+void __init cell_pervasive_init(void)
+{
+       struct cbe_pervasive *p;
+       int cpu;
+       int ret;
+
+       if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
+               return;
+
+       for_each_cpu(cpu) {
+               p = &cbe_pervasive[cpu];
+               ret = cbe_find_pmd_mmio(cpu, p);
+               if (ret)
+                       return;
+       }
+
+       ppc_md.idle_loop = cbe_idle;
+       ppc_md.system_reset_exception = cbe_system_reset_exception;
+}
diff --git a/arch/powerpc/platforms/cell/pervasive.h b/arch/powerpc/platforms/cell/pervasive.h
new file mode 100644 (file)
index 0000000..da1fb85
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Cell Pervasive Monitor and Debug interface and HW structures
+ *
+ * (C) Copyright IBM Corporation 2005
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ *          David J. Erb (djerb@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, 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 PERVASIVE_H
+#define PERVASIVE_H
+
+struct pmd_regs {
+       u8 pad_0x0000_0x0800[0x0800 - 0x0000];                  /* 0x0000 */
+
+       /* Thermal Sensor Registers */
+       u64  ts_ctsr1;                                          /* 0x0800 */
+       u64  ts_ctsr2;                                          /* 0x0808 */
+       u64  ts_mtsr1;                                          /* 0x0810 */
+       u64  ts_mtsr2;                                          /* 0x0818 */
+       u64  ts_itr1;                                           /* 0x0820 */
+       u64  ts_itr2;                                           /* 0x0828 */
+       u64  ts_gitr;                                           /* 0x0830 */
+       u64  ts_isr;                                            /* 0x0838 */
+       u64  ts_imr;                                            /* 0x0840 */
+       u64  tm_cr1;                                            /* 0x0848 */
+       u64  tm_cr2;                                            /* 0x0850 */
+       u64  tm_simr;                                           /* 0x0858 */
+       u64  tm_tpr;                                            /* 0x0860 */
+       u64  tm_str1;                                           /* 0x0868 */
+       u64  tm_str2;                                           /* 0x0870 */
+       u64  tm_tsr;                                            /* 0x0878 */
+
+       /* Power Management */
+       u64  pm_control;                                        /* 0x0880 */
+#define PMD_PAUSE_ZERO_CONTROL         0x10000
+       u64  pm_status;                                         /* 0x0888 */
+
+       /* Time Base Register */
+       u64  tbr;                                               /* 0x0890 */
+
+       u8   pad_0x0898_0x1000 [0x1000 - 0x0898];               /* 0x0898 */
+};
+
+void __init cell_pervasive_init(void);
+
+#endif
index 9a495634d0c238aeaef80aa3b675dc5a3ef3f8e8..18e25e65c04b23ba2ec87328ba68ba4b97f40eae 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/mmu.h>
 #include <asm/processor.h>
 #include <asm/io.h>
+#include <asm/kexec.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -48,6 +49,7 @@
 
 #include "interrupt.h"
 #include "iommu.h"
+#include "pervasive.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -67,6 +69,77 @@ void cell_show_cpuinfo(struct seq_file *m)
        of_node_put(root);
 }
 
+#ifdef CONFIG_SPARSEMEM
+static int __init find_spu_node_id(struct device_node *spe)
+{
+       unsigned int *id;
+#ifdef CONFIG_NUMA
+       struct device_node *cpu;
+       cpu = spe->parent->parent;
+       id = (unsigned int *)get_property(cpu, "node-id", NULL);
+#else
+       id = NULL;
+#endif
+       return id ? *id : 0;
+}
+
+static void __init cell_spuprop_present(struct device_node *spe,
+                                      const char *prop, int early)
+{
+       struct address_prop {
+               unsigned long address;
+               unsigned int len;
+       } __attribute__((packed)) *p;
+       int proplen;
+
+       unsigned long start_pfn, end_pfn, pfn;
+       int node_id;
+
+       p = (void*)get_property(spe, prop, &proplen);
+       WARN_ON(proplen != sizeof (*p));
+
+       node_id = find_spu_node_id(spe);
+
+       start_pfn = p->address >> PAGE_SHIFT;
+       end_pfn = (p->address + p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+       /* We need to call memory_present *before* the call to sparse_init,
+          but we can initialize the page structs only *after* that call.
+          Thus, we're being called twice. */
+       if (early)
+               memory_present(node_id, start_pfn, end_pfn);
+       else {
+               /* As the pages backing SPU LS and I/O are outside the range
+                  of regular memory, their page structs were not initialized
+                  by free_area_init. Do it here instead. */
+               for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+                       struct page *page = pfn_to_page(pfn);
+                       set_page_links(page, ZONE_DMA, node_id, pfn);
+                       set_page_count(page, 1);
+                       reset_page_mapcount(page);
+                       SetPageReserved(page);
+                       INIT_LIST_HEAD(&page->lru);
+               }
+       }
+}
+
+static void __init cell_spumem_init(int early)
+{
+       struct device_node *node;
+       for (node = of_find_node_by_type(NULL, "spe");
+                       node; node = of_find_node_by_type(node, "spe")) {
+               cell_spuprop_present(node, "local-store", early);
+               cell_spuprop_present(node, "problem", early);
+               cell_spuprop_present(node, "priv1", early);
+               cell_spuprop_present(node, "priv2", early);
+       }
+}
+#else
+static void __init cell_spumem_init(int early)
+{
+}
+#endif
+
 static void cell_progress(char *s, unsigned short hex)
 {
        printk("*** %04x : %s\n", hex, s ? s : "");
@@ -93,11 +166,14 @@ static void __init cell_setup_arch(void)
        init_pci_config_tokens();
        find_and_init_phbs();
        spider_init_IRQ();
+       cell_pervasive_init();
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
 #endif
 
        mmio_nvram_init();
+
+       cell_spumem_init(0);
 }
 
 /*
@@ -113,6 +189,8 @@ static void __init cell_init_early(void)
 
        ppc64_interrupt_controller = IC_CELL_PIC;
 
+       cell_spumem_init(1);
+
        DBG(" <- cell_init_early()\n");
 }
 
@@ -125,6 +203,15 @@ static int __init cell_probe(int platform)
        return 1;
 }
 
+/*
+ * Cell has no legacy IO; anything calling this function has to
+ * fail or bad things will happen
+ */
+static int cell_check_legacy_ioport(unsigned int baseport)
+{
+       return -ENODEV;
+}
+
 struct machdep_calls __initdata cell_md = {
        .probe                  = cell_probe,
        .setup_arch             = cell_setup_arch,
@@ -137,5 +224,11 @@ struct machdep_calls __initdata cell_md = {
        .get_rtc_time           = rtas_get_rtc_time,
        .set_rtc_time           = rtas_set_rtc_time,
        .calibrate_decr         = generic_calibrate_decr,
+       .check_legacy_ioport    = cell_check_legacy_ioport,
        .progress               = cell_progress,
+#ifdef CONFIG_KEXEC
+       .machine_kexec          = default_machine_kexec,
+       .machine_kexec_prepare  = default_machine_kexec_prepare,
+       .machine_crash_shutdown = default_machine_crash_shutdown,
+#endif
 };
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
new file mode 100644 (file)
index 0000000..d75ae03
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+ * Low-level SPU handling
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@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.
+ */
+
+#undef DEBUG
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/mmu_context.h>
+
+#include "interrupt.h"
+
+static int __spu_trap_invalid_dma(struct spu *spu)
+{
+       pr_debug("%s\n", __FUNCTION__);
+       force_sig(SIGBUS, /* info, */ current);
+       return 0;
+}
+
+static int __spu_trap_dma_align(struct spu *spu)
+{
+       pr_debug("%s\n", __FUNCTION__);
+       force_sig(SIGBUS, /* info, */ current);
+       return 0;
+}
+
+static int __spu_trap_error(struct spu *spu)
+{
+       pr_debug("%s\n", __FUNCTION__);
+       force_sig(SIGILL, /* info, */ current);
+       return 0;
+}
+
+static void spu_restart_dma(struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
+               out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
+}
+
+static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       struct mm_struct *mm = spu->mm;
+       u64 esid, vsid;
+
+       pr_debug("%s\n", __FUNCTION__);
+
+       if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
+               /* SLBs are pre-loaded for context switch, so
+                * we should never get here!
+                */
+               printk("%s: invalid access during switch!\n", __func__);
+               return 1;
+       }
+       if (!mm || (REGION_ID(ea) != USER_REGION_ID)) {
+               /* Future: support kernel segments so that drivers
+                * can use SPUs.
+                */
+               pr_debug("invalid region access at %016lx\n", ea);
+               return 1;
+       }
+
+       esid = (ea & ESID_MASK) | SLB_ESID_V;
+       vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | SLB_VSID_USER;
+       if (in_hugepage_area(mm->context, ea))
+               vsid |= SLB_VSID_L;
+
+       out_be64(&priv2->slb_index_W, spu->slb_replace);
+       out_be64(&priv2->slb_vsid_RW, vsid);
+       out_be64(&priv2->slb_esid_RW, esid);
+
+       spu->slb_replace++;
+       if (spu->slb_replace >= 8)
+               spu->slb_replace = 0;
+
+       spu_restart_dma(spu);
+
+       return 0;
+}
+
+extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
+static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
+{
+       pr_debug("%s\n", __FUNCTION__);
+
+       /* Handle kernel space hash faults immediately.
+          User hash faults need to be deferred to process context. */
+       if ((dsisr & MFC_DSISR_PTE_NOT_FOUND)
+           && REGION_ID(ea) != USER_REGION_ID
+           && hash_page(ea, _PAGE_PRESENT, 0x300) == 0) {
+               spu_restart_dma(spu);
+               return 0;
+       }
+
+       if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
+               printk("%s: invalid access during switch!\n", __func__);
+               return 1;
+       }
+
+       spu->dar = ea;
+       spu->dsisr = dsisr;
+       mb();
+       if (spu->stop_callback)
+               spu->stop_callback(spu);
+       return 0;
+}
+
+static int __spu_trap_mailbox(struct spu *spu)
+{
+       if (spu->ibox_callback)
+               spu->ibox_callback(spu);
+
+       /* atomically disable SPU mailbox interrupts */
+       spin_lock(&spu->register_lock);
+       spu_int_mask_and(spu, 2, ~0x1);
+       spin_unlock(&spu->register_lock);
+       return 0;
+}
+
+static int __spu_trap_stop(struct spu *spu)
+{
+       pr_debug("%s\n", __FUNCTION__);
+       spu->stop_code = in_be32(&spu->problem->spu_status_R);
+       if (spu->stop_callback)
+               spu->stop_callback(spu);
+       return 0;
+}
+
+static int __spu_trap_halt(struct spu *spu)
+{
+       pr_debug("%s\n", __FUNCTION__);
+       spu->stop_code = in_be32(&spu->problem->spu_status_R);
+       if (spu->stop_callback)
+               spu->stop_callback(spu);
+       return 0;
+}
+
+static int __spu_trap_tag_group(struct spu *spu)
+{
+       pr_debug("%s\n", __FUNCTION__);
+       /* wake_up(&spu->dma_wq); */
+       return 0;
+}
+
+static int __spu_trap_spubox(struct spu *spu)
+{
+       if (spu->wbox_callback)
+               spu->wbox_callback(spu);
+
+       /* atomically disable SPU mailbox interrupts */
+       spin_lock(&spu->register_lock);
+       spu_int_mask_and(spu, 2, ~0x10);
+       spin_unlock(&spu->register_lock);
+       return 0;
+}
+
+static irqreturn_t
+spu_irq_class_0(int irq, void *data, struct pt_regs *regs)
+{
+       struct spu *spu;
+
+       spu = data;
+       spu->class_0_pending = 1;
+       if (spu->stop_callback)
+               spu->stop_callback(spu);
+
+       return IRQ_HANDLED;
+}
+
+int
+spu_irq_class_0_bottom(struct spu *spu)
+{
+       unsigned long stat, mask;
+
+       spu->class_0_pending = 0;
+
+       mask = spu_int_mask_get(spu, 0);
+       stat = spu_int_stat_get(spu, 0);
+
+       stat &= mask;
+
+       if (stat & 1) /* invalid MFC DMA */
+               __spu_trap_invalid_dma(spu);
+
+       if (stat & 2) /* invalid DMA alignment */
+               __spu_trap_dma_align(spu);
+
+       if (stat & 4) /* error on SPU */
+               __spu_trap_error(spu);
+
+       spu_int_stat_clear(spu, 0, stat);
+
+       return (stat & 0x7) ? -EIO : 0;
+}
+EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
+
+static irqreturn_t
+spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
+{
+       struct spu *spu;
+       unsigned long stat, mask, dar, dsisr;
+
+       spu = data;
+
+       /* atomically read & clear class1 status. */
+       spin_lock(&spu->register_lock);
+       mask  = spu_int_mask_get(spu, 1);
+       stat  = spu_int_stat_get(spu, 1) & mask;
+       dar   = spu_mfc_dar_get(spu);
+       dsisr = spu_mfc_dsisr_get(spu);
+       if (stat & 2) /* mapping fault */
+               spu_mfc_dsisr_set(spu, 0ul);
+       spu_int_stat_clear(spu, 1, stat);
+       spin_unlock(&spu->register_lock);
+
+       if (stat & 1) /* segment fault */
+               __spu_trap_data_seg(spu, dar);
+
+       if (stat & 2) { /* mapping fault */
+               __spu_trap_data_map(spu, dar, dsisr);
+       }
+
+       if (stat & 4) /* ls compare & suspend on get */
+               ;
+
+       if (stat & 8) /* ls compare & suspend on put */
+               ;
+
+       return stat ? IRQ_HANDLED : IRQ_NONE;
+}
+EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
+
+static irqreturn_t
+spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
+{
+       struct spu *spu;
+       unsigned long stat;
+       unsigned long mask;
+
+       spu = data;
+       stat = spu_int_stat_get(spu, 2);
+       mask = spu_int_mask_get(spu, 2);
+
+       pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
+
+       stat &= mask;
+
+       if (stat & 1)  /* PPC core mailbox */
+               __spu_trap_mailbox(spu);
+
+       if (stat & 2) /* SPU stop-and-signal */
+               __spu_trap_stop(spu);
+
+       if (stat & 4) /* SPU halted */
+               __spu_trap_halt(spu);
+
+       if (stat & 8) /* DMA tag group complete */
+               __spu_trap_tag_group(spu);
+
+       if (stat & 0x10) /* SPU mailbox threshold */
+               __spu_trap_spubox(spu);
+
+       spu_int_stat_clear(spu, 2, stat);
+       return stat ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int
+spu_request_irqs(struct spu *spu)
+{
+       int ret;
+       int irq_base;
+
+       irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;
+
+       snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number);
+       ret = request_irq(irq_base + spu->isrc,
+                spu_irq_class_0, 0, spu->irq_c0, spu);
+       if (ret)
+               goto out;
+
+       snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
+       ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
+                spu_irq_class_1, 0, spu->irq_c1, spu);
+       if (ret)
+               goto out1;
+
+       snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number);
+       ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc,
+                spu_irq_class_2, 0, spu->irq_c2, spu);
+       if (ret)
+               goto out2;
+       goto out;
+
+out2:
+       free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu);
+out1:
+       free_irq(irq_base + spu->isrc, spu);
+out:
+       return ret;
+}
+
+static void
+spu_free_irqs(struct spu *spu)
+{
+       int irq_base;
+
+       irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;
+
+       free_irq(irq_base + spu->isrc, spu);
+       free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu);
+       free_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, spu);
+}
+
+static LIST_HEAD(spu_list);
+static DECLARE_MUTEX(spu_mutex);
+
+static void spu_init_channels(struct spu *spu)
+{
+       static const struct {
+                unsigned channel;
+                unsigned count;
+       } zero_list[] = {
+               { 0x00, 1, }, { 0x01, 1, }, { 0x03, 1, }, { 0x04, 1, },
+               { 0x18, 1, }, { 0x19, 1, }, { 0x1b, 1, }, { 0x1d, 1, },
+       }, count_list[] = {
+               { 0x00, 0, }, { 0x03, 0, }, { 0x04, 0, }, { 0x15, 16, },
+               { 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, },
+               { 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, },
+       };
+       struct spu_priv2 __iomem *priv2;
+       int i;
+
+       priv2 = spu->priv2;
+
+       /* initialize all channel data to zero */
+       for (i = 0; i < ARRAY_SIZE(zero_list); i++) {
+               int count;
+
+               out_be64(&priv2->spu_chnlcntptr_RW, zero_list[i].channel);
+               for (count = 0; count < zero_list[i].count; count++)
+                       out_be64(&priv2->spu_chnldata_RW, 0);
+       }
+
+       /* initialize channel counts to meaningful values */
+       for (i = 0; i < ARRAY_SIZE(count_list); i++) {
+               out_be64(&priv2->spu_chnlcntptr_RW, count_list[i].channel);
+               out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count);
+       }
+}
+
+struct spu *spu_alloc(void)
+{
+       struct spu *spu;
+
+       down(&spu_mutex);
+       if (!list_empty(&spu_list)) {
+               spu = list_entry(spu_list.next, struct spu, list);
+               list_del_init(&spu->list);
+               pr_debug("Got SPU %x %d\n", spu->isrc, spu->number);
+       } else {
+               pr_debug("No SPU left\n");
+               spu = NULL;
+       }
+       up(&spu_mutex);
+
+       if (spu)
+               spu_init_channels(spu);
+
+       return spu;
+}
+EXPORT_SYMBOL_GPL(spu_alloc);
+
+void spu_free(struct spu *spu)
+{
+       down(&spu_mutex);
+       list_add_tail(&spu->list, &spu_list);
+       up(&spu_mutex);
+}
+EXPORT_SYMBOL_GPL(spu_free);
+
+static int spu_handle_mm_fault(struct spu *spu)
+{
+       struct mm_struct *mm = spu->mm;
+       struct vm_area_struct *vma;
+       u64 ea, dsisr, is_write;
+       int ret;
+
+       ea = spu->dar;
+       dsisr = spu->dsisr;
+#if 0
+       if (!IS_VALID_EA(ea)) {
+               return -EFAULT;
+       }
+#endif /* XXX */
+       if (mm == NULL) {
+               return -EFAULT;
+       }
+       if (mm->pgd == NULL) {
+               return -EFAULT;
+       }
+
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, ea);
+       if (!vma)
+               goto bad_area;
+       if (vma->vm_start <= ea)
+               goto good_area;
+       if (!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+#if 0
+       if (expand_stack(vma, ea))
+               goto bad_area;
+#endif /* XXX */
+good_area:
+       is_write = dsisr & MFC_DSISR_ACCESS_PUT;
+       if (is_write) {
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       } else {
+               if (dsisr & MFC_DSISR_ACCESS_DENIED)
+                       goto bad_area;
+               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto bad_area;
+       }
+       ret = 0;
+       switch (handle_mm_fault(mm, vma, ea, is_write)) {
+       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:
+               BUG();
+       }
+       up_read(&mm->mmap_sem);
+       return ret;
+
+bad_area:
+       up_read(&mm->mmap_sem);
+       return -EFAULT;
+}
+
+int spu_irq_class_1_bottom(struct spu *spu)
+{
+       u64 ea, dsisr, access, error = 0UL;
+       int ret = 0;
+
+       ea = spu->dar;
+       dsisr = spu->dsisr;
+       if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
+               access = (_PAGE_PRESENT | _PAGE_USER);
+               access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
+               if (hash_page(ea, access, 0x300) != 0)
+                       error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
+       }
+       if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) ||
+           (dsisr & MFC_DSISR_ACCESS_DENIED)) {
+               if ((ret = spu_handle_mm_fault(spu)) != 0)
+                       error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
+               else
+                       error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
+       }
+       spu->dar = 0UL;
+       spu->dsisr = 0UL;
+       if (!error) {
+               spu_restart_dma(spu);
+       } else {
+               __spu_trap_invalid_dma(spu);
+       }
+       return ret;
+}
+
+void spu_irq_setaffinity(struct spu *spu, int cpu)
+{
+       u64 target = iic_get_target_id(cpu);
+       u64 route = target << 48 | target << 32 | target << 16;
+       spu_int_route_set(spu, route);
+}
+EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
+
+static void __iomem * __init map_spe_prop(struct device_node *n,
+                                                const char *name)
+{
+       struct address_prop {
+               unsigned long address;
+               unsigned int len;
+       } __attribute__((packed)) *prop;
+
+       void *p;
+       int proplen;
+
+       p = get_property(n, name, &proplen);
+       if (proplen != sizeof (struct address_prop))
+               return NULL;
+
+       prop = p;
+
+       return ioremap(prop->address, prop->len);
+}
+
+static void spu_unmap(struct spu *spu)
+{
+       iounmap(spu->priv2);
+       iounmap(spu->priv1);
+       iounmap(spu->problem);
+       iounmap((u8 __iomem *)spu->local_store);
+}
+
+static int __init spu_map_device(struct spu *spu, struct device_node *spe)
+{
+       char *prop;
+       int ret;
+
+       ret = -ENODEV;
+       prop = get_property(spe, "isrc", NULL);
+       if (!prop)
+               goto out;
+       spu->isrc = *(unsigned int *)prop;
+
+       spu->name = get_property(spe, "name", NULL);
+       if (!spu->name)
+               goto out;
+
+       prop = get_property(spe, "local-store", NULL);
+       if (!prop)
+               goto out;
+       spu->local_store_phys = *(unsigned long *)prop;
+
+       /* we use local store as ram, not io memory */
+       spu->local_store = (void __force *)map_spe_prop(spe, "local-store");
+       if (!spu->local_store)
+               goto out;
+
+       spu->problem= map_spe_prop(spe, "problem");
+       if (!spu->problem)
+               goto out_unmap;
+
+       spu->priv1= map_spe_prop(spe, "priv1");
+       /* priv1 is not available on a hypervisor */
+
+       spu->priv2= map_spe_prop(spe, "priv2");
+       if (!spu->priv2)
+               goto out_unmap;
+       ret = 0;
+       goto out;
+
+out_unmap:
+       spu_unmap(spu);
+out:
+       return ret;
+}
+
+static int __init find_spu_node_id(struct device_node *spe)
+{
+       unsigned int *id;
+       struct device_node *cpu;
+
+       cpu = spe->parent->parent;
+       id = (unsigned int *)get_property(cpu, "node-id", NULL);
+
+       return id ? *id : 0;
+}
+
+static int __init create_spu(struct device_node *spe)
+{
+       struct spu *spu;
+       int ret;
+       static int number;
+
+       ret = -ENOMEM;
+       spu = kmalloc(sizeof (*spu), GFP_KERNEL);
+       if (!spu)
+               goto out;
+
+       ret = spu_map_device(spu, spe);
+       if (ret)
+               goto out_free;
+
+       spu->node = find_spu_node_id(spe);
+       spu->stop_code = 0;
+       spu->slb_replace = 0;
+       spu->mm = NULL;
+       spu->ctx = NULL;
+       spu->rq = NULL;
+       spu->pid = 0;
+       spu->class_0_pending = 0;
+       spu->flags = 0UL;
+       spu->dar = 0UL;
+       spu->dsisr = 0UL;
+       spin_lock_init(&spu->register_lock);
+
+       spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
+       spu_mfc_sr1_set(spu, 0x33);
+
+       spu->ibox_callback = NULL;
+       spu->wbox_callback = NULL;
+       spu->stop_callback = NULL;
+
+       down(&spu_mutex);
+       spu->number = number++;
+       ret = spu_request_irqs(spu);
+       if (ret)
+               goto out_unmap;
+
+       list_add(&spu->list, &spu_list);
+       up(&spu_mutex);
+
+       pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
+               spu->name, spu->isrc, spu->local_store,
+               spu->problem, spu->priv1, spu->priv2, spu->number);
+       goto out;
+
+out_unmap:
+       up(&spu_mutex);
+       spu_unmap(spu);
+out_free:
+       kfree(spu);
+out:
+       return ret;
+}
+
+static void destroy_spu(struct spu *spu)
+{
+       list_del_init(&spu->list);
+
+       spu_free_irqs(spu);
+       spu_unmap(spu);
+       kfree(spu);
+}
+
+static void cleanup_spu_base(void)
+{
+       struct spu *spu, *tmp;
+       down(&spu_mutex);
+       list_for_each_entry_safe(spu, tmp, &spu_list, list)
+               destroy_spu(spu);
+       up(&spu_mutex);
+}
+module_exit(cleanup_spu_base);
+
+static int __init init_spu_base(void)
+{
+       struct device_node *node;
+       int ret;
+
+       ret = -ENODEV;
+       for (node = of_find_node_by_type(NULL, "spe");
+                       node; node = of_find_node_by_type(node, "spe")) {
+               ret = create_spu(node);
+               if (ret) {
+                       printk(KERN_WARNING "%s: Error initializing %s\n",
+                               __FUNCTION__, node->name);
+                       cleanup_spu_base();
+                       break;
+               }
+       }
+       /* in some old firmware versions, the spe is called 'spc', so we
+          look for that as well */
+       for (node = of_find_node_by_type(NULL, "spc");
+                       node; node = of_find_node_by_type(node, "spc")) {
+               ret = create_spu(node);
+               if (ret) {
+                       printk(KERN_WARNING "%s: Error initializing %s\n",
+                               __FUNCTION__, node->name);
+                       cleanup_spu_base();
+                       break;
+               }
+       }
+       return ret;
+}
+module_init(init_spu_base);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
diff --git a/arch/powerpc/platforms/cell/spu_priv1.c b/arch/powerpc/platforms/cell/spu_priv1.c
new file mode 100644 (file)
index 0000000..b265642
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * access to SPU privileged registers
+ */
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+
+void spu_int_mask_and(struct spu *spu, int class, u64 mask)
+{
+       u64 old_mask;
+
+       old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+       out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_and);
+
+void spu_int_mask_or(struct spu *spu, int class, u64 mask)
+{
+       u64 old_mask;
+
+       old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+       out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_or);
+
+void spu_int_mask_set(struct spu *spu, int class, u64 mask)
+{
+       out_be64(&spu->priv1->int_mask_RW[class], mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_set);
+
+u64 spu_int_mask_get(struct spu *spu, int class)
+{
+       return in_be64(&spu->priv1->int_mask_RW[class]);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_get);
+
+void spu_int_stat_clear(struct spu *spu, int class, u64 stat)
+{
+       out_be64(&spu->priv1->int_stat_RW[class], stat);
+}
+EXPORT_SYMBOL_GPL(spu_int_stat_clear);
+
+u64 spu_int_stat_get(struct spu *spu, int class)
+{
+       return in_be64(&spu->priv1->int_stat_RW[class]);
+}
+EXPORT_SYMBOL_GPL(spu_int_stat_get);
+
+void spu_int_route_set(struct spu *spu, u64 route)
+{
+       out_be64(&spu->priv1->int_route_RW, route);
+}
+EXPORT_SYMBOL_GPL(spu_int_route_set);
+
+u64 spu_mfc_dar_get(struct spu *spu)
+{
+       return in_be64(&spu->priv1->mfc_dar_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dar_get);
+
+u64 spu_mfc_dsisr_get(struct spu *spu)
+{
+       return in_be64(&spu->priv1->mfc_dsisr_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dsisr_get);
+
+void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr)
+{
+       out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dsisr_set);
+
+void spu_mfc_sdr_set(struct spu *spu, u64 sdr)
+{
+       out_be64(&spu->priv1->mfc_sdr_RW, sdr);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sdr_set);
+
+void spu_mfc_sr1_set(struct spu *spu, u64 sr1)
+{
+       out_be64(&spu->priv1->mfc_sr1_RW, sr1);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sr1_set);
+
+u64 spu_mfc_sr1_get(struct spu *spu)
+{
+       return in_be64(&spu->priv1->mfc_sr1_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sr1_get);
+
+void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
+{
+       out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_set);
+
+u64 spu_mfc_tclass_id_get(struct spu *spu)
+{
+       return in_be64(&spu->priv1->mfc_tclass_id_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_get);
+
+void spu_tlb_invalidate(struct spu *spu)
+{
+       out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
+}
+EXPORT_SYMBOL_GPL(spu_tlb_invalidate);
+
+void spu_resource_allocation_groupID_set(struct spu *spu, u64 id)
+{
+       out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_set);
+
+u64 spu_resource_allocation_groupID_get(struct spu *spu)
+{
+       return in_be64(&spu->priv1->resource_allocation_groupID_RW);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_get);
+
+void spu_resource_allocation_enable_set(struct spu *spu, u64 enable)
+{
+       out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_set);
+
+u64 spu_resource_allocation_enable_get(struct spu *spu)
+{
+       return in_be64(&spu->priv1->resource_allocation_enable_RW);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_get);
diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c
new file mode 100644 (file)
index 0000000..261b507
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * SPU file system -- system call stubs
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@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/file.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+#include <asm/spu.h>
+
+struct spufs_calls spufs_calls = {
+       .owner = NULL,
+};
+
+/* These stub syscalls are needed to have the actual implementation
+ * within a loadable module. When spufs is built into the kernel,
+ * 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)
+{
+       long ret;
+       struct module *owner = spufs_calls.owner;
+
+       ret = -ENOSYS;
+       if (owner && try_module_get(owner)) {
+               ret = spufs_calls.create_thread(name, flags, mode);
+               module_put(owner);
+       }
+       return ret;
+}
+
+asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
+{
+       long ret;
+       struct file *filp;
+       int fput_needed;
+       struct module *owner = spufs_calls.owner;
+
+       ret = -ENOSYS;
+       if (owner && try_module_get(owner)) {
+               ret = -EBADF;
+               filp = fget_light(fd, &fput_needed);
+               if (filp) {
+                       ret = spufs_calls.spu_run(filp, unpc, ustatus);
+                       fput_light(filp, fput_needed);
+               }
+               module_put(owner);
+       }
+       return ret;
+}
+
+int register_spu_syscalls(struct spufs_calls *calls)
+{
+       if (spufs_calls.owner)
+               return -EBUSY;
+
+       spufs_calls.create_thread = calls->create_thread;
+       spufs_calls.spu_run = calls->spu_run;
+       smp_mb();
+       spufs_calls.owner = calls->owner;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(register_spu_syscalls);
+
+void unregister_spu_syscalls(struct spufs_calls *calls)
+{
+       BUG_ON(spufs_calls.owner != calls->owner);
+       spufs_calls.owner = NULL;
+}
+EXPORT_SYMBOL_GPL(unregister_spu_syscalls);
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
new file mode 100644 (file)
index 0000000..a7cddf4
--- /dev/null
@@ -0,0 +1,54 @@
+obj-$(CONFIG_SPU_FS) += spufs.o
+spufs-y += inode.o file.o context.o switch.o syscalls.o
+spufs-y += sched.o backing_ops.o hw_ops.o run.o
+
+# Rules to build switch.o with the help of SPU tool chain
+SPU_CROSS      := spu-
+SPU_CC         := $(SPU_CROSS)gcc
+SPU_AS         := $(SPU_CROSS)gcc
+SPU_LD         := $(SPU_CROSS)ld
+SPU_OBJCOPY    := $(SPU_CROSS)objcopy
+SPU_CFLAGS     := -O2 -Wall -I$(srctree)/include -I$(objtree)/include2
+SPU_AFLAGS     := -c -D__ASSEMBLY__ -I$(srctree)/include -I$(objtree)/include2
+SPU_LDFLAGS    := -N -Ttext=0x0
+
+$(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h
+
+# Compile SPU files
+      cmd_spu_cc = $(SPU_CC) $(SPU_CFLAGS) -c -o $@ $<
+quiet_cmd_spu_cc = SPU_CC  $@
+$(obj)/spu_%.o: $(src)/spu_%.c
+       $(call if_changed,spu_cc)
+
+# Assemble SPU files
+      cmd_spu_as = $(SPU_AS) $(SPU_AFLAGS) -o $@ $<
+quiet_cmd_spu_as = SPU_AS  $@
+$(obj)/spu_%.o: $(src)/spu_%.S
+       $(call if_changed,spu_as)
+
+# Link SPU Executables
+      cmd_spu_ld = $(SPU_LD) $(SPU_LDFLAGS) -o $@ $^
+quiet_cmd_spu_ld = SPU_LD  $@
+$(obj)/spu_%: $(obj)/spu_%_crt0.o $(obj)/spu_%.o
+       $(call if_changed,spu_ld)
+
+# Copy into binary format
+      cmd_spu_objcopy = $(SPU_OBJCOPY) -O binary $< $@
+quiet_cmd_spu_objcopy = OBJCOPY $@
+$(obj)/spu_%.bin: $(src)/spu_%
+       $(call if_changed,spu_objcopy)
+
+# create C code from ELF executable
+cmd_hexdump   = ( \
+               echo "/*" ; \
+               echo " * $*_dump.h: Copyright (C) 2005 IBM." ; \
+               echo " * Hex-dump auto generated from $*.c." ; \
+               echo " * Do not edit!" ; \
+               echo " */" ; \
+               echo "static unsigned int $*_code[] __page_aligned = {" ; \
+               hexdump -v -e '"0x" 4/1 "%02x" "," "\n"' $< ; \
+               echo "};" ; \
+               ) > $@
+quiet_cmd_hexdump = HEXDUMP $@
+$(obj)/%_dump.h: $(obj)/%.bin
+       $(call if_changed,hexdump)
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
new file mode 100644 (file)
index 0000000..a5c489a
--- /dev/null
@@ -0,0 +1,308 @@
+/* backing_ops.c - query/set operations on saved SPU context.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * These register operations allow SPUFS to operate on saved
+ * SPU contexts rather than hardware.
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/poll.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+#include "spufs.h"
+
+/*
+ * Reads/writes to various problem and priv2 registers require
+ * state changes, i.e.  generate SPU events, modify channel
+ * counts, etc.
+ */
+
+static void gen_spu_event(struct spu_context *ctx, u32 event)
+{
+       u64 ch0_cnt;
+       u64 ch0_data;
+       u64 ch1_data;
+
+       ch0_cnt = ctx->csa.spu_chnlcnt_RW[0];
+       ch0_data = ctx->csa.spu_chnldata_RW[0];
+       ch1_data = ctx->csa.spu_chnldata_RW[1];
+       ctx->csa.spu_chnldata_RW[0] |= event;
+       if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) {
+               ctx->csa.spu_chnlcnt_RW[0] = 1;
+       }
+}
+
+static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data)
+{
+       u32 mbox_stat;
+       int ret = 0;
+
+       spin_lock(&ctx->csa.register_lock);
+       mbox_stat = ctx->csa.prob.mb_stat_R;
+       if (mbox_stat & 0x0000ff) {
+               /* Read the first available word.
+                * Implementation note: the depth
+                * of pu_mb_R is currently 1.
+                */
+               *data = ctx->csa.prob.pu_mb_R;
+               ctx->csa.prob.mb_stat_R &= ~(0x0000ff);
+               ctx->csa.spu_chnlcnt_RW[28] = 1;
+               gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT);
+               ret = 4;
+       }
+       spin_unlock(&ctx->csa.register_lock);
+       return ret;
+}
+
+static u32 spu_backing_mbox_stat_read(struct spu_context *ctx)
+{
+       return ctx->csa.prob.mb_stat_R;
+}
+
+static unsigned int spu_backing_mbox_stat_poll(struct spu_context *ctx,
+                                         unsigned int events)
+{
+       int ret;
+       u32 stat;
+
+       ret = 0;
+       spin_lock_irq(&ctx->csa.register_lock);
+       stat = ctx->csa.prob.mb_stat_R;
+
+       /* if the requested event is there, return the poll
+          mask, otherwise enable the interrupt to get notified,
+          but first mark any pending interrupts as done so
+          we don't get woken up unnecessarily */
+
+       if (events & (POLLIN | POLLRDNORM)) {
+               if (stat & 0xff0000)
+                       ret |= POLLIN | POLLRDNORM;
+               else {
+                       ctx->csa.priv1.int_stat_class0_RW &= ~0x1;
+                       ctx->csa.priv1.int_mask_class2_RW |= 0x1;
+               }
+       }
+       if (events & (POLLOUT | POLLWRNORM)) {
+               if (stat & 0x00ff00)
+                       ret = POLLOUT | POLLWRNORM;
+               else {
+                       ctx->csa.priv1.int_stat_class0_RW &= ~0x10;
+                       ctx->csa.priv1.int_mask_class2_RW |= 0x10;
+               }
+       }
+       spin_unlock_irq(&ctx->csa.register_lock);
+       return ret;
+}
+
+static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data)
+{
+       int ret;
+
+       spin_lock(&ctx->csa.register_lock);
+       if (ctx->csa.prob.mb_stat_R & 0xff0000) {
+               /* Read the first available word.
+                * Implementation note: the depth
+                * of puint_mb_R is currently 1.
+                */
+               *data = ctx->csa.priv2.puint_mb_R;
+               ctx->csa.prob.mb_stat_R &= ~(0xff0000);
+               ctx->csa.spu_chnlcnt_RW[30] = 1;
+               gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT);
+               ret = 4;
+       } else {
+               /* make sure we get woken up by the interrupt */
+               ctx->csa.priv1.int_mask_class2_RW |= 0x1UL;
+               ret = 0;
+       }
+       spin_unlock(&ctx->csa.register_lock);
+       return ret;
+}
+
+static int spu_backing_wbox_write(struct spu_context *ctx, u32 data)
+{
+       int ret;
+
+       spin_lock(&ctx->csa.register_lock);
+       if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) {
+               int slot = ctx->csa.spu_chnlcnt_RW[29];
+               int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8;
+
+               /* We have space to write wbox_data.
+                * Implementation note: the depth
+                * of spu_mb_W is currently 4.
+                */
+               BUG_ON(avail != (4 - slot));
+               ctx->csa.spu_mailbox_data[slot] = data;
+               ctx->csa.spu_chnlcnt_RW[29] = ++slot;
+               ctx->csa.prob.mb_stat_R = (((4 - slot) & 0xff) << 8);
+               gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT);
+               ret = 4;
+       } else {
+               /* make sure we get woken up by the interrupt when space
+                  becomes available */
+               ctx->csa.priv1.int_mask_class2_RW |= 0x10;
+               ret = 0;
+       }
+       spin_unlock(&ctx->csa.register_lock);
+       return ret;
+}
+
+static u32 spu_backing_signal1_read(struct spu_context *ctx)
+{
+       return ctx->csa.spu_chnldata_RW[3];
+}
+
+static void spu_backing_signal1_write(struct spu_context *ctx, u32 data)
+{
+       spin_lock(&ctx->csa.register_lock);
+       if (ctx->csa.priv2.spu_cfg_RW & 0x1)
+               ctx->csa.spu_chnldata_RW[3] |= data;
+       else
+               ctx->csa.spu_chnldata_RW[3] = data;
+       ctx->csa.spu_chnlcnt_RW[3] = 1;
+       gen_spu_event(ctx, MFC_SIGNAL_1_EVENT);
+       spin_unlock(&ctx->csa.register_lock);
+}
+
+static u32 spu_backing_signal2_read(struct spu_context *ctx)
+{
+       return ctx->csa.spu_chnldata_RW[4];
+}
+
+static void spu_backing_signal2_write(struct spu_context *ctx, u32 data)
+{
+       spin_lock(&ctx->csa.register_lock);
+       if (ctx->csa.priv2.spu_cfg_RW & 0x2)
+               ctx->csa.spu_chnldata_RW[4] |= data;
+       else
+               ctx->csa.spu_chnldata_RW[4] = data;
+       ctx->csa.spu_chnlcnt_RW[4] = 1;
+       gen_spu_event(ctx, MFC_SIGNAL_2_EVENT);
+       spin_unlock(&ctx->csa.register_lock);
+}
+
+static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val)
+{
+       u64 tmp;
+
+       spin_lock(&ctx->csa.register_lock);
+       tmp = ctx->csa.priv2.spu_cfg_RW;
+       if (val)
+               tmp |= 1;
+       else
+               tmp &= ~1;
+       ctx->csa.priv2.spu_cfg_RW = tmp;
+       spin_unlock(&ctx->csa.register_lock);
+}
+
+static u64 spu_backing_signal1_type_get(struct spu_context *ctx)
+{
+       return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0);
+}
+
+static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val)
+{
+       u64 tmp;
+
+       spin_lock(&ctx->csa.register_lock);
+       tmp = ctx->csa.priv2.spu_cfg_RW;
+       if (val)
+               tmp |= 2;
+       else
+               tmp &= ~2;
+       ctx->csa.priv2.spu_cfg_RW = tmp;
+       spin_unlock(&ctx->csa.register_lock);
+}
+
+static u64 spu_backing_signal2_type_get(struct spu_context *ctx)
+{
+       return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0);
+}
+
+static u32 spu_backing_npc_read(struct spu_context *ctx)
+{
+       return ctx->csa.prob.spu_npc_RW;
+}
+
+static void spu_backing_npc_write(struct spu_context *ctx, u32 val)
+{
+       ctx->csa.prob.spu_npc_RW = val;
+}
+
+static u32 spu_backing_status_read(struct spu_context *ctx)
+{
+       return ctx->csa.prob.spu_status_R;
+}
+
+static char *spu_backing_get_ls(struct spu_context *ctx)
+{
+       return ctx->csa.lscsa->ls;
+}
+
+static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val)
+{
+       spin_lock(&ctx->csa.register_lock);
+       ctx->csa.prob.spu_runcntl_RW = val;
+       if (val & SPU_RUNCNTL_RUNNABLE) {
+               ctx->csa.prob.spu_status_R |= SPU_STATUS_RUNNING;
+       } else {
+               ctx->csa.prob.spu_status_R &= ~SPU_STATUS_RUNNING;
+       }
+       spin_unlock(&ctx->csa.register_lock);
+}
+
+static void spu_backing_runcntl_stop(struct spu_context *ctx)
+{
+       spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
+}
+
+struct spu_context_ops spu_backing_ops = {
+       .mbox_read = spu_backing_mbox_read,
+       .mbox_stat_read = spu_backing_mbox_stat_read,
+       .mbox_stat_poll = spu_backing_mbox_stat_poll,
+       .ibox_read = spu_backing_ibox_read,
+       .wbox_write = spu_backing_wbox_write,
+       .signal1_read = spu_backing_signal1_read,
+       .signal1_write = spu_backing_signal1_write,
+       .signal2_read = spu_backing_signal2_read,
+       .signal2_write = spu_backing_signal2_write,
+       .signal1_type_set = spu_backing_signal1_type_set,
+       .signal1_type_get = spu_backing_signal1_type_get,
+       .signal2_type_set = spu_backing_signal2_type_set,
+       .signal2_type_get = spu_backing_signal2_type_get,
+       .npc_read = spu_backing_npc_read,
+       .npc_write = spu_backing_npc_write,
+       .status_read = spu_backing_status_read,
+       .get_ls = spu_backing_get_ls,
+       .runcntl_write = spu_backing_runcntl_write,
+       .runcntl_stop = spu_backing_runcntl_stop,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
new file mode 100644 (file)
index 0000000..336f238
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * SPU file system -- SPU context management
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@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/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include "spufs.h"
+
+struct spu_context *alloc_spu_context(struct address_space *local_store)
+{
+       struct spu_context *ctx;
+       ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx)
+               goto out;
+       /* Binding to physical processor deferred
+        * until spu_activate().
+        */
+       spu_init_csa(&ctx->csa);
+       if (!ctx->csa.lscsa) {
+               goto out_free;
+       }
+       spin_lock_init(&ctx->mmio_lock);
+       kref_init(&ctx->kref);
+       init_rwsem(&ctx->state_sema);
+       init_MUTEX(&ctx->run_sema);
+       init_waitqueue_head(&ctx->ibox_wq);
+       init_waitqueue_head(&ctx->wbox_wq);
+       init_waitqueue_head(&ctx->stop_wq);
+       ctx->ibox_fasync = NULL;
+       ctx->wbox_fasync = NULL;
+       ctx->state = SPU_STATE_SAVED;
+       ctx->local_store = local_store;
+       ctx->spu = NULL;
+       ctx->ops = &spu_backing_ops;
+       ctx->owner = get_task_mm(current);
+       goto out;
+out_free:
+       kfree(ctx);
+       ctx = NULL;
+out:
+       return ctx;
+}
+
+void destroy_spu_context(struct kref *kref)
+{
+       struct spu_context *ctx;
+       ctx = container_of(kref, struct spu_context, kref);
+       down_write(&ctx->state_sema);
+       spu_deactivate(ctx);
+       ctx->ibox_fasync = NULL;
+       ctx->wbox_fasync = NULL;
+       up_write(&ctx->state_sema);
+       spu_fini_csa(&ctx->csa);
+       kfree(ctx);
+}
+
+struct spu_context * get_spu_context(struct spu_context *ctx)
+{
+       kref_get(&ctx->kref);
+       return ctx;
+}
+
+int put_spu_context(struct spu_context *ctx)
+{
+       return kref_put(&ctx->kref, &destroy_spu_context);
+}
+
+/* give up the mm reference when the context is about to be destroyed */
+void spu_forget(struct spu_context *ctx)
+{
+       struct mm_struct *mm;
+       spu_acquire_saved(ctx);
+       mm = ctx->owner;
+       ctx->owner = NULL;
+       mmput(mm);
+       spu_release(ctx);
+}
+
+void spu_acquire(struct spu_context *ctx)
+{
+       down_read(&ctx->state_sema);
+}
+
+void spu_release(struct spu_context *ctx)
+{
+       up_read(&ctx->state_sema);
+}
+
+void spu_unmap_mappings(struct spu_context *ctx)
+{
+       unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+}
+
+int spu_acquire_runnable(struct spu_context *ctx)
+{
+       int ret = 0;
+
+       down_read(&ctx->state_sema);
+       if (ctx->state == SPU_STATE_RUNNABLE) {
+               ctx->spu->prio = current->prio;
+               return 0;
+       }
+       up_read(&ctx->state_sema);
+
+       down_write(&ctx->state_sema);
+       /* ctx is about to be freed, can't acquire any more */
+       if (!ctx->owner) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (ctx->state == SPU_STATE_SAVED) {
+               ret = spu_activate(ctx, 0);
+               if (ret)
+                       goto out;
+               ctx->state = SPU_STATE_RUNNABLE;
+       }
+
+       downgrade_write(&ctx->state_sema);
+       /* On success, we return holding the lock */
+
+       return ret;
+out:
+       /* Release here, to simplify calling code. */
+       up_write(&ctx->state_sema);
+
+       return ret;
+}
+
+void spu_acquire_saved(struct spu_context *ctx)
+{
+       down_read(&ctx->state_sema);
+
+       if (ctx->state == SPU_STATE_SAVED)
+               return;
+
+       up_read(&ctx->state_sema);
+       down_write(&ctx->state_sema);
+
+       if (ctx->state == SPU_STATE_RUNNABLE) {
+               spu_deactivate(ctx);
+               ctx->state = SPU_STATE_SAVED;
+       }
+
+       downgrade_write(&ctx->state_sema);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
new file mode 100644 (file)
index 0000000..dfa649c
--- /dev/null
@@ -0,0 +1,794 @@
+/*
+ * SPU file system -- file contents
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@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/fs.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/ptrace.h>
+
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+
+static int
+spufs_mem_open(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       file->private_data = i->i_ctx;
+       file->f_mapping = i->i_ctx->local_store;
+       return 0;
+}
+
+static ssize_t
+spufs_mem_read(struct file *file, char __user *buffer,
+                               size_t size, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       char *local_store;
+       int ret;
+
+       spu_acquire(ctx);
+
+       local_store = ctx->ops->get_ls(ctx);
+       ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
+
+       spu_release(ctx);
+       return ret;
+}
+
+static ssize_t
+spufs_mem_write(struct file *file, const char __user *buffer,
+                                       size_t size, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       char *local_store;
+       int ret;
+
+       size = min_t(ssize_t, LS_SIZE - *pos, size);
+       if (size <= 0)
+               return -EFBIG;
+       *pos += size;
+
+       spu_acquire(ctx);
+
+       local_store = ctx->ops->get_ls(ctx);
+       ret = copy_from_user(local_store + *pos - size,
+                            buffer, size) ? -EFAULT : size;
+
+       spu_release(ctx);
+       return ret;
+}
+
+#ifdef CONFIG_SPARSEMEM
+static struct page *
+spufs_mem_mmap_nopage(struct vm_area_struct *vma,
+                     unsigned long address, int *type)
+{
+       struct page *page = NOPAGE_SIGBUS;
+
+       struct spu_context *ctx = vma->vm_file->private_data;
+       unsigned long offset = address - vma->vm_start;
+       offset += vma->vm_pgoff << PAGE_SHIFT;
+
+       spu_acquire(ctx);
+
+       if (ctx->state == SPU_STATE_SAVED)
+               page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
+       else
+               page = pfn_to_page((ctx->spu->local_store_phys + offset)
+                                  >> PAGE_SHIFT);
+
+       spu_release(ctx);
+
+       if (type)
+               *type = VM_FAULT_MINOR;
+
+       page_cache_get(page);
+       return page;
+}
+
+static struct vm_operations_struct spufs_mem_mmap_vmops = {
+       .nopage = spufs_mem_mmap_nopage,
+};
+
+static int
+spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       if (!(vma->vm_flags & VM_SHARED))
+               return -EINVAL;
+
+       /* FIXME: */
+       vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+                                    | _PAGE_NO_CACHE);
+
+       vma->vm_ops = &spufs_mem_mmap_vmops;
+       return 0;
+}
+#endif
+
+static struct file_operations spufs_mem_fops = {
+       .open    = spufs_mem_open,
+       .read    = spufs_mem_read,
+       .write   = spufs_mem_write,
+       .llseek  = generic_file_llseek,
+#ifdef CONFIG_SPARSEMEM
+       .mmap    = spufs_mem_mmap,
+#endif
+};
+
+static int
+spufs_regs_open(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       file->private_data = i->i_ctx;
+       return 0;
+}
+
+static ssize_t
+spufs_regs_read(struct file *file, char __user *buffer,
+               size_t size, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       int ret;
+
+       spu_acquire_saved(ctx);
+
+       ret = simple_read_from_buffer(buffer, size, pos,
+                                     lscsa->gprs, sizeof lscsa->gprs);
+
+       spu_release(ctx);
+       return ret;
+}
+
+static ssize_t
+spufs_regs_write(struct file *file, const char __user *buffer,
+                size_t size, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       int ret;
+
+       size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
+       if (size <= 0)
+               return -EFBIG;
+       *pos += size;
+
+       spu_acquire_saved(ctx);
+
+       ret = copy_from_user(lscsa->gprs + *pos - size,
+                            buffer, size) ? -EFAULT : size;
+
+       spu_release(ctx);
+       return ret;
+}
+
+static struct file_operations spufs_regs_fops = {
+       .open    = spufs_regs_open,
+       .read    = spufs_regs_read,
+       .write   = spufs_regs_write,
+       .llseek  = generic_file_llseek,
+};
+
+static ssize_t
+spufs_fpcr_read(struct file *file, char __user * buffer,
+               size_t size, loff_t * pos)
+{
+       struct spu_context *ctx = file->private_data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       int ret;
+
+       spu_acquire_saved(ctx);
+
+       ret = simple_read_from_buffer(buffer, size, pos,
+                                     &lscsa->fpcr, sizeof(lscsa->fpcr));
+
+       spu_release(ctx);
+       return ret;
+}
+
+static ssize_t
+spufs_fpcr_write(struct file *file, const char __user * buffer,
+                size_t size, loff_t * pos)
+{
+       struct spu_context *ctx = file->private_data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       int ret;
+
+       size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
+       if (size <= 0)
+               return -EFBIG;
+       *pos += size;
+
+       spu_acquire_saved(ctx);
+
+       ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
+                            buffer, size) ? -EFAULT : size;
+
+       spu_release(ctx);
+       return ret;
+}
+
+static struct file_operations spufs_fpcr_fops = {
+       .open = spufs_regs_open,
+       .read = spufs_fpcr_read,
+       .write = spufs_fpcr_write,
+       .llseek = generic_file_llseek,
+};
+
+/* generic open function for all pipe-like files */
+static int spufs_pipe_open(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       file->private_data = i->i_ctx;
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       u32 mbox_data;
+       int ret;
+
+       if (len < 4)
+               return -EINVAL;
+
+       spu_acquire(ctx);
+       ret = ctx->ops->mbox_read(ctx, &mbox_data);
+       spu_release(ctx);
+
+       if (!ret)
+               return -EAGAIN;
+
+       if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
+               return -EFAULT;
+
+       return 4;
+}
+
+static struct file_operations spufs_mbox_fops = {
+       .open   = spufs_pipe_open,
+       .read   = spufs_mbox_read,
+};
+
+static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       u32 mbox_stat;
+
+       if (len < 4)
+               return -EINVAL;
+
+       spu_acquire(ctx);
+
+       mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
+
+       spu_release(ctx);
+
+       if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
+               return -EFAULT;
+
+       return 4;
+}
+
+static struct file_operations spufs_mbox_stat_fops = {
+       .open   = spufs_pipe_open,
+       .read   = spufs_mbox_stat_read,
+};
+
+/* low-level ibox access function */
+size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
+{
+       return ctx->ops->ibox_read(ctx, data);
+}
+
+static int spufs_ibox_fasync(int fd, struct file *file, int on)
+{
+       struct spu_context *ctx = file->private_data;
+
+       return fasync_helper(fd, file, on, &ctx->ibox_fasync);
+}
+
+/* interrupt-level ibox callback function. */
+void spufs_ibox_callback(struct spu *spu)
+{
+       struct spu_context *ctx = spu->ctx;
+
+       wake_up_all(&ctx->ibox_wq);
+       kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
+}
+
+static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       u32 ibox_data;
+       ssize_t ret;
+
+       if (len < 4)
+               return -EINVAL;
+
+       spu_acquire(ctx);
+
+       ret = 0;
+       if (file->f_flags & O_NONBLOCK) {
+               if (!spu_ibox_read(ctx, &ibox_data))
+                       ret = -EAGAIN;
+       } else {
+               ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
+       }
+
+       spu_release(ctx);
+
+       if (ret)
+               return ret;
+
+       ret = 4;
+       if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
+               ret = -EFAULT;
+
+       return ret;
+}
+
+static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
+{
+       struct spu_context *ctx = file->private_data;
+       unsigned int mask;
+
+       poll_wait(file, &ctx->ibox_wq, wait);
+
+       spu_acquire(ctx);
+       mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM);
+       spu_release(ctx);
+
+       return mask;
+}
+
+static struct file_operations spufs_ibox_fops = {
+       .open   = spufs_pipe_open,
+       .read   = spufs_ibox_read,
+       .poll   = spufs_ibox_poll,
+       .fasync = spufs_ibox_fasync,
+};
+
+static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       u32 ibox_stat;
+
+       if (len < 4)
+               return -EINVAL;
+
+       spu_acquire(ctx);
+       ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
+       spu_release(ctx);
+
+       if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
+               return -EFAULT;
+
+       return 4;
+}
+
+static struct file_operations spufs_ibox_stat_fops = {
+       .open   = spufs_pipe_open,
+       .read   = spufs_ibox_stat_read,
+};
+
+/* low-level mailbox write */
+size_t spu_wbox_write(struct spu_context *ctx, u32 data)
+{
+       return ctx->ops->wbox_write(ctx, data);
+}
+
+static int spufs_wbox_fasync(int fd, struct file *file, int on)
+{
+       struct spu_context *ctx = file->private_data;
+       int ret;
+
+       ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
+
+       return ret;
+}
+
+/* interrupt-level wbox callback function. */
+void spufs_wbox_callback(struct spu *spu)
+{
+       struct spu_context *ctx = spu->ctx;
+
+       wake_up_all(&ctx->wbox_wq);
+       kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
+}
+
+static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       u32 wbox_data;
+       int ret;
+
+       if (len < 4)
+               return -EINVAL;
+
+       if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
+               return -EFAULT;
+
+       spu_acquire(ctx);
+
+       ret = 0;
+       if (file->f_flags & O_NONBLOCK) {
+               if (!spu_wbox_write(ctx, wbox_data))
+                       ret = -EAGAIN;
+       } else {
+               ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
+       }
+
+       spu_release(ctx);
+
+       return ret ? ret : sizeof wbox_data;
+}
+
+static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
+{
+       struct spu_context *ctx = file->private_data;
+       unsigned int mask;
+
+       poll_wait(file, &ctx->wbox_wq, wait);
+
+       spu_acquire(ctx);
+       mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM);
+       spu_release(ctx);
+
+       return mask;
+}
+
+static struct file_operations spufs_wbox_fops = {
+       .open   = spufs_pipe_open,
+       .write  = spufs_wbox_write,
+       .poll   = spufs_wbox_poll,
+       .fasync = spufs_wbox_fasync,
+};
+
+static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       u32 wbox_stat;
+
+       if (len < 4)
+               return -EINVAL;
+
+       spu_acquire(ctx);
+       wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
+       spu_release(ctx);
+
+       if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
+               return -EFAULT;
+
+       return 4;
+}
+
+static struct file_operations spufs_wbox_stat_fops = {
+       .open   = spufs_pipe_open,
+       .read   = spufs_wbox_stat_read,
+};
+
+static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx = file->private_data;
+       u32 data;
+
+       if (len < 4)
+               return -EINVAL;
+
+       spu_acquire(ctx);
+       data = ctx->ops->signal1_read(ctx);
+       spu_release(ctx);
+
+       if (copy_to_user(buf, &data, 4))
+               return -EFAULT;
+
+       return 4;
+}
+
+static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx;
+       u32 data;
+
+       ctx = file->private_data;
+
+       if (len < 4)
+               return -EINVAL;
+
+       if (copy_from_user(&data, buf, 4))
+               return -EFAULT;
+
+       spu_acquire(ctx);
+       ctx->ops->signal1_write(ctx, data);
+       spu_release(ctx);
+
+       return 4;
+}
+
+static struct file_operations spufs_signal1_fops = {
+       .open = spufs_pipe_open,
+       .read = spufs_signal1_read,
+       .write = spufs_signal1_write,
+};
+
+static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx;
+       u32 data;
+
+       ctx = file->private_data;
+
+       if (len < 4)
+               return -EINVAL;
+
+       spu_acquire(ctx);
+       data = ctx->ops->signal2_read(ctx);
+       spu_release(ctx);
+
+       if (copy_to_user(buf, &data, 4))
+               return -EFAULT;
+
+       return 4;
+}
+
+static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
+                       size_t len, loff_t *pos)
+{
+       struct spu_context *ctx;
+       u32 data;
+
+       ctx = file->private_data;
+
+       if (len < 4)
+               return -EINVAL;
+
+       if (copy_from_user(&data, buf, 4))
+               return -EFAULT;
+
+       spu_acquire(ctx);
+       ctx->ops->signal2_write(ctx, data);
+       spu_release(ctx);
+
+       return 4;
+}
+
+static struct file_operations spufs_signal2_fops = {
+       .open = spufs_pipe_open,
+       .read = spufs_signal2_read,
+       .write = spufs_signal2_write,
+};
+
+static void spufs_signal1_type_set(void *data, u64 val)
+{
+       struct spu_context *ctx = data;
+
+       spu_acquire(ctx);
+       ctx->ops->signal1_type_set(ctx, val);
+       spu_release(ctx);
+}
+
+static u64 spufs_signal1_type_get(void *data)
+{
+       struct spu_context *ctx = data;
+       u64 ret;
+
+       spu_acquire(ctx);
+       ret = ctx->ops->signal1_type_get(ctx);
+       spu_release(ctx);
+
+       return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
+                                       spufs_signal1_type_set, "%llu");
+
+static void spufs_signal2_type_set(void *data, u64 val)
+{
+       struct spu_context *ctx = data;
+
+       spu_acquire(ctx);
+       ctx->ops->signal2_type_set(ctx, val);
+       spu_release(ctx);
+}
+
+static u64 spufs_signal2_type_get(void *data)
+{
+       struct spu_context *ctx = data;
+       u64 ret;
+
+       spu_acquire(ctx);
+       ret = ctx->ops->signal2_type_get(ctx);
+       spu_release(ctx);
+
+       return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
+                                       spufs_signal2_type_set, "%llu");
+
+static void spufs_npc_set(void *data, u64 val)
+{
+       struct spu_context *ctx = data;
+       spu_acquire(ctx);
+       ctx->ops->npc_write(ctx, val);
+       spu_release(ctx);
+}
+
+static u64 spufs_npc_get(void *data)
+{
+       struct spu_context *ctx = data;
+       u64 ret;
+       spu_acquire(ctx);
+       ret = ctx->ops->npc_read(ctx);
+       spu_release(ctx);
+       return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
+
+static void spufs_decr_set(void *data, u64 val)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       spu_acquire_saved(ctx);
+       lscsa->decr.slot[0] = (u32) val;
+       spu_release(ctx);
+}
+
+static u64 spufs_decr_get(void *data)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       u64 ret;
+       spu_acquire_saved(ctx);
+       ret = lscsa->decr.slot[0];
+       spu_release(ctx);
+       return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
+                       "%llx\n")
+
+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);
+}
+
+static u64 spufs_decr_status_get(void *data)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       u64 ret;
+       spu_acquire_saved(ctx);
+       ret = lscsa->decr_status.slot[0];
+       spu_release(ctx);
+       return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
+                       spufs_decr_status_set, "%llx\n")
+
+static void spufs_spu_tag_mask_set(void *data, u64 val)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       spu_acquire_saved(ctx);
+       lscsa->tag_mask.slot[0] = (u32) val;
+       spu_release(ctx);
+}
+
+static u64 spufs_spu_tag_mask_get(void *data)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       u64 ret;
+       spu_acquire_saved(ctx);
+       ret = lscsa->tag_mask.slot[0];
+       spu_release(ctx);
+       return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
+                       spufs_spu_tag_mask_set, "%llx\n")
+
+static void spufs_event_mask_set(void *data, u64 val)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       spu_acquire_saved(ctx);
+       lscsa->event_mask.slot[0] = (u32) val;
+       spu_release(ctx);
+}
+
+static u64 spufs_event_mask_get(void *data)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       u64 ret;
+       spu_acquire_saved(ctx);
+       ret = lscsa->event_mask.slot[0];
+       spu_release(ctx);
+       return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
+                       spufs_event_mask_set, "%llx\n")
+
+static void spufs_srr0_set(void *data, u64 val)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       spu_acquire_saved(ctx);
+       lscsa->srr0.slot[0] = (u32) val;
+       spu_release(ctx);
+}
+
+static u64 spufs_srr0_get(void *data)
+{
+       struct spu_context *ctx = data;
+       struct spu_lscsa *lscsa = ctx->csa.lscsa;
+       u64 ret;
+       spu_acquire_saved(ctx);
+       ret = lscsa->srr0.slot[0];
+       spu_release(ctx);
+       return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
+                       "%llx\n")
+
+struct tree_descr spufs_dir_contents[] = {
+       { "mem",  &spufs_mem_fops,  0666, },
+       { "regs", &spufs_regs_fops,  0666, },
+       { "mbox", &spufs_mbox_fops, 0444, },
+       { "ibox", &spufs_ibox_fops, 0444, },
+       { "wbox", &spufs_wbox_fops, 0222, },
+       { "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_type", &spufs_signal1_type, 0666, },
+       { "signal2_type", &spufs_signal2_type, 0666, },
+       { "npc", &spufs_npc_ops, 0666, },
+       { "fpcr", &spufs_fpcr_fops, 0666, },
+       { "decr", &spufs_decr_ops, 0666, },
+       { "decr_status", &spufs_decr_status_ops, 0666, },
+       { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
+       { "event_mask", &spufs_event_mask_ops, 0666, },
+       { "srr0", &spufs_srr0_ops, 0666, },
+       {},
+};
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
new file mode 100644 (file)
index 0000000..5445719
--- /dev/null
@@ -0,0 +1,255 @@
+/* hw_ops.c - query/set operations on active SPU context.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@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, 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/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+#include "spufs.h"
+
+static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
+{
+       struct spu *spu = ctx->spu;
+       struct spu_problem __iomem *prob = spu->problem;
+       u32 mbox_stat;
+       int ret = 0;
+
+       spin_lock_irq(&spu->register_lock);
+       mbox_stat = in_be32(&prob->mb_stat_R);
+       if (mbox_stat & 0x0000ff) {
+               *data = in_be32(&prob->pu_mb_R);
+               ret = 4;
+       }
+       spin_unlock_irq(&spu->register_lock);
+       return ret;
+}
+
+static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
+{
+       return in_be32(&ctx->spu->problem->mb_stat_R);
+}
+
+static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx,
+                                         unsigned int events)
+{
+       struct spu *spu = ctx->spu;
+       int ret = 0;
+       u32 stat;
+
+       spin_lock_irq(&spu->register_lock);
+       stat = in_be32(&spu->problem->mb_stat_R);
+
+       /* if the requested event is there, return the poll
+          mask, otherwise enable the interrupt to get notified,
+          but first mark any pending interrupts as done so
+          we don't get woken up unnecessarily */
+
+       if (events & (POLLIN | POLLRDNORM)) {
+               if (stat & 0xff0000)
+                       ret |= POLLIN | POLLRDNORM;
+               else {
+                       spu_int_stat_clear(spu, 2, 0x1);
+                       spu_int_mask_or(spu, 2, 0x1);
+               }
+       }
+       if (events & (POLLOUT | POLLWRNORM)) {
+               if (stat & 0x00ff00)
+                       ret = POLLOUT | POLLWRNORM;
+               else {
+                       spu_int_stat_clear(spu, 2, 0x10);
+                       spu_int_mask_or(spu, 2, 0x10);
+               }
+       }
+       spin_unlock_irq(&spu->register_lock);
+       return ret;
+}
+
+static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
+{
+       struct spu *spu = ctx->spu;
+       struct spu_problem __iomem *prob = spu->problem;
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       int ret;
+
+       spin_lock_irq(&spu->register_lock);
+       if (in_be32(&prob->mb_stat_R) & 0xff0000) {
+               /* read the first available word */
+               *data = in_be64(&priv2->puint_mb_R);
+               ret = 4;
+       } else {
+               /* make sure we get woken up by the interrupt */
+               spu_int_mask_or(spu, 2, 0x1);
+               ret = 0;
+       }
+       spin_unlock_irq(&spu->register_lock);
+       return ret;
+}
+
+static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
+{
+       struct spu *spu = ctx->spu;
+       struct spu_problem __iomem *prob = spu->problem;
+       int ret;
+
+       spin_lock_irq(&spu->register_lock);
+       if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
+               /* we have space to write wbox_data to */
+               out_be32(&prob->spu_mb_W, data);
+               ret = 4;
+       } else {
+               /* make sure we get woken up by the interrupt when space
+                  becomes available */
+               spu_int_mask_or(spu, 2, 0x10);
+               ret = 0;
+       }
+       spin_unlock_irq(&spu->register_lock);
+       return ret;
+}
+
+static u32 spu_hw_signal1_read(struct spu_context *ctx)
+{
+       return in_be32(&ctx->spu->problem->signal_notify1);
+}
+
+static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
+{
+       out_be32(&ctx->spu->problem->signal_notify1, data);
+}
+
+static u32 spu_hw_signal2_read(struct spu_context *ctx)
+{
+       return in_be32(&ctx->spu->problem->signal_notify1);
+}
+
+static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
+{
+       out_be32(&ctx->spu->problem->signal_notify2, data);
+}
+
+static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
+{
+       struct spu *spu = ctx->spu;
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       u64 tmp;
+
+       spin_lock_irq(&spu->register_lock);
+       tmp = in_be64(&priv2->spu_cfg_RW);
+       if (val)
+               tmp |= 1;
+       else
+               tmp &= ~1;
+       out_be64(&priv2->spu_cfg_RW, tmp);
+       spin_unlock_irq(&spu->register_lock);
+}
+
+static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
+{
+       return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
+}
+
+static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
+{
+       struct spu *spu = ctx->spu;
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       u64 tmp;
+
+       spin_lock_irq(&spu->register_lock);
+       tmp = in_be64(&priv2->spu_cfg_RW);
+       if (val)
+               tmp |= 2;
+       else
+               tmp &= ~2;
+       out_be64(&priv2->spu_cfg_RW, tmp);
+       spin_unlock_irq(&spu->register_lock);
+}
+
+static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
+{
+       return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
+}
+
+static u32 spu_hw_npc_read(struct spu_context *ctx)
+{
+       return in_be32(&ctx->spu->problem->spu_npc_RW);
+}
+
+static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
+{
+       out_be32(&ctx->spu->problem->spu_npc_RW, val);
+}
+
+static u32 spu_hw_status_read(struct spu_context *ctx)
+{
+       return in_be32(&ctx->spu->problem->spu_status_R);
+}
+
+static char *spu_hw_get_ls(struct spu_context *ctx)
+{
+       return ctx->spu->local_store;
+}
+
+static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
+{
+       eieio();
+       out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
+}
+
+static void spu_hw_runcntl_stop(struct spu_context *ctx)
+{
+       spin_lock_irq(&ctx->spu->register_lock);
+       out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+       while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
+               cpu_relax();
+       spin_unlock_irq(&ctx->spu->register_lock);
+}
+
+struct spu_context_ops spu_hw_ops = {
+       .mbox_read = spu_hw_mbox_read,
+       .mbox_stat_read = spu_hw_mbox_stat_read,
+       .mbox_stat_poll = spu_hw_mbox_stat_poll,
+       .ibox_read = spu_hw_ibox_read,
+       .wbox_write = spu_hw_wbox_write,
+       .signal1_read = spu_hw_signal1_read,
+       .signal1_write = spu_hw_signal1_write,
+       .signal2_read = spu_hw_signal2_read,
+       .signal2_write = spu_hw_signal2_write,
+       .signal1_type_set = spu_hw_signal1_type_set,
+       .signal1_type_get = spu_hw_signal1_type_get,
+       .signal2_type_set = spu_hw_signal2_type_set,
+       .signal2_type_get = spu_hw_signal2_type_get,
+       .npc_read = spu_hw_npc_read,
+       .npc_write = spu_hw_npc_write,
+       .status_read = spu_hw_status_read,
+       .get_ls = spu_hw_get_ls,
+       .runcntl_write = spu_hw_runcntl_write,
+       .runcntl_stop = spu_hw_runcntl_stop,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
new file mode 100644 (file)
index 0000000..1f3507c
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * SPU file system
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@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/file.h>
+#include <linux/fs.h>
+#include <linux/backing-dev.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/parser.h>
+
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+static kmem_cache_t *spufs_inode_cache;
+
+static struct inode *
+spufs_alloc_inode(struct super_block *sb)
+{
+       struct spufs_inode_info *ei;
+
+       ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL);
+       if (!ei)
+               return NULL;
+       return &ei->vfs_inode;
+}
+
+static void
+spufs_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
+}
+
+static void
+spufs_init_once(void *p, kmem_cache_t * cachep, unsigned long flags)
+{
+       struct spufs_inode_info *ei = p;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+           SLAB_CTOR_CONSTRUCTOR) {
+               inode_init_once(&ei->vfs_inode);
+       }
+}
+
+static struct inode *
+spufs_new_inode(struct super_block *sb, int mode)
+{
+       struct inode *inode;
+
+       inode = new_inode(sb);
+       if (!inode)
+               goto out;
+
+       inode->i_mode = mode;
+       inode->i_uid = current->fsuid;
+       inode->i_gid = current->fsgid;
+       inode->i_blksize = PAGE_CACHE_SIZE;
+       inode->i_blocks = 0;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+out:
+       return inode;
+}
+
+static int
+spufs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+       struct inode *inode = dentry->d_inode;
+
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           (attr->ia_size != inode->i_size))
+               return -EINVAL;
+       return inode_setattr(inode, attr);
+}
+
+
+static int
+spufs_new_file(struct super_block *sb, struct dentry *dentry,
+               struct file_operations *fops, int mode,
+               struct spu_context *ctx)
+{
+       static struct inode_operations spufs_file_iops = {
+               .setattr = spufs_setattr,
+       };
+       struct inode *inode;
+       int ret;
+
+       ret = -ENOSPC;
+       inode = spufs_new_inode(sb, S_IFREG | mode);
+       if (!inode)
+               goto out;
+
+       ret = 0;
+       inode->i_op = &spufs_file_iops;
+       inode->i_fop = fops;
+       inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
+       d_add(dentry, inode);
+out:
+       return ret;
+}
+
+static void
+spufs_delete_inode(struct inode *inode)
+{
+       if (SPUFS_I(inode)->i_ctx)
+               put_spu_context(SPUFS_I(inode)->i_ctx);
+       clear_inode(inode);
+}
+
+static void spufs_prune_dir(struct dentry *dir)
+{
+       struct dentry *dentry, *tmp;
+       down(&dir->d_inode->i_sem);
+       list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
+               spin_lock(&dcache_lock);
+               spin_lock(&dentry->d_lock);
+               if (!(d_unhashed(dentry)) && dentry->d_inode) {
+                       dget_locked(dentry);
+                       __d_drop(dentry);
+                       spin_unlock(&dentry->d_lock);
+                       simple_unlink(dir->d_inode, dentry);
+                       spin_unlock(&dcache_lock);
+                       dput(dentry);
+               } else {
+                       spin_unlock(&dentry->d_lock);
+                       spin_unlock(&dcache_lock);
+               }
+       }
+       shrink_dcache_parent(dir);
+       up(&dir->d_inode->i_sem);
+}
+
+static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+{
+       struct spu_context *ctx;
+
+       /* remove all entries */
+       down(&root->i_sem);
+       spufs_prune_dir(dir_dentry);
+       up(&root->i_sem);
+
+       /* We have to give up the mm_struct */
+       ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx;
+       spu_forget(ctx);
+
+       /* XXX Do we need to hold i_sem here ? */
+       return simple_rmdir(root, dir_dentry);
+}
+
+static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
+                         int mode, struct spu_context *ctx)
+{
+       struct dentry *dentry;
+       int ret;
+
+       while (files->name && files->name[0]) {
+               ret = -ENOMEM;
+               dentry = d_alloc_name(dir, files->name);
+               if (!dentry)
+                       goto out;
+               ret = spufs_new_file(dir->d_sb, dentry, files->ops,
+                                       files->mode & mode, ctx);
+               if (ret)
+                       goto out;
+               files++;
+       }
+       return 0;
+out:
+       spufs_prune_dir(dir);
+       return ret;
+}
+
+static int spufs_dir_close(struct inode *inode, struct file *file)
+{
+       struct inode *dir;
+       struct dentry *dentry;
+       int ret;
+
+       dentry = file->f_dentry;
+       dir = dentry->d_parent->d_inode;
+
+       ret = spufs_rmdir(dir, dentry);
+       WARN_ON(ret);
+
+       return dcache_dir_close(inode, file);
+}
+
+struct inode_operations spufs_dir_inode_operations = {
+       .lookup = simple_lookup,
+};
+
+struct file_operations spufs_context_fops = {
+       .open           = dcache_dir_open,
+       .release        = spufs_dir_close,
+       .llseek         = dcache_dir_lseek,
+       .read           = generic_read_dir,
+       .readdir        = dcache_readdir,
+       .fsync          = simple_sync_file,
+};
+
+static int
+spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       int ret;
+       struct inode *inode;
+       struct spu_context *ctx;
+
+       ret = -ENOSPC;
+       inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
+       if (!inode)
+               goto out;
+
+       if (dir->i_mode & S_ISGID) {
+               inode->i_gid = dir->i_gid;
+               inode->i_mode &= S_ISGID;
+       }
+       ctx = alloc_spu_context(inode->i_mapping);
+       SPUFS_I(inode)->i_ctx = ctx;
+       if (!ctx)
+               goto out_iput;
+
+       inode->i_op = &spufs_dir_inode_operations;
+       inode->i_fop = &simple_dir_operations;
+       ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
+       if (ret)
+               goto out_free_ctx;
+
+       d_instantiate(dentry, inode);
+       dget(dentry);
+       dir->i_nlink++;
+       dentry->d_inode->i_nlink++;
+       goto out;
+
+out_free_ctx:
+       put_spu_context(ctx);
+out_iput:
+       iput(inode);
+out:
+       return ret;
+}
+
+static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt)
+{
+       int ret;
+       struct file *filp;
+
+       ret = get_unused_fd();
+       if (ret < 0) {
+               dput(dentry);
+               mntput(mnt);
+               goto out;
+       }
+
+       filp = dentry_open(dentry, mnt, O_RDONLY);
+       if (IS_ERR(filp)) {
+               put_unused_fd(ret);
+               ret = PTR_ERR(filp);
+               goto out;
+       }
+
+       filp->f_op = &spufs_context_fops;
+       fd_install(ret, filp);
+out:
+       return ret;
+}
+
+static struct file_system_type spufs_type;
+
+long spufs_create_thread(struct nameidata *nd,
+                        unsigned int flags, mode_t mode)
+{
+       struct dentry *dentry;
+       int ret;
+
+       /* need to be at the root of spufs */
+       ret = -EINVAL;
+       if (nd->dentry->d_sb->s_type != &spufs_type ||
+           nd->dentry != nd->dentry->d_sb->s_root)
+               goto out;
+
+       dentry = lookup_create(nd, 1);
+       ret = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
+               goto out_dir;
+
+       ret = -EEXIST;
+       if (dentry->d_inode)
+               goto out_dput;
+
+       mode &= ~current->fs->umask;
+       ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO);
+       if (ret)
+               goto out_dput;
+
+       /*
+        * get references for dget and mntget, will be released
+        * in error path of *_open().
+        */
+       ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
+       if (ret < 0)
+               spufs_rmdir(nd->dentry->d_inode, dentry);
+
+out_dput:
+       dput(dentry);
+out_dir:
+       up(&nd->dentry->d_inode->i_sem);
+out:
+       return ret;
+}
+
+/* File system initialization */
+enum {
+       Opt_uid, Opt_gid, Opt_err,
+};
+
+static match_table_t spufs_tokens = {
+       { Opt_uid, "uid=%d" },
+       { Opt_gid, "gid=%d" },
+       { Opt_err, NULL  },
+};
+
+static int
+spufs_parse_options(char *options, struct inode *root)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token, option;
+
+               if (!*p)
+                       continue;
+
+               token = match_token(p, spufs_tokens, args);
+               switch (token) {
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       root->i_uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       root->i_gid = option;
+                       break;
+               default:
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static int
+spufs_create_root(struct super_block *sb, void *data)
+{
+       struct inode *inode;
+       int ret;
+
+       ret = -ENOMEM;
+       inode = spufs_new_inode(sb, S_IFDIR | 0775);
+       if (!inode)
+               goto out;
+
+       inode->i_op = &spufs_dir_inode_operations;
+       inode->i_fop = &simple_dir_operations;
+       SPUFS_I(inode)->i_ctx = NULL;
+
+       ret = -EINVAL;
+       if (!spufs_parse_options(data, inode))
+               goto out_iput;
+
+       ret = -ENOMEM;
+       sb->s_root = d_alloc_root(inode);
+       if (!sb->s_root)
+               goto out_iput;
+
+       return 0;
+out_iput:
+       iput(inode);
+out:
+       return ret;
+}
+
+static int
+spufs_fill_super(struct super_block *sb, void *data, int silent)
+{
+       static struct super_operations s_ops = {
+               .alloc_inode = spufs_alloc_inode,
+               .destroy_inode = spufs_destroy_inode,
+               .statfs = simple_statfs,
+               .delete_inode = spufs_delete_inode,
+               .drop_inode = generic_delete_inode,
+       };
+
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
+       sb->s_blocksize = PAGE_CACHE_SIZE;
+       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+       sb->s_magic = SPUFS_MAGIC;
+       sb->s_op = &s_ops;
+
+       return spufs_create_root(sb, data);
+}
+
+static struct super_block *
+spufs_get_sb(struct file_system_type *fstype, int flags,
+               const char *name, void *data)
+{
+       return get_sb_single(fstype, flags, data, spufs_fill_super);
+}
+
+static struct file_system_type spufs_type = {
+       .owner = THIS_MODULE,
+       .name = "spufs",
+       .get_sb = spufs_get_sb,
+       .kill_sb = kill_litter_super,
+};
+
+static int spufs_init(void)
+{
+       int ret;
+       ret = -ENOMEM;
+       spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
+                       sizeof(struct spufs_inode_info), 0,
+                       SLAB_HWCACHE_ALIGN, spufs_init_once, NULL);
+
+       if (!spufs_inode_cache)
+               goto out;
+       if (spu_sched_init() != 0) {
+               kmem_cache_destroy(spufs_inode_cache);
+               goto out;
+       }
+       ret = register_filesystem(&spufs_type);
+       if (ret)
+               goto out_cache;
+       ret = register_spu_syscalls(&spufs_calls);
+       if (ret)
+               goto out_fs;
+       return 0;
+out_fs:
+       unregister_filesystem(&spufs_type);
+out_cache:
+       kmem_cache_destroy(spufs_inode_cache);
+out:
+       return ret;
+}
+module_init(spufs_init);
+
+static void spufs_exit(void)
+{
+       spu_sched_exit();
+       unregister_spu_syscalls(&spufs_calls);
+       unregister_filesystem(&spufs_type);
+       kmem_cache_destroy(spufs_inode_cache);
+}
+module_exit(spufs_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
+
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
new file mode 100644 (file)
index 0000000..18ea886
--- /dev/null
@@ -0,0 +1,131 @@
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+
+#include <asm/spu.h>
+
+#include "spufs.h"
+
+/* interrupt-level stop callback function. */
+void spufs_stop_callback(struct spu *spu)
+{
+       struct spu_context *ctx = spu->ctx;
+
+       wake_up_all(&ctx->stop_wq);
+}
+
+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;
+       pte_fault = spu->dsisr &
+           (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
+       return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
+}
+
+static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
+                              u32 * status)
+{
+       int ret;
+
+       if ((ret = spu_acquire_runnable(ctx)) != 0)
+               return ret;
+       ctx->ops->npc_write(ctx, *npc);
+       ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+       return 0;
+}
+
+static inline 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);
+       spu_release(ctx);
+
+       if (signal_pending(current))
+               ret = -ERESTARTSYS;
+       if (unlikely(current->ptrace & PT_PTRACED)) {
+               if ((*status & SPU_STATUS_STOPPED_BY_STOP)
+                   && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
+                       force_sig(SIGTRAP, current);
+                       ret = -ERESTARTSYS;
+               }
+       }
+       return ret;
+}
+
+static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
+                                        u32 *status)
+{
+       int ret;
+
+       if ((ret = spu_run_fini(ctx, npc, status)) != 0)
+               return ret;
+       if (*status & (SPU_STATUS_STOPPED_BY_STOP |
+                      SPU_STATUS_STOPPED_BY_HALT)) {
+               return *status;
+       }
+       if ((ret = spu_run_init(ctx, npc, status)) != 0)
+               return ret;
+       return 0;
+}
+
+static inline int spu_process_events(struct spu_context *ctx)
+{
+       struct spu *spu = ctx->spu;
+       u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
+       int ret = 0;
+
+       if (spu->dsisr & pte_fault)
+               ret = spu_irq_class_1_bottom(spu);
+       if (spu->class_0_pending)
+               ret = spu_irq_class_0_bottom(spu);
+       if (!ret && signal_pending(current))
+               ret = -ERESTARTSYS;
+       return ret;
+}
+
+long spufs_run_spu(struct file *file, struct spu_context *ctx,
+                  u32 * npc, u32 * status)
+{
+       int ret;
+
+       if (down_interruptible(&ctx->run_sema))
+               return -ERESTARTSYS;
+
+       ret = spu_run_init(ctx, npc, status);
+       if (ret)
+               goto out;
+
+       do {
+               ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
+               if (unlikely(ret))
+                       break;
+               if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
+                       ret = spu_reacquire_runnable(ctx, npc, status);
+                       if (ret)
+                               goto out;
+                       continue;
+               }
+               ret = spu_process_events(ctx);
+
+       } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
+                                     SPU_STATUS_STOPPED_BY_HALT)));
+
+       ctx->ops->runcntl_stop(ctx);
+       ret = spu_run_fini(ctx, npc, status);
+       if (!ret)
+               ret = *status;
+       spu_yield(ctx);
+
+out:
+       up(&ctx->run_sema);
+       return ret;
+}
+
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
new file mode 100644 (file)
index 0000000..963182f
--- /dev/null
@@ -0,0 +1,461 @@
+/* sched.c - SPU scheduler.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * SPU scheduler, based on Linux thread priority.  For now use
+ * a simple "cooperative" yield model with no preemption.  SPU
+ * scheduling will eventually be preemptive: When a thread with
+ * a higher static priority gets ready to run, then an active SPU
+ * context will be preempted and returned to the waitq.
+ *
+ * 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.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/completion.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include "spufs.h"
+
+#define SPU_MIN_TIMESLICE      (100 * HZ / 1000)
+
+#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
+struct spu_prio_array {
+       atomic_t nr_blocked;
+       unsigned long bitmap[SPU_BITMAP_SIZE];
+       wait_queue_head_t waitq[MAX_PRIO];
+};
+
+/* spu_runqueue - This is the main runqueue data structure for SPUs. */
+struct spu_runqueue {
+       struct semaphore sem;
+       unsigned long nr_active;
+       unsigned long nr_idle;
+       unsigned long nr_switches;
+       struct list_head active_list;
+       struct list_head idle_list;
+       struct spu_prio_array prio;
+};
+
+static struct spu_runqueue *spu_runqueues = NULL;
+
+static inline struct spu_runqueue *spu_rq(void)
+{
+       /* Future: make this a per-NODE array,
+        * and use cpu_to_node(smp_processor_id())
+        */
+       return spu_runqueues;
+}
+
+static inline struct spu *del_idle(struct spu_runqueue *rq)
+{
+       struct spu *spu;
+
+       BUG_ON(rq->nr_idle <= 0);
+       BUG_ON(list_empty(&rq->idle_list));
+       /* Future: Move SPU out of low-power SRI state. */
+       spu = list_entry(rq->idle_list.next, struct spu, sched_list);
+       list_del_init(&spu->sched_list);
+       rq->nr_idle--;
+       return spu;
+}
+
+static inline void del_active(struct spu_runqueue *rq, struct spu *spu)
+{
+       BUG_ON(rq->nr_active <= 0);
+       BUG_ON(list_empty(&rq->active_list));
+       list_del_init(&spu->sched_list);
+       rq->nr_active--;
+}
+
+static inline void add_idle(struct spu_runqueue *rq, struct spu *spu)
+{
+       /* Future: Put SPU into low-power SRI state. */
+       list_add_tail(&spu->sched_list, &rq->idle_list);
+       rq->nr_idle++;
+}
+
+static inline void add_active(struct spu_runqueue *rq, struct spu *spu)
+{
+       rq->nr_active++;
+       rq->nr_switches++;
+       list_add_tail(&spu->sched_list, &rq->active_list);
+}
+
+static void prio_wakeup(struct spu_runqueue *rq)
+{
+       if (atomic_read(&rq->prio.nr_blocked) && rq->nr_idle) {
+               int best = sched_find_first_bit(rq->prio.bitmap);
+               if (best < MAX_PRIO) {
+                       wait_queue_head_t *wq = &rq->prio.waitq[best];
+                       wake_up_interruptible_nr(wq, 1);
+               }
+       }
+}
+
+static void prio_wait(struct spu_runqueue *rq, struct spu_context *ctx,
+                     u64 flags)
+{
+       int prio = current->prio;
+       wait_queue_head_t *wq = &rq->prio.waitq[prio];
+       DEFINE_WAIT(wait);
+
+       __set_bit(prio, rq->prio.bitmap);
+       atomic_inc(&rq->prio.nr_blocked);
+       prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE);
+       if (!signal_pending(current)) {
+               up(&rq->sem);
+               up_write(&ctx->state_sema);
+               pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
+                        current->pid, current->prio);
+               schedule();
+               down_write(&ctx->state_sema);
+               down(&rq->sem);
+       }
+       finish_wait(wq, &wait);
+       atomic_dec(&rq->prio.nr_blocked);
+       if (!waitqueue_active(wq))
+               __clear_bit(prio, rq->prio.bitmap);
+}
+
+static inline int is_best_prio(struct spu_runqueue *rq)
+{
+       int best_prio;
+
+       best_prio = sched_find_first_bit(rq->prio.bitmap);
+       return (current->prio < best_prio) ? 1 : 0;
+}
+
+static inline void mm_needs_global_tlbie(struct mm_struct *mm)
+{
+       /* Global TLBIE broadcast required with SPEs. */
+#if (NR_CPUS > 1)
+       __cpus_setall(&mm->cpu_vm_mask, NR_CPUS);
+#else
+       __cpus_setall(&mm->cpu_vm_mask, NR_CPUS+1); /* is this ok? */
+#endif
+}
+
+static inline void bind_context(struct spu *spu, struct spu_context *ctx)
+{
+       pr_debug("%s: pid=%d SPU=%d\n", __FUNCTION__, current->pid,
+                spu->number);
+       spu->ctx = ctx;
+       spu->flags = 0;
+       ctx->flags = 0;
+       ctx->spu = spu;
+       ctx->ops = &spu_hw_ops;
+       spu->pid = current->pid;
+       spu->prio = current->prio;
+       spu->mm = ctx->owner;
+       mm_needs_global_tlbie(spu->mm);
+       spu->ibox_callback = spufs_ibox_callback;
+       spu->wbox_callback = spufs_wbox_callback;
+       spu->stop_callback = spufs_stop_callback;
+       mb();
+       spu_unmap_mappings(ctx);
+       spu_restore(&ctx->csa, spu);
+       spu->timestamp = jiffies;
+}
+
+static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
+{
+       pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__,
+                spu->pid, spu->number);
+       spu_unmap_mappings(ctx);
+       spu_save(&ctx->csa, spu);
+       spu->timestamp = jiffies;
+       ctx->state = SPU_STATE_SAVED;
+       spu->ibox_callback = NULL;
+       spu->wbox_callback = NULL;
+       spu->stop_callback = NULL;
+       spu->mm = NULL;
+       spu->pid = 0;
+       spu->prio = MAX_PRIO;
+       ctx->ops = &spu_backing_ops;
+       ctx->spu = NULL;
+       ctx->flags = 0;
+       spu->flags = 0;
+       spu->ctx = NULL;
+}
+
+static void spu_reaper(void *data)
+{
+       struct spu_context *ctx = data;
+       struct spu *spu;
+
+       down_write(&ctx->state_sema);
+       spu = ctx->spu;
+       if (spu && test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
+               if (atomic_read(&spu->rq->prio.nr_blocked)) {
+                       pr_debug("%s: spu=%d\n", __func__, spu->number);
+                       ctx->ops->runcntl_stop(ctx);
+                       spu_deactivate(ctx);
+                       wake_up_all(&ctx->stop_wq);
+               } else {
+                       clear_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
+               }
+       }
+       up_write(&ctx->state_sema);
+       put_spu_context(ctx);
+}
+
+static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu)
+{
+       struct spu_context *ctx = get_spu_context(spu->ctx);
+       unsigned long now = jiffies;
+       unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE;
+
+       set_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
+       INIT_WORK(&ctx->reap_work, spu_reaper, ctx);
+       if (time_after(now, expire))
+               schedule_work(&ctx->reap_work);
+       else
+               schedule_delayed_work(&ctx->reap_work, expire - now);
+}
+
+static void check_preempt_active(struct spu_runqueue *rq)
+{
+       struct list_head *p;
+       struct spu *worst = NULL;
+
+       list_for_each(p, &rq->active_list) {
+               struct spu *spu = list_entry(p, struct spu, sched_list);
+               struct spu_context *ctx = spu->ctx;
+               if (!test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
+                       if (!worst || (spu->prio > worst->prio)) {
+                               worst = spu;
+                       }
+               }
+       }
+       if (worst && (current->prio < worst->prio))
+               schedule_spu_reaper(rq, worst);
+}
+
+static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags)
+{
+       struct spu_runqueue *rq;
+       struct spu *spu = NULL;
+
+       rq = spu_rq();
+       down(&rq->sem);
+       for (;;) {
+               if (rq->nr_idle > 0) {
+                       if (is_best_prio(rq)) {
+                               /* Fall through. */
+                               spu = del_idle(rq);
+                               break;
+                       } else {
+                               prio_wakeup(rq);
+                               up(&rq->sem);
+                               yield();
+                               if (signal_pending(current)) {
+                                       return NULL;
+                               }
+                               rq = spu_rq();
+                               down(&rq->sem);
+                               continue;
+                       }
+               } else {
+                       check_preempt_active(rq);
+                       prio_wait(rq, ctx, flags);
+                       if (signal_pending(current)) {
+                               prio_wakeup(rq);
+                               spu = NULL;
+                               break;
+                       }
+                       continue;
+               }
+       }
+       up(&rq->sem);
+       return spu;
+}
+
+static void put_idle_spu(struct spu *spu)
+{
+       struct spu_runqueue *rq = spu->rq;
+
+       down(&rq->sem);
+       add_idle(rq, spu);
+       prio_wakeup(rq);
+       up(&rq->sem);
+}
+
+static int get_active_spu(struct spu *spu)
+{
+       struct spu_runqueue *rq = spu->rq;
+       struct list_head *p;
+       struct spu *tmp;
+       int rc = 0;
+
+       down(&rq->sem);
+       list_for_each(p, &rq->active_list) {
+               tmp = list_entry(p, struct spu, sched_list);
+               if (tmp == spu) {
+                       del_active(rq, spu);
+                       rc = 1;
+                       break;
+               }
+       }
+       up(&rq->sem);
+       return rc;
+}
+
+static void put_active_spu(struct spu *spu)
+{
+       struct spu_runqueue *rq = spu->rq;
+
+       down(&rq->sem);
+       add_active(rq, spu);
+       up(&rq->sem);
+}
+
+/* Lock order:
+ *     spu_activate() & spu_deactivate() require the
+ *     caller to have down_write(&ctx->state_sema).
+ *
+ *     The rq->sem is breifly held (inside or outside a
+ *     given ctx lock) for list management, but is never
+ *     held during save/restore.
+ */
+
+int spu_activate(struct spu_context *ctx, u64 flags)
+{
+       struct spu *spu;
+
+       if (ctx->spu)
+               return 0;
+       spu = get_idle_spu(ctx, flags);
+       if (!spu)
+               return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
+       bind_context(spu, ctx);
+       /*
+        * We're likely to wait for interrupts on the same
+        * CPU that we are now on, so send them here.
+        */
+       spu_irq_setaffinity(spu, raw_smp_processor_id());
+       put_active_spu(spu);
+       return 0;
+}
+
+void spu_deactivate(struct spu_context *ctx)
+{
+       struct spu *spu;
+       int needs_idle;
+
+       spu = ctx->spu;
+       if (!spu)
+               return;
+       needs_idle = get_active_spu(spu);
+       unbind_context(spu, ctx);
+       if (needs_idle)
+               put_idle_spu(spu);
+}
+
+void spu_yield(struct spu_context *ctx)
+{
+       struct spu *spu;
+       int need_yield = 0;
+
+       down_write(&ctx->state_sema);
+       spu = ctx->spu;
+       if (spu && (sched_find_first_bit(spu->rq->prio.bitmap) < MAX_PRIO)) {
+               pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number);
+               spu_deactivate(ctx);
+               ctx->state = SPU_STATE_SAVED;
+               need_yield = 1;
+       } else if (spu) {
+               spu->prio = MAX_PRIO;
+       }
+       up_write(&ctx->state_sema);
+       if (unlikely(need_yield))
+               yield();
+}
+
+int __init spu_sched_init(void)
+{
+       struct spu_runqueue *rq;
+       struct spu *spu;
+       int i;
+
+       rq = spu_runqueues = kmalloc(sizeof(struct spu_runqueue), GFP_KERNEL);
+       if (!rq) {
+               printk(KERN_WARNING "%s: Unable to allocate runqueues.\n",
+                      __FUNCTION__);
+               return 1;
+       }
+       memset(rq, 0, sizeof(struct spu_runqueue));
+       init_MUTEX(&rq->sem);
+       INIT_LIST_HEAD(&rq->active_list);
+       INIT_LIST_HEAD(&rq->idle_list);
+       rq->nr_active = 0;
+       rq->nr_idle = 0;
+       rq->nr_switches = 0;
+       atomic_set(&rq->prio.nr_blocked, 0);
+       for (i = 0; i < MAX_PRIO; i++) {
+               init_waitqueue_head(&rq->prio.waitq[i]);
+               __clear_bit(i, rq->prio.bitmap);
+       }
+       __set_bit(MAX_PRIO, rq->prio.bitmap);
+       for (;;) {
+               spu = spu_alloc();
+               if (!spu)
+                       break;
+               pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number);
+               add_idle(rq, spu);
+               spu->rq = rq;
+               spu->timestamp = jiffies;
+       }
+       if (!rq->nr_idle) {
+               printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__);
+               kfree(rq);
+               return 1;
+       }
+       return 0;
+}
+
+void __exit spu_sched_exit(void)
+{
+       struct spu_runqueue *rq = spu_rq();
+       struct spu *spu;
+
+       if (!rq) {
+               printk(KERN_WARNING "%s: no runqueues!\n", __FUNCTION__);
+               return;
+       }
+       while (rq->nr_idle > 0) {
+               spu = del_idle(rq);
+               if (!spu)
+                       break;
+               spu_free(spu);
+       }
+       kfree(rq);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore.c b/arch/powerpc/platforms/cell/spufs/spu_restore.c
new file mode 100644 (file)
index 0000000..0bf723d
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * spu_restore.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * SPU-side context restore sequence outlined in
+ * Synergistic Processor Element Book IV
+ *
+ * Author: Mark Nutter <mnutter@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, 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 LS_SIZE
+#define LS_SIZE                 0x40000        /* 256K (in bytes) */
+#endif
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+#include <spu_intrinsics.h>
+#include <asm/spu_csa.h>
+#include "spu_utils.h"
+
+#define BR_INSTR               0x327fff80      /* br -4         */
+#define NOP_INSTR              0x40200000      /* nop           */
+#define HEQ_INSTR              0x7b000000      /* heq $0, $0    */
+#define STOP_INSTR             0x00000000      /* stop 0x0      */
+#define ILLEGAL_INSTR          0x00800000      /* illegal instr */
+#define RESTORE_COMPLETE       0x00003ffc      /* stop 0x3ffc   */
+
+static inline void fetch_regs_from_mem(addr64 lscsa_ea)
+{
+       unsigned int ls = (unsigned int)&regs_spill[0];
+       unsigned int size = sizeof(regs_spill);
+       unsigned int tag_id = 0;
+       unsigned int cmd = 0x40;        /* GET */
+
+       spu_writech(MFC_LSA, ls);
+       spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+       spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+       spu_writech(MFC_Size, size);
+       spu_writech(MFC_TagID, tag_id);
+       spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void restore_upper_240kb(addr64 lscsa_ea)
+{
+       unsigned int ls = 16384;
+       unsigned int list = (unsigned int)&dma_list[0];
+       unsigned int size = sizeof(dma_list);
+       unsigned int tag_id = 0;
+       unsigned int cmd = 0x44;        /* GETL */
+
+       /* Restore, Step 4:
+        *    Enqueue the GETL command (tag 0) to the MFC SPU command
+        *    queue to transfer the upper 240 kb of LS from CSA.
+        */
+       spu_writech(MFC_LSA, ls);
+       spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+       spu_writech(MFC_EAL, list);
+       spu_writech(MFC_Size, size);
+       spu_writech(MFC_TagID, tag_id);
+       spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void restore_decr(void)
+{
+       unsigned int offset;
+       unsigned int decr_running;
+       unsigned int decr;
+
+       /* Restore, Step 6:
+        *    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];
+       if (decr_running) {
+               offset = LSCSA_QW_OFFSET(decr);
+               decr = regs_spill[offset].slot[0];
+               spu_writech(SPU_WrDec, decr);
+       }
+}
+
+static inline void write_ppu_mb(void)
+{
+       unsigned int offset;
+       unsigned int data;
+
+       /* Restore, Step 11:
+        *    Write the MFC_WrOut_MB channel with the PPU_MB
+        *    data from LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(ppu_mb);
+       data = regs_spill[offset].slot[0];
+       spu_writech(SPU_WrOutMbox, data);
+}
+
+static inline void write_ppuint_mb(void)
+{
+       unsigned int offset;
+       unsigned int data;
+
+       /* Restore, Step 12:
+        *    Write the MFC_WrInt_MB channel with the PPUINT_MB
+        *    data from LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(ppuint_mb);
+       data = regs_spill[offset].slot[0];
+       spu_writech(SPU_WrOutIntrMbox, data);
+}
+
+static inline void restore_fpcr(void)
+{
+       unsigned int offset;
+       vector unsigned int fpcr;
+
+       /* Restore, Step 13:
+        *    Restore the floating-point status and control
+        *    register from the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(fpcr);
+       fpcr = regs_spill[offset].v;
+       spu_mtfpscr(fpcr);
+}
+
+static inline void restore_srr0(void)
+{
+       unsigned int offset;
+       unsigned int srr0;
+
+       /* Restore, Step 14:
+        *    Restore the SPU SRR0 data from the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(srr0);
+       srr0 = regs_spill[offset].slot[0];
+       spu_writech(SPU_WrSRR0, srr0);
+}
+
+static inline void restore_event_mask(void)
+{
+       unsigned int offset;
+       unsigned int event_mask;
+
+       /* Restore, Step 15:
+        *    Restore the SPU_RdEventMsk data from the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(event_mask);
+       event_mask = regs_spill[offset].slot[0];
+       spu_writech(SPU_WrEventMask, event_mask);
+}
+
+static inline void restore_tag_mask(void)
+{
+       unsigned int offset;
+       unsigned int tag_mask;
+
+       /* Restore, Step 16:
+        *    Restore the SPU_RdTagMsk data from the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(tag_mask);
+       tag_mask = regs_spill[offset].slot[0];
+       spu_writech(MFC_WrTagMask, tag_mask);
+}
+
+static inline void restore_complete(void)
+{
+       extern void exit_fini(void);
+       unsigned int *exit_instrs = (unsigned int *)exit_fini;
+       unsigned int offset;
+       unsigned int stopped_status;
+       unsigned int stopped_code;
+
+       /* Restore, Step 18:
+        *    Issue a stop-and-signal instruction with
+        *    "good context restore" signal value.
+        *
+        * Restore, Step 19:
+        *    There may be additional instructions placed
+        *    here by the PPE Sequence for SPU Context
+        *    Restore in order to restore the correct
+        *    "stopped state".
+        *
+        *    This step is handled here by analyzing the
+        *    LSCSA.stopped_status and then modifying the
+        *    exit() function to behave appropriately.
+        */
+
+       offset = LSCSA_QW_OFFSET(stopped_status);
+       stopped_status = regs_spill[offset].slot[0];
+       stopped_code = regs_spill[offset].slot[1];
+
+       switch (stopped_status) {
+       case SPU_STOPPED_STATUS_P_I:
+               /* SPU_Status[P,I]=1.  Add illegal instruction
+                * followed by stop-and-signal instruction after
+                * end of restore code.
+                */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = ILLEGAL_INSTR;
+               exit_instrs[2] = STOP_INSTR | stopped_code;
+               break;
+       case SPU_STOPPED_STATUS_P_H:
+               /* SPU_Status[P,H]=1.  Add 'heq $0, $0' followed
+                * by stop-and-signal instruction after end of
+                * restore code.
+                */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = HEQ_INSTR;
+               exit_instrs[2] = STOP_INSTR | stopped_code;
+               break;
+       case SPU_STOPPED_STATUS_S_P:
+               /* SPU_Status[S,P]=1.  Add nop instruction
+                * followed by 'br -4' after end of restore
+                * code.
+                */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = STOP_INSTR | stopped_code;
+               exit_instrs[2] = NOP_INSTR;
+               exit_instrs[3] = BR_INSTR;
+               break;
+       case SPU_STOPPED_STATUS_S_I:
+               /* SPU_Status[S,I]=1.  Add  illegal instruction
+                * followed by 'br -4' after end of restore code.
+                */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = ILLEGAL_INSTR;
+               exit_instrs[2] = NOP_INSTR;
+               exit_instrs[3] = BR_INSTR;
+               break;
+       case SPU_STOPPED_STATUS_I:
+               /* SPU_Status[I]=1. Add illegal instruction followed
+                * by infinite loop after end of restore sequence.
+                */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = ILLEGAL_INSTR;
+               exit_instrs[2] = NOP_INSTR;
+               exit_instrs[3] = BR_INSTR;
+               break;
+       case SPU_STOPPED_STATUS_S:
+               /* SPU_Status[S]=1. Add two 'nop' instructions. */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = NOP_INSTR;
+               exit_instrs[2] = NOP_INSTR;
+               exit_instrs[3] = BR_INSTR;
+               break;
+       case SPU_STOPPED_STATUS_H:
+               /* SPU_Status[H]=1. Add 'heq $0, $0' instruction
+                * after end of restore code.
+                */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = HEQ_INSTR;
+               exit_instrs[2] = NOP_INSTR;
+               exit_instrs[3] = BR_INSTR;
+               break;
+       case SPU_STOPPED_STATUS_P:
+               /* SPU_Status[P]=1. Add stop-and-signal instruction
+                * after end of restore code.
+                */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = STOP_INSTR | stopped_code;
+               break;
+       case SPU_STOPPED_STATUS_R:
+               /* SPU_Status[I,S,H,P,R]=0. Add infinite loop. */
+               exit_instrs[0] = RESTORE_COMPLETE;
+               exit_instrs[1] = NOP_INSTR;
+               exit_instrs[2] = NOP_INSTR;
+               exit_instrs[3] = BR_INSTR;
+               break;
+       default:
+               /* SPU_Status[R]=1. No additonal instructions. */
+               break;
+       }
+       spu_sync();
+}
+
+/**
+ * main - entry point for SPU-side context restore.
+ *
+ * This code deviates from the documented sequence in the
+ * following aspects:
+ *
+ *     1. The EA for LSCSA is passed from PPE in the
+ *        signal notification channels.
+ *     2. The register spill area is pulled by SPU
+ *        into LS, rather than pushed by PPE.
+ *     3. All 128 registers are restored by exit().
+ *     4. The exit() function is modified at run
+ *        time in order to properly restore the
+ *        SPU_Status register.
+ */
+int main()
+{
+       addr64 lscsa_ea;
+
+       lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
+       lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
+       fetch_regs_from_mem(lscsa_ea);
+
+       set_event_mask();               /* Step 1.  */
+       set_tag_mask();                 /* Step 2.  */
+       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. */
+       read_llar_status();             /* Step 10. */
+       write_ppu_mb();                 /* Step 11. */
+       write_ppuint_mb();              /* Step 12. */
+       restore_fpcr();                 /* Step 13. */
+       restore_srr0();                 /* Step 14. */
+       restore_event_mask();           /* Step 15. */
+       restore_tag_mask();             /* Step 16. */
+                                       /* Step 17. done by 'exit'. */
+       restore_complete();             /* Step 18. */
+
+       return 0;
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S b/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S
new file mode 100644 (file)
index 0000000..2905949
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * crt0_r.S: Entry function for SPU-side context restore.
+ *
+ * Copyright (C) 2005 IBM
+ *
+ * Entry and exit function for SPU-side of the context restore
+ * sequence.  Sets up an initial stack frame, then branches to
+ * 'main'.  On return, restores all 128 registers from the LSCSA
+ * and exits.
+ *
+ *
+ * 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 <asm/spu_csa.h>
+
+.data
+.align 7
+.globl regs_spill
+regs_spill:
+.space SIZEOF_SPU_SPILL_REGS, 0x0
+
+.text
+.global _start
+_start:
+       /* Initialize the stack pointer to point to 16368
+        * (16kb-16). The back chain pointer is initialized
+        * to NULL.
+        */
+       il      $0, 0
+       il      $SP, 16368
+       stqd    $0, 0($SP)
+
+       /* Allocate a minimum stack frame for the called main.
+        * This is needed so that main has a place to save the
+        * link register when it calls another function.
+        */
+       stqd    $SP, -160($SP)
+       ai      $SP, $SP, -160
+
+       /* Call the program's main function. */
+       brsl    $0, main
+
+.global exit
+.global        _exit
+exit:
+_exit:
+       /* SPU Context Restore, Step 5: Restore the remaining 112 GPRs. */
+       ila     $3, regs_spill + 256
+restore_regs:
+       lqr     $4, restore_reg_insts
+restore_reg_loop:
+       ai      $4, $4, 4
+       .balignl 16, 0x40200000
+restore_reg_insts:       /* must be quad-word aligned. */
+       lqd     $16, 0($3)
+       lqd     $17, 16($3)
+       lqd     $18, 32($3)
+       lqd     $19, 48($3)
+       andi    $5, $4, 0x7F
+       stqr    $4, restore_reg_insts
+       ai      $3, $3, 64
+       brnz    $5, restore_reg_loop
+
+       /* SPU Context Restore Step 17: Restore the first 16 GPRs. */
+       lqa $0, regs_spill + 0
+       lqa $1, regs_spill + 16
+       lqa $2, regs_spill + 32
+       lqa $3, regs_spill + 48
+       lqa $4, regs_spill + 64
+       lqa $5, regs_spill + 80
+       lqa $6, regs_spill + 96
+       lqa $7, regs_spill + 112
+       lqa $8, regs_spill + 128
+       lqa $9, regs_spill + 144
+       lqa $10, regs_spill + 160
+       lqa $11, regs_spill + 176
+       lqa $12, regs_spill + 192
+       lqa $13, regs_spill + 208
+       lqa $14, regs_spill + 224
+       lqa $15, regs_spill + 240
+
+       /* Under normal circumstances, the 'exit' function
+        * terminates with 'stop SPU_RESTORE_COMPLETE',
+        * indicating that the SPU-side restore code has
+        * completed.
+        *
+        * However it is possible that instructions immediately
+        * following the 'stop 0x3ffc' have been modified at run
+        * time so as to recreate the exact SPU_Status settings
+        * from the application, e.g. illegal instruciton, halt,
+        * etc.
+        */
+.global exit_fini
+.global        _exit_fini
+exit_fini:
+_exit_fini:
+       stop    SPU_RESTORE_COMPLETE
+       stop    0
+       stop    0
+       stop    0
+
+       /* Pad the size of this crt0.o to be multiple of 16 bytes. */
+.balignl 16, 0x0
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
new file mode 100644 (file)
index 0000000..1b2355f
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * spu_restore_dump.h: Copyright (C) 2005 IBM.
+ * Hex-dump auto generated from spu_restore.c.
+ * Do not edit!
+ */
+static unsigned int spu_restore_code[] __page_aligned = {
+0x40800000, 0x409ff801, 0x24000080, 0x24fd8081,
+0x1cd80081, 0x33001180, 0x42030003, 0x33800284,
+0x1c010204, 0x40200000, 0x40200000, 0x40200000,
+0x34000190, 0x34004191, 0x34008192, 0x3400c193,
+0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffa85,
+0x3080a000, 0x3080a201, 0x3080a402, 0x3080a603,
+0x3080a804, 0x3080aa05, 0x3080ac06, 0x3080ae07,
+0x3080b008, 0x3080b209, 0x3080b40a, 0x3080b60b,
+0x3080b80c, 0x3080ba0d, 0x3080bc0e, 0x3080be0f,
+0x00003ffc, 0x00000000, 0x00000000, 0x00000000,
+0x01a00182, 0x3ec00083, 0xb0a14103, 0x01a00204,
+0x3ec10082, 0x4202800e, 0x04000703, 0xb0a14202,
+0x21a00803, 0x3fbf028d, 0x3f20068d, 0x3fbe0682,
+0x3fe30102, 0x21a00882, 0x3f82028f, 0x3fe3078f,
+0x3fbf0784, 0x3f200204, 0x3fbe0204, 0x3fe30204,
+0x04000203, 0x21a00903, 0x40848002, 0x21a00982,
+0x40800003, 0x21a00a03, 0x40802002, 0x21a00a82,
+0x21a00083, 0x40800082, 0x21a00b02, 0x10002818,
+0x40a80002, 0x32800007, 0x4207000c, 0x18008208,
+0x40a0000b, 0x4080020a, 0x40800709, 0x00200000,
+0x42070002, 0x3ac30384, 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, 0x40802202, 0x21a00a82, 0x42028005,
+0x34208702, 0x21002282, 0x21a00804, 0x21a00886,
+0x3fbf0782, 0x3f200102, 0x3fbe0102, 0x3fe30102,
+0x21a00902, 0x40804003, 0x21a00983, 0x21a00a04,
+0x40805a02, 0x21a00a82, 0x40800083, 0x21a00b83,
+0x01a00c02, 0x01a00d83, 0x3420c282, 0x21a00e02,
+0x34210283, 0x21a00f03, 0x34200284, 0x77400200,
+0x3421c282, 0x21a00702, 0x34218283, 0x21a00083,
+0x34214282, 0x21a00b02, 0x4200480c, 0x00200000,
+0x1c010286, 0x34220284, 0x34220302, 0x0f608203,
+0x5c024204, 0x3b81810b, 0x42013c02, 0x00200000,
+0x18008185, 0x38808183, 0x3b814182, 0x21004e84,
+0x4020007f, 0x35000100, 0x000004e0, 0x000002a0,
+0x000002e8, 0x00000428, 0x00000360, 0x000002e8,
+0x000004a0, 0x00000468, 0x000003c8, 0x00000360,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40085,
+0x10009c09, 0x3ac10606, 0xb060c105, 0x4020007f,
+0x4020007f, 0x20801203, 0x38810602, 0xb0408586,
+0x28810602, 0x32004180, 0x34204702, 0x21a00382,
+0x4020007f, 0x327fdc80, 0x409ffe02, 0x30801203,
+0x40800204, 0x3ec40087, 0x40800405, 0x00200000,
+0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a,
+0xb060c107, 0x20801203, 0x41004003, 0x38810602,
+0x4020007f, 0xb0408188, 0x4020007f, 0x28810602,
+0x41201002, 0x38814603, 0x10009c09, 0xb060c109,
+0x4020007f, 0x28814603, 0x41193f83, 0x38818602,
+0x60ffc003, 0xb040818a, 0x28818602, 0x32003080,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087,
+0x41201008, 0x10009c14, 0x40800405, 0x3ac10609,
+0x40800606, 0x3ac1460a, 0xb060c107, 0x3ac1860b,
+0x20801203, 0x38810602, 0xb0408409, 0x28810602,
+0x38814603, 0xb060c40a, 0x4020007f, 0x28814603,
+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, 0x4020007f, 0xb0408588, 0x28818602,
+0x4020007f, 0x32001780, 0x409ffe02, 0x1000640e,
+0x40800204, 0x30801203, 0x40800405, 0x3ec40087,
+0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a,
+0xb060c107, 0x20801203, 0x413d8003, 0x38810602,
+0x4020007f, 0x327fd780, 0x409ffe02, 0x10007f0c,
+0x40800205, 0x30801204, 0x40800406, 0x3ec40083,
+0x3ac14607, 0x3ac18608, 0xb0810103, 0x413d8002,
+0x20801204, 0x38814603, 0x4020007f, 0x327feb80,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087,
+0x40800405, 0x1000650a, 0x40800606, 0x3ac10608,
+0x3ac14609, 0x3ac1860a, 0xb060c107, 0x20801203,
+0x38810602, 0xb0408588, 0x4020007f, 0x327fc980,
+0x00400000, 0x40800003, 0x4020007f, 0x35000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save.c b/arch/powerpc/platforms/cell/spufs/spu_save.c
new file mode 100644 (file)
index 0000000..196033b
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * spu_save.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * SPU-side context save sequence outlined in
+ * Synergistic Processor Element Book IV
+ *
+ * Author: Mark Nutter <mnutter@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, 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 LS_SIZE
+#define LS_SIZE                 0x40000        /* 256K (in bytes) */
+#endif
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+#include <spu_intrinsics.h>
+#include <asm/spu_csa.h>
+#include "spu_utils.h"
+
+static inline void save_event_mask(void)
+{
+       unsigned int offset;
+
+       /* Save, Step 2:
+        *    Read the SPU_RdEventMsk channel and save to the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(event_mask);
+       regs_spill[offset].slot[0] = spu_readch(SPU_RdEventStatMask);
+}
+
+static inline void save_tag_mask(void)
+{
+       unsigned int offset;
+
+       /* Save, Step 3:
+        *    Read the SPU_RdTagMsk channel and save to the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(tag_mask);
+       regs_spill[offset].slot[0] = spu_readch(MFC_RdTagMask);
+}
+
+static inline void save_upper_240kb(addr64 lscsa_ea)
+{
+       unsigned int ls = 16384;
+       unsigned int list = (unsigned int)&dma_list[0];
+       unsigned int size = sizeof(dma_list);
+       unsigned int tag_id = 0;
+       unsigned int cmd = 0x24;        /* PUTL */
+
+       /* Save, Step 7:
+        *    Enqueue the PUTL command (tag 0) to the MFC SPU command
+        *    queue to transfer the remaining 240 kb of LS to CSA.
+        */
+       spu_writech(MFC_LSA, ls);
+       spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+       spu_writech(MFC_EAL, list);
+       spu_writech(MFC_Size, size);
+       spu_writech(MFC_TagID, tag_id);
+       spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void save_fpcr(void)
+{
+       // vector unsigned int fpcr;
+       unsigned int offset;
+
+       /* Save, Step 9:
+        *    Issue the floating-point status and control register
+        *    read instruction, and save to the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(fpcr);
+       regs_spill[offset].v = spu_mffpscr();
+}
+
+static inline void save_decr(void)
+{
+       unsigned int offset;
+
+       /* Save, Step 10:
+        *    Read and save the SPU_RdDec channel data to
+        *    the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(decr);
+       regs_spill[offset].slot[0] = spu_readch(SPU_RdDec);
+}
+
+static inline void save_srr0(void)
+{
+       unsigned int offset;
+
+       /* Save, Step 11:
+        *    Read and save the SPU_WSRR0 channel data to
+        *    the LSCSA.
+        */
+       offset = LSCSA_QW_OFFSET(srr0);
+       regs_spill[offset].slot[0] = spu_readch(SPU_RdSRR0);
+}
+
+static inline void spill_regs_to_mem(addr64 lscsa_ea)
+{
+       unsigned int ls = (unsigned int)&regs_spill[0];
+       unsigned int size = sizeof(regs_spill);
+       unsigned int tag_id = 0;
+       unsigned int cmd = 0x20;        /* PUT */
+
+       /* Save, Step 13:
+        *    Enqueue a PUT command (tag 0) to send the LSCSA
+        *    to the CSA.
+        */
+       spu_writech(MFC_LSA, ls);
+       spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+       spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+       spu_writech(MFC_Size, size);
+       spu_writech(MFC_TagID, tag_id);
+       spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void enqueue_sync(addr64 lscsa_ea)
+{
+       unsigned int tag_id = 0;
+       unsigned int cmd = 0xCC;
+
+       /* Save, Step 14:
+        *    Enqueue an MFC_SYNC command (tag 0).
+        */
+       spu_writech(MFC_TagID, tag_id);
+       spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void save_complete(void)
+{
+       /* Save, Step 18:
+        *    Issue a stop-and-signal instruction indicating
+        *    "save complete".  Note: This function will not
+        *    return!!
+        */
+       spu_stop(SPU_SAVE_COMPLETE);
+}
+
+/**
+ * main - entry point for SPU-side context save.
+ *
+ * This code deviates from the documented sequence as follows:
+ *
+ *      1. The EA for LSCSA is passed from PPE in the
+ *         signal notification channels.
+ *      2. All 128 registers are saved by crt0.o.
+ */
+int main()
+{
+       addr64 lscsa_ea;
+
+       lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
+       lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
+
+       /* Step 1: done by exit(). */
+       save_event_mask();      /* Step 2.  */
+       save_tag_mask();        /* Step 3.  */
+       set_event_mask();       /* Step 4.  */
+       set_tag_mask();         /* Step 5.  */
+       build_dma_list(lscsa_ea);       /* Step 6.  */
+       save_upper_240kb(lscsa_ea);     /* Step 7.  */
+       /* Step 8: done by exit(). */
+       save_fpcr();            /* Step 9.  */
+       save_decr();            /* Step 10. */
+       save_srr0();            /* Step 11. */
+       enqueue_putllc(lscsa_ea);       /* Step 12. */
+       spill_regs_to_mem(lscsa_ea);    /* Step 13. */
+       enqueue_sync(lscsa_ea); /* Step 14. */
+       set_tag_update();       /* Step 15. */
+       read_tag_status();      /* Step 16. */
+       read_llar_status();     /* Step 17. */
+       save_complete();        /* Step 18. */
+
+       return 0;
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S b/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S
new file mode 100644 (file)
index 0000000..6659d6a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * crt0_s.S: Entry function for SPU-side context save.
+ *
+ * Copyright (C) 2005 IBM
+ *
+ * Entry function for SPU-side of the context save sequence.
+ * Saves all 128 GPRs, sets up an initial stack frame, then
+ * branches to 'main'.
+ *
+ *
+ * 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 <asm/spu_csa.h>
+
+.data
+.align 7
+.globl regs_spill
+regs_spill:
+.space SIZEOF_SPU_SPILL_REGS, 0x0
+
+.text
+.global _start
+_start:
+       /* SPU Context Save Step 1: Save the first 16 GPRs. */
+       stqa $0, regs_spill + 0
+       stqa $1, regs_spill + 16
+       stqa $2, regs_spill + 32
+       stqa $3, regs_spill + 48
+       stqa $4, regs_spill + 64
+       stqa $5, regs_spill + 80
+       stqa $6, regs_spill + 96
+       stqa $7, regs_spill + 112
+       stqa $8, regs_spill + 128
+       stqa $9, regs_spill + 144
+       stqa $10, regs_spill + 160
+       stqa $11, regs_spill + 176
+       stqa $12, regs_spill + 192
+       stqa $13, regs_spill + 208
+       stqa $14, regs_spill + 224
+       stqa $15, regs_spill + 240
+
+       /* SPU Context Save, Step 8: Save the remaining 112 GPRs. */
+       ila     $3, regs_spill + 256
+save_regs:
+       lqr     $4, save_reg_insts
+save_reg_loop:
+       ai      $4, $4, 4
+       .balignl 16, 0x40200000
+save_reg_insts:       /* must be quad-word aligned. */
+       stqd    $16, 0($3)
+       stqd    $17, 16($3)
+       stqd    $18, 32($3)
+       stqd    $19, 48($3)
+       andi    $5, $4, 0x7F
+       stqr    $4, save_reg_insts
+       ai      $3, $3, 64
+       brnz    $5, save_reg_loop
+
+       /* Initialize the stack pointer to point to 16368
+        * (16kb-16). The back chain pointer is initialized
+        * to NULL.
+        */
+       il      $0, 0
+       il      $SP, 16368
+       stqd    $0, 0($SP)
+
+       /* Allocate a minimum stack frame for the called main.
+        * This is needed so that main has a place to save the
+        * link register when it calls another function.
+        */
+       stqd    $SP, -160($SP)
+       ai      $SP, $SP, -160
+
+       /* Call the program's main function. */
+       brsl    $0, main
+
+       /* In this case main should not return; if it does
+        * there has been an error in the sequence.  Execute
+        * stop-and-signal with code=0.
+        */
+.global exit
+.global        _exit
+exit:
+_exit:
+       stop    0x0
+
+       /* Pad the size of this crt0.o to be multiple of 16 bytes. */
+.balignl 16, 0x0
+
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped
new file mode 100644 (file)
index 0000000..39e5400
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * spu_save_dump.h: Copyright (C) 2005 IBM.
+ * Hex-dump auto generated from spu_save.c.
+ * Do not edit!
+ */
+static unsigned int spu_save_code[] __page_aligned = {
+0x20805000, 0x20805201, 0x20805402, 0x20805603,
+0x20805804, 0x20805a05, 0x20805c06, 0x20805e07,
+0x20806008, 0x20806209, 0x2080640a, 0x2080660b,
+0x2080680c, 0x20806a0d, 0x20806c0e, 0x20806e0f,
+0x4201c003, 0x33800184, 0x1c010204, 0x40200000,
+0x24000190, 0x24004191, 0x24008192, 0x2400c193,
+0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffb85,
+0x40800000, 0x409ff801, 0x24000080, 0x24fd8081,
+0x1cd80081, 0x33000180, 0x00000000, 0x00000000,
+0x01a00182, 0x3ec00083, 0xb1c38103, 0x01a00204,
+0x3ec10082, 0x4201400d, 0xb1c38202, 0x01a00583,
+0x34218682, 0x3ed80684, 0xb0408184, 0x24218682,
+0x01a00603, 0x00200000, 0x34214682, 0x3ed40684,
+0xb0408184, 0x40800003, 0x24214682, 0x21a00083,
+0x40800082, 0x21a00b02, 0x4020007f, 0x1000251e,
+0x40a80002, 0x32800008, 0x4205c00c, 0x00200000,
+0x40a0000b, 0x3f82070f, 0x4080020a, 0x40800709,
+0x3fe3078f, 0x3fbf0783, 0x3f200183, 0x3fbe0183,
+0x3fe30187, 0x18008387, 0x4205c002, 0x3ac30404,
+0x1cffc489, 0x00200000, 0x18008403, 0x38830402,
+0x4cffc486, 0x3ac28185, 0xb0408584, 0x28830402,
+0x1c020408, 0x38828182, 0xb0408385, 0x1802c387,
+0x28828182, 0x217ff886, 0x04000582, 0x32800007,
+0x21a00802, 0x3fbf0705, 0x3f200285, 0x3fbe0285,
+0x3fe30285, 0x21a00885, 0x04000603, 0x21a00903,
+0x40803c02, 0x21a00982, 0x04000386, 0x21a00a06,
+0x40801202, 0x21a00a82, 0x73000003, 0x24200683,
+0x01a00404, 0x00200000, 0x34204682, 0x3ec40683,
+0xb0408203, 0x24204682, 0x01a00783, 0x00200000,
+0x3421c682, 0x3edc0684, 0xb0408184, 0x2421c682,
+0x21a00806, 0x21a00885, 0x3fbf0784, 0x3f200204,
+0x3fbe0204, 0x3fe30204, 0x21a00904, 0x40804002,
+0x21a00982, 0x21a00a06, 0x40805a02, 0x21a00a82,
+0x04000683, 0x21a00803, 0x21a00885, 0x21a00904,
+0x40848002, 0x21a00982, 0x21a00a06, 0x40801002,
+0x21a00a82, 0x21a00a06, 0x40806602, 0x00200000,
+0x35800009, 0x21a00a82, 0x40800083, 0x21a00b83,
+0x01a00c02, 0x01a00d83, 0x00003ffb, 0x40800003,
+0x4020007f, 0x35000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/spu_utils.h b/arch/powerpc/platforms/cell/spufs/spu_utils.h
new file mode 100644 (file)
index 0000000..58359fe
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * utils.h: Utilities for SPU-side of the context switch operation.
+ *
+ * (C) Copyright IBM 2005
+ *
+ * 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.
+ */
+
+#ifndef _SPU_CONTEXT_UTILS_H_
+#define _SPU_CONTEXT_UTILS_H_
+
+/*
+ * 64-bit safe EA.
+ */
+typedef union {
+       unsigned long long ull;
+       unsigned int ui[2];
+} addr64;
+
+/*
+ * 128-bit register template.
+ */
+typedef union {
+       unsigned int slot[4];
+       vector unsigned int v;
+} spu_reg128v;
+
+/*
+ * DMA list structure.
+ */
+struct dma_list_elem {
+       unsigned int size;
+       unsigned int ea_low;
+};
+
+/*
+ * Declare storage for 8-byte aligned DMA list.
+ */
+struct dma_list_elem dma_list[15] __attribute__ ((aligned(8)));
+
+/*
+ * External definition for storage
+ * declared in crt0.
+ */
+extern spu_reg128v regs_spill[NR_SPU_SPILL_REGS];
+
+/*
+ * Compute LSCSA byte offset for a given field.
+ */
+static struct spu_lscsa *dummy = (struct spu_lscsa *)0;
+#define LSCSA_BYTE_OFFSET(_field)  \
+       ((char *)(&(dummy->_field)) - (char *)(&(dummy->gprs[0].slot[0])))
+#define LSCSA_QW_OFFSET(_field)  (LSCSA_BYTE_OFFSET(_field) >> 4)
+
+static inline void set_event_mask(void)
+{
+       unsigned int event_mask = 0;
+
+       /* Save, Step 4:
+        * Restore, Step 1:
+        *    Set the SPU_RdEventMsk channel to zero to mask
+        *    all events.
+        */
+       spu_writech(SPU_WrEventMask, event_mask);
+}
+
+static inline void set_tag_mask(void)
+{
+       unsigned int tag_mask = 1;
+
+       /* Save, Step 5:
+        * Restore, Step 2:
+        *    Set the SPU_WrTagMsk channel to '01' to unmask
+        *    only tag group 0.
+        */
+       spu_writech(MFC_WrTagMask, tag_mask);
+}
+
+static inline void build_dma_list(addr64 lscsa_ea)
+{
+       unsigned int ea_low;
+       int i;
+
+       /* Save, Step 6:
+        * Restore, Step 3:
+        *    Update the effective address for the CSA in the
+        *    pre-canned DMA-list in local storage.
+        */
+       ea_low = lscsa_ea.ui[1];
+       ea_low += LSCSA_BYTE_OFFSET(ls[16384]);
+
+       for (i = 0; i < 15; i++, ea_low += 16384) {
+               dma_list[i].size = 16384;
+               dma_list[i].ea_low = ea_low;
+       }
+}
+
+static inline void enqueue_putllc(addr64 lscsa_ea)
+{
+       unsigned int ls = 0;
+       unsigned int size = 128;
+       unsigned int tag_id = 0;
+       unsigned int cmd = 0xB4;        /* PUTLLC */
+
+       /* Save, Step 12:
+        * Restore, Step 7:
+        *    Send a PUTLLC (tag 0) command to the MFC using
+        *    an effective address in the CSA in order to
+        *    remove any possible lock-line reservation.
+        */
+       spu_writech(MFC_LSA, ls);
+       spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+       spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+       spu_writech(MFC_Size, size);
+       spu_writech(MFC_TagID, tag_id);
+       spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void set_tag_update(void)
+{
+       unsigned int update_any = 1;
+
+       /* Save, Step 15:
+        * Restore, Step 8:
+        *    Write the MFC_TagUpdate channel with '01'.
+        */
+       spu_writech(MFC_WrTagUpdate, update_any);
+}
+
+static inline void read_tag_status(void)
+{
+       /* Save, Step 16:
+        * Restore, Step 9:
+        *    Read the MFC_TagStat channel data.
+        */
+       spu_readch(MFC_RdTagStat);
+}
+
+static inline void read_llar_status(void)
+{
+       /* Save, Step 17:
+        * Restore, Step 10:
+        *    Read the MFC_AtomicStat channel data.
+        */
+       spu_readch(MFC_RdAtomicStat);
+}
+
+#endif                         /* _SPU_CONTEXT_UTILS_H_ */
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
new file mode 100644 (file)
index 0000000..db2601f
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * SPU file system
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@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.
+ */
+#ifndef SPUFS_H
+#define SPUFS_H
+
+#include <linux/kref.h>
+#include <linux/rwsem.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+
+/* The magic number for our file system */
+enum {
+       SPUFS_MAGIC = 0x23c9b64e,
+};
+
+struct spu_context_ops;
+
+#define SPU_CONTEXT_PREEMPT          0UL
+
+struct spu_context {
+       struct spu *spu;                  /* pointer to a physical SPU */
+       struct spu_state csa;             /* SPU context save area. */
+       spinlock_t mmio_lock;             /* protects mmio access */
+       struct address_space *local_store;/* local store backing store */
+
+       enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
+       struct rw_semaphore state_sema;
+       struct semaphore run_sema;
+
+       struct mm_struct *owner;
+
+       struct kref kref;
+       wait_queue_head_t ibox_wq;
+       wait_queue_head_t wbox_wq;
+       wait_queue_head_t stop_wq;
+       struct fasync_struct *ibox_fasync;
+       struct fasync_struct *wbox_fasync;
+       struct spu_context_ops *ops;
+       struct work_struct reap_work;
+       u64 flags;
+};
+
+/* SPU context query/set operations. */
+struct spu_context_ops {
+       int (*mbox_read) (struct spu_context * ctx, u32 * data);
+        u32(*mbox_stat_read) (struct spu_context * ctx);
+       unsigned int (*mbox_stat_poll)(struct spu_context *ctx,
+                                       unsigned int events);
+       int (*ibox_read) (struct spu_context * ctx, u32 * data);
+       int (*wbox_write) (struct spu_context * ctx, u32 data);
+        u32(*signal1_read) (struct spu_context * ctx);
+       void (*signal1_write) (struct spu_context * ctx, u32 data);
+        u32(*signal2_read) (struct spu_context * ctx);
+       void (*signal2_write) (struct spu_context * ctx, u32 data);
+       void (*signal1_type_set) (struct spu_context * ctx, u64 val);
+        u64(*signal1_type_get) (struct spu_context * ctx);
+       void (*signal2_type_set) (struct spu_context * ctx, u64 val);
+        u64(*signal2_type_get) (struct spu_context * ctx);
+        u32(*npc_read) (struct spu_context * ctx);
+       void (*npc_write) (struct spu_context * ctx, u32 data);
+        u32(*status_read) (struct spu_context * ctx);
+       char*(*get_ls) (struct spu_context * ctx);
+       void (*runcntl_write) (struct spu_context * ctx, u32 data);
+       void (*runcntl_stop) (struct spu_context * ctx);
+};
+
+extern struct spu_context_ops spu_hw_ops;
+extern struct spu_context_ops spu_backing_ops;
+
+struct spufs_inode_info {
+       struct spu_context *i_ctx;
+       struct inode vfs_inode;
+};
+#define SPUFS_I(inode) \
+       container_of(inode, struct spufs_inode_info, vfs_inode)
+
+extern struct tree_descr spufs_dir_contents[];
+
+/* system call implementation */
+long spufs_run_spu(struct file *file,
+                  struct spu_context *ctx, u32 *npc, u32 *status);
+long spufs_create_thread(struct nameidata *nd,
+                        unsigned int flags, mode_t mode);
+extern struct file_operations spufs_context_fops;
+
+/* context management */
+struct spu_context * alloc_spu_context(struct address_space *local_store);
+void destroy_spu_context(struct kref *kref);
+struct spu_context * get_spu_context(struct spu_context *ctx);
+int put_spu_context(struct spu_context *ctx);
+void spu_unmap_mappings(struct spu_context *ctx);
+
+void spu_forget(struct spu_context *ctx);
+void spu_acquire(struct spu_context *ctx);
+void spu_release(struct spu_context *ctx);
+int spu_acquire_runnable(struct spu_context *ctx);
+void spu_acquire_saved(struct spu_context *ctx);
+
+int spu_activate(struct spu_context *ctx, u64 flags);
+void spu_deactivate(struct spu_context *ctx);
+void spu_yield(struct spu_context *ctx);
+int __init spu_sched_init(void);
+void __exit spu_sched_exit(void);
+
+/*
+ * spufs_wait
+ *     Same as wait_event_interruptible(), except that here
+ *     we need to call spu_release(ctx) before sleeping, and
+ *     then spu_acquire(ctx) when awoken.
+ */
+
+#define spufs_wait(wq, condition)                                      \
+({                                                                     \
+       int __ret = 0;                                                  \
+       DEFINE_WAIT(__wait);                                            \
+       for (;;) {                                                      \
+               prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);    \
+               if (condition)                                          \
+                       break;                                          \
+               if (!signal_pending(current)) {                         \
+                       spu_release(ctx);                               \
+                       schedule();                                     \
+                       spu_acquire(ctx);                               \
+                       continue;                                       \
+               }                                                       \
+               __ret = -ERESTARTSYS;                                   \
+               break;                                                  \
+       }                                                               \
+       finish_wait(&(wq), &__wait);                                    \
+       __ret;                                                          \
+})
+
+size_t spu_wbox_write(struct spu_context *ctx, u32 data);
+size_t spu_ibox_read(struct spu_context *ctx, u32 *data);
+
+/* irq callback funcs. */
+void spufs_ibox_callback(struct spu *spu);
+void spufs_wbox_callback(struct spu *spu);
+void spufs_stop_callback(struct spu *spu);
+
+#endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
new file mode 100644 (file)
index 0000000..1061c12
--- /dev/null
@@ -0,0 +1,2180 @@
+/*
+ * spu_switch.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * Host-side part of SPU context switch sequence outlined in
+ * Synergistic Processor Element, Book IV.
+ *
+ * A fully premptive switch of an SPE is very expensive in terms
+ * of time and system resources.  SPE Book IV indicates that SPE
+ * allocation should follow a "serially reusable device" model,
+ * in which the SPE is assigned a task until it completes.  When
+ * this is not possible, this sequence may be used to premptively
+ * save, and then later (optionally) restore the context of a
+ * program executing on an SPE.
+ *
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+
+#include "spu_save_dump.h"
+#include "spu_restore_dump.h"
+
+#if 0
+#define POLL_WHILE_TRUE(_c) {                          \
+    do {                                               \
+    } while (_c);                                      \
+  }
+#else
+#define RELAX_SPIN_COUNT                               1000
+#define POLL_WHILE_TRUE(_c) {                          \
+    do {                                               \
+       int _i;                                         \
+       for (_i=0; _i<RELAX_SPIN_COUNT && (_c); _i++) { \
+           cpu_relax();                                \
+       }                                               \
+       if (unlikely(_c)) yield();                      \
+       else break;                                     \
+    } while (_c);                                      \
+  }
+#endif                         /* debug */
+
+#define POLL_WHILE_FALSE(_c)   POLL_WHILE_TRUE(!(_c))
+
+static inline void acquire_spu_lock(struct spu *spu)
+{
+       /* Save, Step 1:
+        * Restore, Step 1:
+        *    Acquire SPU-specific mutual exclusion lock.
+        *    TBD.
+        */
+}
+
+static inline void release_spu_lock(struct spu *spu)
+{
+       /* Restore, Step 76:
+        *    Release SPU-specific mutual exclusion lock.
+        *    TBD.
+        */
+}
+
+static inline int check_spu_isolate(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       u32 isolate_state;
+
+       /* Save, Step 2:
+        * Save, Step 6:
+        *     If SPU_Status[E,L,IS] any field is '1', this
+        *     SPU is in isolate state and cannot be context
+        *     saved at this time.
+        */
+       isolate_state = SPU_STATUS_ISOLATED_STATE |
+           SPU_STATUS_ISOLATED_LOAD_STAUTUS | SPU_STATUS_ISOLATED_EXIT_STAUTUS;
+       return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0;
+}
+
+static inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 3:
+        * Restore, Step 2:
+        *     Save INT_Mask_class0 in CSA.
+        *     Write INT_MASK_class0 with value of 0.
+        *     Save INT_Mask_class1 in CSA.
+        *     Write INT_MASK_class1 with value of 0.
+        *     Save INT_Mask_class2 in CSA.
+        *     Write INT_MASK_class2 with value of 0.
+        */
+       spin_lock_irq(&spu->register_lock);
+       if (csa) {
+               csa->priv1.int_mask_class0_RW = spu_int_mask_get(spu, 0);
+               csa->priv1.int_mask_class1_RW = spu_int_mask_get(spu, 1);
+               csa->priv1.int_mask_class2_RW = spu_int_mask_get(spu, 2);
+       }
+       spu_int_mask_set(spu, 0, 0ul);
+       spu_int_mask_set(spu, 1, 0ul);
+       spu_int_mask_set(spu, 2, 0ul);
+       eieio();
+       spin_unlock_irq(&spu->register_lock);
+}
+
+static inline void set_watchdog_timer(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 4:
+        * Restore, Step 25.
+        *    Set a software watchdog timer, which specifies the
+        *    maximum allowable time for a context save sequence.
+        *
+        *    For present, this implementation will not set a global
+        *    watchdog timer, as virtualization & variable system load
+        *    may cause unpredictable execution times.
+        */
+}
+
+static inline void inhibit_user_access(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 5:
+        * Restore, Step 3:
+        *     Inhibit user-space access (if provided) to this
+        *     SPU by unmapping the virtual pages assigned to
+        *     the SPU memory-mapped I/O (MMIO) for problem
+        *     state. TBD.
+        */
+}
+
+static inline void set_switch_pending(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 7:
+        * Restore, Step 5:
+        *     Set a software context switch pending flag.
+        */
+       set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
+       mb();
+}
+
+static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 8:
+        *     Read and save MFC_CNTL[Ss].
+        */
+       if (csa) {
+               csa->priv2.mfc_control_RW = in_be64(&priv2->mfc_control_RW) &
+                   MFC_CNTL_SUSPEND_DMA_STATUS_MASK;
+       }
+}
+
+static inline void save_spu_runcntl(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 9:
+        *     Save SPU_Runcntl in the CSA.  This value contains
+        *     the "Application Desired State".
+        */
+       csa->prob.spu_runcntl_RW = in_be32(&prob->spu_runcntl_RW);
+}
+
+static inline void save_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 10:
+        *     Save MFC_SR1 in the CSA.
+        */
+       csa->priv1.mfc_sr1_RW = spu_mfc_sr1_get(spu);
+}
+
+static inline void save_spu_status(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 11:
+        *     Read SPU_Status[R], and save to CSA.
+        */
+       if ((in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) == 0) {
+               csa->prob.spu_status_R = in_be32(&prob->spu_status_R);
+       } else {
+               u32 stopped;
+
+               out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+               eieio();
+               POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                               SPU_STATUS_RUNNING);
+               stopped =
+                   SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP |
+                   SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
+               if ((in_be32(&prob->spu_status_R) & stopped) == 0)
+                       csa->prob.spu_status_R = SPU_STATUS_RUNNING;
+               else
+                       csa->prob.spu_status_R = in_be32(&prob->spu_status_R);
+       }
+}
+
+static inline void save_mfc_decr(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 12:
+        *     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();
+       }
+}
+
+static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 13:
+        *     Write MFC_CNTL[Dh] set to a '1' to halt
+        *     the decrementer.
+        */
+       out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED);
+       eieio();
+}
+
+static inline void save_timebase(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 14:
+        *    Read PPE Timebase High and Timebase low registers
+        *    and save in CSA.  TBD.
+        */
+       csa->suspend_time = get_cycles();
+}
+
+static inline void remove_other_spu_access(struct spu_state *csa,
+                                          struct spu *spu)
+{
+       /* Save, Step 15:
+        *     Remove other SPU access to this SPU by unmapping
+        *     this SPU's pages from their address space.  TBD.
+        */
+}
+
+static inline void do_mfc_mssync(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 16:
+        * Restore, Step 11.
+        *     Write SPU_MSSync register. Poll SPU_MSSync[P]
+        *     for a value of 0.
+        */
+       out_be64(&prob->spc_mssync_RW, 1UL);
+       POLL_WHILE_TRUE(in_be64(&prob->spc_mssync_RW) & MS_SYNC_PENDING);
+}
+
+static inline void issue_mfc_tlbie(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 17:
+        * Restore, Step 12.
+        * Restore, Step 48.
+        *     Write TLB_Invalidate_Entry[IS,VPN,L,Lp]=0 register.
+        *     Then issue a PPE sync instruction.
+        */
+       spu_tlb_invalidate(spu);
+       mb();
+}
+
+static inline void handle_pending_interrupts(struct spu_state *csa,
+                                            struct spu *spu)
+{
+       /* Save, Step 18:
+        *     Handle any pending interrupts from this SPU
+        *     here.  This is OS or hypervisor specific.  One
+        *     option is to re-enable interrupts to handle any
+        *     pending interrupts, with the interrupt handlers
+        *     recognizing the software Context Switch Pending
+        *     flag, to ensure the SPU execution or MFC command
+        *     queue is not restarted.  TBD.
+        */
+}
+
+static inline void save_mfc_queues(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       int i;
+
+       /* Save, Step 19:
+        *     If MFC_Cntl[Se]=0 then save
+        *     MFC command queues.
+        */
+       if ((in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DMA_QUEUES_EMPTY) == 0) {
+               for (i = 0; i < 8; i++) {
+                       csa->priv2.puq[i].mfc_cq_data0_RW =
+                           in_be64(&priv2->puq[i].mfc_cq_data0_RW);
+                       csa->priv2.puq[i].mfc_cq_data1_RW =
+                           in_be64(&priv2->puq[i].mfc_cq_data1_RW);
+                       csa->priv2.puq[i].mfc_cq_data2_RW =
+                           in_be64(&priv2->puq[i].mfc_cq_data2_RW);
+                       csa->priv2.puq[i].mfc_cq_data3_RW =
+                           in_be64(&priv2->puq[i].mfc_cq_data3_RW);
+               }
+               for (i = 0; i < 16; i++) {
+                       csa->priv2.spuq[i].mfc_cq_data0_RW =
+                           in_be64(&priv2->spuq[i].mfc_cq_data0_RW);
+                       csa->priv2.spuq[i].mfc_cq_data1_RW =
+                           in_be64(&priv2->spuq[i].mfc_cq_data1_RW);
+                       csa->priv2.spuq[i].mfc_cq_data2_RW =
+                           in_be64(&priv2->spuq[i].mfc_cq_data2_RW);
+                       csa->priv2.spuq[i].mfc_cq_data3_RW =
+                           in_be64(&priv2->spuq[i].mfc_cq_data3_RW);
+               }
+       }
+}
+
+static inline void save_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 20:
+        *     Save the PPU_QueryMask register
+        *     in the CSA.
+        */
+       csa->prob.dma_querymask_RW = in_be32(&prob->dma_querymask_RW);
+}
+
+static inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 21:
+        *     Save the PPU_QueryType register
+        *     in the CSA.
+        */
+       csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW);
+}
+
+static inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 22:
+        *     Save the MFC_CSR_TSQ register
+        *     in the LSCSA.
+        */
+       csa->priv2.spu_tag_status_query_RW =
+           in_be64(&priv2->spu_tag_status_query_RW);
+}
+
+static inline void save_mfc_csr_cmd(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 23:
+        *     Save the MFC_CSR_CMD1 and MFC_CSR_CMD2
+        *     registers in the CSA.
+        */
+       csa->priv2.spu_cmd_buf1_RW = in_be64(&priv2->spu_cmd_buf1_RW);
+       csa->priv2.spu_cmd_buf2_RW = in_be64(&priv2->spu_cmd_buf2_RW);
+}
+
+static inline void save_mfc_csr_ato(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 24:
+        *     Save the MFC_CSR_ATO register in
+        *     the CSA.
+        */
+       csa->priv2.spu_atomic_status_RW = in_be64(&priv2->spu_atomic_status_RW);
+}
+
+static inline void save_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 25:
+        *     Save the MFC_TCLASS_ID register in
+        *     the CSA.
+        */
+       csa->priv1.mfc_tclass_id_RW = spu_mfc_tclass_id_get(spu);
+}
+
+static inline void set_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 26:
+        * Restore, Step 23.
+        *     Write the MFC_TCLASS_ID register with
+        *     the value 0x10000000.
+        */
+       spu_mfc_tclass_id_set(spu, 0x10000000);
+       eieio();
+}
+
+static inline void purge_mfc_queue(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 27:
+        * Restore, Step 14.
+        *     Write MFC_CNTL[Pc]=1 (purge queue).
+        */
+       out_be64(&priv2->mfc_control_RW, MFC_CNTL_PURGE_DMA_REQUEST);
+       eieio();
+}
+
+static inline void wait_purge_complete(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 28:
+        *     Poll MFC_CNTL[Ps] until value '11' is read
+        *     (purge complete).
+        */
+       POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) &
+                        MFC_CNTL_PURGE_DMA_COMPLETE);
+}
+
+static inline void save_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       int i;
+
+       /* Save, Step 29:
+        *     If MFC_SR1[R]='1', save SLBs in CSA.
+        */
+       if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) {
+               csa->priv2.slb_index_W = in_be64(&priv2->slb_index_W);
+               for (i = 0; i < 8; i++) {
+                       out_be64(&priv2->slb_index_W, i);
+                       eieio();
+                       csa->slb_esid_RW[i] = in_be64(&priv2->slb_esid_RW);
+                       csa->slb_vsid_RW[i] = in_be64(&priv2->slb_vsid_RW);
+                       eieio();
+               }
+       }
+}
+
+static inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 30:
+        * Restore, Step 18:
+        *     Write MFC_SR1 with MFC_SR1[D=0,S=1] and
+        *     MFC_SR1[TL,R,Pr,T] set correctly for the
+        *     OS specific environment.
+        *
+        *     Implementation note: The SPU-side code
+        *     for save/restore is privileged, so the
+        *     MFC_SR1[Pr] bit is not set.
+        *
+        */
+       spu_mfc_sr1_set(spu, (MFC_STATE1_MASTER_RUN_CONTROL_MASK |
+                             MFC_STATE1_RELOCATE_MASK |
+                             MFC_STATE1_BUS_TLBIE_MASK));
+}
+
+static inline void save_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 31:
+        *     Save SPU_NPC in the CSA.
+        */
+       csa->prob.spu_npc_RW = in_be32(&prob->spu_npc_RW);
+}
+
+static inline void save_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 32:
+        *     Save SPU_PrivCntl in the CSA.
+        */
+       csa->priv2.spu_privcntl_RW = in_be64(&priv2->spu_privcntl_RW);
+}
+
+static inline void reset_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 33:
+        * Restore, Step 16:
+        *     Write SPU_PrivCntl[S,Le,A] fields reset to 0.
+        */
+       out_be64(&priv2->spu_privcntl_RW, 0UL);
+       eieio();
+}
+
+static inline void save_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 34:
+        *     Save SPU_LSLR in the CSA.
+        */
+       csa->priv2.spu_lslr_RW = in_be64(&priv2->spu_lslr_RW);
+}
+
+static inline void reset_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 35:
+        * Restore, Step 17.
+        *     Reset SPU_LSLR.
+        */
+       out_be64(&priv2->spu_lslr_RW, LS_ADDR_MASK);
+       eieio();
+}
+
+static inline void save_spu_cfg(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 36:
+        *     Save SPU_Cfg in the CSA.
+        */
+       csa->priv2.spu_cfg_RW = in_be64(&priv2->spu_cfg_RW);
+}
+
+static inline void save_pm_trace(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 37:
+        *     Save PM_Trace_Tag_Wait_Mask in the CSA.
+        *     Not performed by this implementation.
+        */
+}
+
+static inline void save_mfc_rag(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 38:
+        *     Save RA_GROUP_ID register and the
+        *     RA_ENABLE reigster in the CSA.
+        */
+       csa->priv1.resource_allocation_groupID_RW =
+               spu_resource_allocation_groupID_get(spu);
+       csa->priv1.resource_allocation_enable_RW =
+               spu_resource_allocation_enable_get(spu);
+}
+
+static inline void save_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 39:
+        *     Save MB_Stat register in the CSA.
+        */
+       csa->prob.mb_stat_R = in_be32(&prob->mb_stat_R);
+}
+
+static inline void save_ppu_mb(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 40:
+        *     Save the PPU_MB register in the CSA.
+        */
+       csa->prob.pu_mb_R = in_be32(&prob->pu_mb_R);
+}
+
+static inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 41:
+        *     Save the PPUINT_MB register in the CSA.
+        */
+       csa->priv2.puint_mb_R = in_be64(&priv2->puint_mb_R);
+}
+
+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, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       int i;
+
+       /* Save, Step 42:
+        *     Save the following CH: [0,1,3,4,24,25,27]
+        */
+       for (i = 0; i < 7; i++) {
+               idx = ch_indices[i];
+               out_be64(&priv2->spu_chnlcntptr_RW, idx);
+               eieio();
+               csa->spu_chnldata_RW[idx] = in_be64(&priv2->spu_chnldata_RW);
+               csa->spu_chnlcnt_RW[idx] = in_be64(&priv2->spu_chnlcnt_RW);
+               out_be64(&priv2->spu_chnldata_RW, 0UL);
+               out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+               eieio();
+       }
+}
+
+static inline void save_spu_mb(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       int i;
+
+       /* Save, Step 43:
+        *     Save SPU Read Mailbox Channel.
+        */
+       out_be64(&priv2->spu_chnlcntptr_RW, 29UL);
+       eieio();
+       csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW);
+       for (i = 0; i < 4; i++) {
+               csa->spu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW);
+       }
+       out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+       eieio();
+}
+
+static inline void save_mfc_cmd(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 44:
+        *     Save MFC_CMD Channel.
+        */
+       out_be64(&priv2->spu_chnlcntptr_RW, 21UL);
+       eieio();
+       csa->spu_chnlcnt_RW[21] = in_be64(&priv2->spu_chnlcnt_RW);
+       eieio();
+}
+
+static inline void reset_ch(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       u64 ch_indices[4] = { 21UL, 23UL, 28UL, 30UL };
+       u64 ch_counts[4] = { 16UL, 1UL, 1UL, 1UL };
+       u64 idx;
+       int i;
+
+       /* Save, Step 45:
+        *     Reset the following CH: [21, 23, 28, 30]
+        */
+       for (i = 0; i < 4; i++) {
+               idx = ch_indices[i];
+               out_be64(&priv2->spu_chnlcntptr_RW, idx);
+               eieio();
+               out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+               eieio();
+       }
+}
+
+static inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 46:
+        * Restore, Step 25.
+        *     Write MFC_CNTL[Sc]=0 (resume queue processing).
+        */
+       out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE);
+}
+
+static inline void invalidate_slbs(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Save, Step 45:
+        * Restore, Step 19:
+        *     If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All.
+        */
+       if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) {
+               out_be64(&priv2->slb_invalidate_all_W, 0UL);
+               eieio();
+       }
+}
+
+static inline void get_kernel_slb(u64 ea, u64 slb[2])
+{
+       slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
+       slb[1] = (ea & ESID_MASK) | SLB_ESID_V;
+
+       /* Large pages are used for kernel text/data, but not vmalloc.  */
+       if (cpu_has_feature(CPU_FTR_16M_PAGE)
+           && REGION_ID(ea) == KERNEL_REGION_ID)
+               slb[0] |= SLB_VSID_L;
+}
+
+static inline void load_mfc_slb(struct spu *spu, u64 slb[2], int slbe)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       out_be64(&priv2->slb_index_W, slbe);
+       eieio();
+       out_be64(&priv2->slb_vsid_RW, slb[0]);
+       out_be64(&priv2->slb_esid_RW, slb[1]);
+       eieio();
+}
+
+static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+       u64 code_slb[2];
+       u64 lscsa_slb[2];
+
+       /* Save, Step 47:
+        * Restore, Step 30.
+        *     If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All
+        *     register, then initialize SLB_VSID and SLB_ESID
+        *     to provide access to SPU context save code and
+        *     LSCSA.
+        *
+        *     This implementation places both the context
+        *     switch code and LSCSA in kernel address space.
+        *
+        *     Further this implementation assumes that the
+        *     MFC_SR1[R]=1 (in other words, assume that
+        *     translation is desired by OS environment).
+        */
+       invalidate_slbs(csa, spu);
+       get_kernel_slb((unsigned long)&spu_save_code[0], code_slb);
+       get_kernel_slb((unsigned long)csa->lscsa, lscsa_slb);
+       load_mfc_slb(spu, code_slb, 0);
+       if ((lscsa_slb[0] != code_slb[0]) || (lscsa_slb[1] != code_slb[1]))
+               load_mfc_slb(spu, lscsa_slb, 1);
+}
+
+static inline void set_switch_active(struct spu_state *csa, struct spu *spu)
+{
+       /* Save, Step 48:
+        * Restore, Step 23.
+        *     Change the software context switch pending flag
+        *     to context switch active.
+        */
+       set_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
+       clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
+       mb();
+}
+
+static inline void enable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+       unsigned long class1_mask = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
+           CLASS1_ENABLE_STORAGE_FAULT_INTR;
+
+       /* Save, Step 49:
+        * Restore, Step 22:
+        *     Reset and then enable interrupts, as
+        *     needed by OS.
+        *
+        *     This implementation enables only class1
+        *     (translation) interrupts.
+        */
+       spin_lock_irq(&spu->register_lock);
+       spu_int_stat_clear(spu, 0, ~0ul);
+       spu_int_stat_clear(spu, 1, ~0ul);
+       spu_int_stat_clear(spu, 2, ~0ul);
+       spu_int_mask_set(spu, 0, 0ul);
+       spu_int_mask_set(spu, 1, class1_mask);
+       spu_int_mask_set(spu, 2, 0ul);
+       spin_unlock_irq(&spu->register_lock);
+}
+
+static inline int send_mfc_dma(struct spu *spu, unsigned long ea,
+                              unsigned int ls_offset, unsigned int size,
+                              unsigned int tag, unsigned int rclass,
+                              unsigned int cmd)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       union mfc_tag_size_class_cmd command;
+       unsigned int transfer_size;
+       volatile unsigned int status = 0x0;
+
+       while (size > 0) {
+               transfer_size =
+                   (size > MFC_MAX_DMA_SIZE) ? MFC_MAX_DMA_SIZE : size;
+               command.u.mfc_size = transfer_size;
+               command.u.mfc_tag = tag;
+               command.u.mfc_rclassid = rclass;
+               command.u.mfc_cmd = cmd;
+               do {
+                       out_be32(&prob->mfc_lsa_W, ls_offset);
+                       out_be64(&prob->mfc_ea_W, ea);
+                       out_be64(&prob->mfc_union_W.all64, command.all64);
+                       status =
+                           in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
+                       if (unlikely(status & 0x2)) {
+                               cpu_relax();
+                       }
+               } while (status & 0x3);
+               size -= transfer_size;
+               ea += transfer_size;
+               ls_offset += transfer_size;
+       }
+       return 0;
+}
+
+static inline void save_ls_16kb(struct spu_state *csa, struct spu *spu)
+{
+       unsigned long addr = (unsigned long)&csa->lscsa->ls[0];
+       unsigned int ls_offset = 0x0;
+       unsigned int size = 16384;
+       unsigned int tag = 0;
+       unsigned int rclass = 0;
+       unsigned int cmd = MFC_PUT_CMD;
+
+       /* Save, Step 50:
+        *     Issue a DMA command to copy the first 16K bytes
+        *     of local storage to the CSA.
+        */
+       send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void set_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 51:
+        * Restore, Step 31.
+        *     Write SPU_NPC[IE]=0 and SPU_NPC[LSA] to entry
+        *     point address of context save code in local
+        *     storage.
+        *
+        *     This implementation uses SPU-side save/restore
+        *     programs with entry points at LSA of 0.
+        */
+       out_be32(&prob->spu_npc_RW, 0);
+       eieio();
+}
+
+static inline void set_signot1(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       union {
+               u64 ull;
+               u32 ui[2];
+       } addr64;
+
+       /* Save, Step 52:
+        * Restore, Step 32:
+        *    Write SPU_Sig_Notify_1 register with upper 32-bits
+        *    of the CSA.LSCSA effective address.
+        */
+       addr64.ull = (u64) csa->lscsa;
+       out_be32(&prob->signal_notify1, addr64.ui[0]);
+       eieio();
+}
+
+static inline void set_signot2(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       union {
+               u64 ull;
+               u32 ui[2];
+       } addr64;
+
+       /* Save, Step 53:
+        * Restore, Step 33:
+        *    Write SPU_Sig_Notify_2 register with lower 32-bits
+        *    of the CSA.LSCSA effective address.
+        */
+       addr64.ull = (u64) csa->lscsa;
+       out_be32(&prob->signal_notify2, addr64.ui[1]);
+       eieio();
+}
+
+static inline void send_save_code(struct spu_state *csa, struct spu *spu)
+{
+       unsigned long addr = (unsigned long)&spu_save_code[0];
+       unsigned int ls_offset = 0x0;
+       unsigned int size = sizeof(spu_save_code);
+       unsigned int tag = 0;
+       unsigned int rclass = 0;
+       unsigned int cmd = MFC_GETFS_CMD;
+
+       /* Save, Step 54:
+        *     Issue a DMA command to copy context save code
+        *     to local storage and start SPU.
+        */
+       send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void set_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Save, Step 55:
+        * Restore, Step 38.
+        *     Write PPU_QueryMask=1 (enable Tag Group 0)
+        *     and issue eieio instruction.
+        */
+       out_be32(&prob->dma_querymask_RW, MFC_TAGID_TO_TAGMASK(0));
+       eieio();
+}
+
+static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       u32 mask = MFC_TAGID_TO_TAGMASK(0);
+       unsigned long flags;
+
+       /* Save, Step 56:
+        * Restore, Step 39.
+        * Restore, Step 39.
+        * Restore, Step 46.
+        *     Poll PPU_TagStatus[gn] until 01 (Tag group 0 complete)
+        *     or write PPU_QueryType[TS]=01 and wait for Tag Group
+        *     Complete Interrupt.  Write INT_Stat_Class0 or
+        *     INT_Stat_Class2 with value of 'handled'.
+        */
+       POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask);
+
+       local_irq_save(flags);
+       spu_int_stat_clear(spu, 0, ~(0ul));
+       spu_int_stat_clear(spu, 2, ~(0ul));
+       local_irq_restore(flags);
+}
+
+static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       unsigned long flags;
+
+       /* Save, Step 57:
+        * Restore, Step 40.
+        *     Poll until SPU_Status[R]=0 or wait for SPU Class 0
+        *     or SPU Class 2 interrupt.  Write INT_Stat_class0
+        *     or INT_Stat_class2 with value of handled.
+        */
+       POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
+
+       local_irq_save(flags);
+       spu_int_stat_clear(spu, 0, ~(0ul));
+       spu_int_stat_clear(spu, 2, ~(0ul));
+       local_irq_restore(flags);
+}
+
+static inline int check_save_status(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       u32 complete;
+
+       /* Save, Step 54:
+        *     If SPU_Status[P]=1 and SPU_Status[SC] = "success",
+        *     context save succeeded, otherwise context save
+        *     failed.
+        */
+       complete = ((SPU_SAVE_COMPLETE << SPU_STOP_STATUS_SHIFT) |
+                   SPU_STATUS_STOPPED_BY_STOP);
+       return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;
+}
+
+static inline void terminate_spu_app(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 4:
+        *    If required, notify the "using application" that
+        *    the SPU task has been terminated.  TBD.
+        */
+}
+
+static inline void suspend_mfc(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
+        *     the queue and halt the decrementer.
+        */
+       out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE |
+                MFC_CNTL_DECREMENTER_HALTED);
+       eieio();
+}
+
+static inline void wait_suspend_mfc_complete(struct spu_state *csa,
+                                            struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 8:
+        * Restore, Step 47.
+        *     Poll MFC_CNTL[Ss] until 11 is returned.
+        */
+       POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) &
+                        MFC_CNTL_SUSPEND_COMPLETE);
+}
+
+static inline int suspend_spe(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Restore, Step 9:
+        *    If SPU_Status[R]=1, stop SPU execution
+        *    and wait for stop to complete.
+        *
+        *    Returns       1 if SPU_Status[R]=1 on entry.
+        *                  0 otherwise
+        */
+       if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) {
+               if (in_be32(&prob->spu_status_R) &
+                   SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+                       POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                                       SPU_STATUS_RUNNING);
+               }
+               if ((in_be32(&prob->spu_status_R) &
+                    SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+                   || (in_be32(&prob->spu_status_R) &
+                       SPU_STATUS_ISOLATED_STATE)) {
+                       out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+                       eieio();
+                       POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                                       SPU_STATUS_RUNNING);
+                       out_be32(&prob->spu_runcntl_RW, 0x2);
+                       eieio();
+                       POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                                       SPU_STATUS_RUNNING);
+               }
+               if (in_be32(&prob->spu_status_R) &
+                   SPU_STATUS_WAITING_FOR_CHANNEL) {
+                       out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+                       eieio();
+                       POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                                       SPU_STATUS_RUNNING);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Restore, Step 10:
+        *    If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1,
+        *    release SPU from isolate state.
+        */
+       if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) {
+               if (in_be32(&prob->spu_status_R) &
+                   SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+                       spu_mfc_sr1_set(spu,
+                                       MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+                       eieio();
+                       out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+                       eieio();
+                       POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                                       SPU_STATUS_RUNNING);
+               }
+               if ((in_be32(&prob->spu_status_R) &
+                    SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+                   || (in_be32(&prob->spu_status_R) &
+                       SPU_STATUS_ISOLATED_STATE)) {
+                       spu_mfc_sr1_set(spu,
+                                       MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+                       eieio();
+                       out_be32(&prob->spu_runcntl_RW, 0x2);
+                       eieio();
+                       POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                                       SPU_STATUS_RUNNING);
+               }
+       }
+}
+
+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, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       u64 idx;
+       int i;
+
+       /* Restore, Step 20:
+        *     Reset the following CH: [0,1,3,4,24,25,27]
+        */
+       for (i = 0; i < 7; i++) {
+               idx = ch_indices[i];
+               out_be64(&priv2->spu_chnlcntptr_RW, idx);
+               eieio();
+               out_be64(&priv2->spu_chnldata_RW, 0UL);
+               out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+               eieio();
+       }
+}
+
+static inline void reset_ch_part2(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       u64 ch_indices[5] = { 21UL, 23UL, 28UL, 29UL, 30UL };
+       u64 ch_counts[5] = { 16UL, 1UL, 1UL, 0UL, 1UL };
+       u64 idx;
+       int i;
+
+       /* Restore, Step 21:
+        *     Reset the following CH: [21, 23, 28, 29, 30]
+        */
+       for (i = 0; i < 5; i++) {
+               idx = ch_indices[i];
+               out_be64(&priv2->spu_chnlcntptr_RW, idx);
+               eieio();
+               out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+               eieio();
+       }
+}
+
+static inline void setup_spu_status_part1(struct spu_state *csa,
+                                         struct spu *spu)
+{
+       u32 status_P = SPU_STATUS_STOPPED_BY_STOP;
+       u32 status_I = SPU_STATUS_INVALID_INSTR;
+       u32 status_H = SPU_STATUS_STOPPED_BY_HALT;
+       u32 status_S = SPU_STATUS_SINGLE_STEP;
+       u32 status_S_I = SPU_STATUS_SINGLE_STEP | SPU_STATUS_INVALID_INSTR;
+       u32 status_S_P = SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_STOP;
+       u32 status_P_H = SPU_STATUS_STOPPED_BY_HALT |SPU_STATUS_STOPPED_BY_STOP;
+       u32 status_P_I = SPU_STATUS_STOPPED_BY_STOP |SPU_STATUS_INVALID_INSTR;
+       u32 status_code;
+
+       /* Restore, Step 27:
+        *     If the CSA.SPU_Status[I,S,H,P]=1 then add the correct
+        *     instruction sequence to the end of the SPU based restore
+        *     code (after the "context restored" stop and signal) to
+        *     restore the correct SPU status.
+        *
+        *     NOTE: Rather than modifying the SPU executable, we
+        *     instead add a new 'stopped_status' field to the
+        *     LSCSA.  The SPU-side restore reads this field and
+        *     takes the appropriate action when exiting.
+        */
+
+       status_code =
+           (csa->prob.spu_status_R >> SPU_STOP_STATUS_SHIFT) & 0xFFFF;
+       if ((csa->prob.spu_status_R & status_P_I) == status_P_I) {
+
+               /* SPU_Status[P,I]=1 - Illegal Instruction followed
+                * by Stop and Signal instruction, followed by 'br -4'.
+                *
+                */
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_I;
+               csa->lscsa->stopped_status.slot[1] = status_code;
+
+       } else if ((csa->prob.spu_status_R & status_P_H) == status_P_H) {
+
+               /* SPU_Status[P,H]=1 - Halt Conditional, followed
+                * by Stop and Signal instruction, followed by
+                * 'br -4'.
+                */
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_H;
+               csa->lscsa->stopped_status.slot[1] = status_code;
+
+       } else if ((csa->prob.spu_status_R & status_S_P) == status_S_P) {
+
+               /* SPU_Status[S,P]=1 - Stop and Signal instruction
+                * followed by 'br -4'.
+                */
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_P;
+               csa->lscsa->stopped_status.slot[1] = status_code;
+
+       } else if ((csa->prob.spu_status_R & status_S_I) == status_S_I) {
+
+               /* SPU_Status[S,I]=1 - Illegal instruction followed
+                * by 'br -4'.
+                */
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_I;
+               csa->lscsa->stopped_status.slot[1] = status_code;
+
+       } else if ((csa->prob.spu_status_R & status_P) == status_P) {
+
+               /* SPU_Status[P]=1 - Stop and Signal instruction
+                * followed by 'br -4'.
+                */
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P;
+               csa->lscsa->stopped_status.slot[1] = status_code;
+
+       } else if ((csa->prob.spu_status_R & status_H) == status_H) {
+
+               /* SPU_Status[H]=1 - Halt Conditional, followed
+                * by 'br -4'.
+                */
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_H;
+
+       } else if ((csa->prob.spu_status_R & status_S) == status_S) {
+
+               /* SPU_Status[S]=1 - Two nop instructions.
+                */
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S;
+
+       } else if ((csa->prob.spu_status_R & status_I) == status_I) {
+
+               /* SPU_Status[I]=1 - Illegal instruction followed
+                * by 'br -4'.
+                */
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_I;
+
+       }
+}
+
+static inline void setup_spu_status_part2(struct spu_state *csa,
+                                         struct spu *spu)
+{
+       u32 mask;
+
+       /* Restore, Step 28:
+        *     If the CSA.SPU_Status[I,S,H,P,R]=0 then
+        *     add a 'br *' instruction to the end of
+        *     the SPU based restore code.
+        *
+        *     NOTE: Rather than modifying the SPU executable, we
+        *     instead add a new 'stopped_status' field to the
+        *     LSCSA.  The SPU-side restore reads this field and
+        *     takes the appropriate action when exiting.
+        */
+       mask = SPU_STATUS_INVALID_INSTR |
+           SPU_STATUS_SINGLE_STEP |
+           SPU_STATUS_STOPPED_BY_HALT |
+           SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING;
+       if (!(csa->prob.spu_status_R & mask)) {
+               csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_R;
+       }
+}
+
+static inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 29:
+        *     Restore RA_GROUP_ID register and the
+        *     RA_ENABLE reigster from the CSA.
+        */
+       spu_resource_allocation_groupID_set(spu,
+                       csa->priv1.resource_allocation_groupID_RW);
+       spu_resource_allocation_enable_set(spu,
+                       csa->priv1.resource_allocation_enable_RW);
+}
+
+static inline void send_restore_code(struct spu_state *csa, struct spu *spu)
+{
+       unsigned long addr = (unsigned long)&spu_restore_code[0];
+       unsigned int ls_offset = 0x0;
+       unsigned int size = sizeof(spu_restore_code);
+       unsigned int tag = 0;
+       unsigned int rclass = 0;
+       unsigned int cmd = MFC_GETFS_CMD;
+
+       /* Restore, Step 37:
+        *     Issue MFC DMA command to copy context
+        *     restore code to local storage.
+        */
+       send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void setup_decr(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 34:
+        *     If CSA.MFC_CNTL[Ds]=1 (decrementer was
+        *     running) then adjust decrementer, set
+        *     decrementer running status in LSCSA,
+        *     and set decrementer "wrapped" status
+        *     in LSCSA.
+        */
+       if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) {
+               cycles_t resume_time = get_cycles();
+               cycles_t delta_time = resume_time - csa->suspend_time;
+
+               csa->lscsa->decr.slot[0] = delta_time;
+       }
+}
+
+static inline void setup_ppu_mb(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 35:
+        *     Copy the CSA.PU_MB data into the LSCSA.
+        */
+       csa->lscsa->ppu_mb.slot[0] = csa->prob.pu_mb_R;
+}
+
+static inline void setup_ppuint_mb(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 36:
+        *     Copy the CSA.PUINT_MB data into the LSCSA.
+        */
+       csa->lscsa->ppuint_mb.slot[0] = csa->priv2.puint_mb_R;
+}
+
+static inline int check_restore_status(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       u32 complete;
+
+       /* Restore, Step 40:
+        *     If SPU_Status[P]=1 and SPU_Status[SC] = "success",
+        *     context restore succeeded, otherwise context restore
+        *     failed.
+        */
+       complete = ((SPU_RESTORE_COMPLETE << SPU_STOP_STATUS_SHIFT) |
+                   SPU_STATUS_STOPPED_BY_STOP);
+       return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;
+}
+
+static inline void restore_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 41:
+        *     Restore SPU_PrivCntl from the CSA.
+        */
+       out_be64(&priv2->spu_privcntl_RW, csa->priv2.spu_privcntl_RW);
+       eieio();
+}
+
+static inline void restore_status_part1(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       u32 mask;
+
+       /* Restore, Step 42:
+        *     If any CSA.SPU_Status[I,S,H,P]=1, then
+        *     restore the error or single step state.
+        */
+       mask = SPU_STATUS_INVALID_INSTR |
+           SPU_STATUS_SINGLE_STEP |
+           SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
+       if (csa->prob.spu_status_R & mask) {
+               out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+               eieio();
+               POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                               SPU_STATUS_RUNNING);
+       }
+}
+
+static inline void restore_status_part2(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       u32 mask;
+
+       /* Restore, Step 43:
+        *     If all CSA.SPU_Status[I,S,H,P,R]=0 then write
+        *     SPU_RunCntl[R0R1]='01', wait for SPU_Status[R]=1,
+        *     then write '00' to SPU_RunCntl[R0R1] and wait
+        *     for SPU_Status[R]=0.
+        */
+       mask = SPU_STATUS_INVALID_INSTR |
+           SPU_STATUS_SINGLE_STEP |
+           SPU_STATUS_STOPPED_BY_HALT |
+           SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING;
+       if (!(csa->prob.spu_status_R & mask)) {
+               out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+               eieio();
+               POLL_WHILE_FALSE(in_be32(&prob->spu_status_R) &
+                                SPU_STATUS_RUNNING);
+               out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+               eieio();
+               POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+                               SPU_STATUS_RUNNING);
+       }
+}
+
+static inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu)
+{
+       unsigned long addr = (unsigned long)&csa->lscsa->ls[0];
+       unsigned int ls_offset = 0x0;
+       unsigned int size = 16384;
+       unsigned int tag = 0;
+       unsigned int rclass = 0;
+       unsigned int cmd = MFC_GET_CMD;
+
+       /* Restore, Step 44:
+        *     Issue a DMA command to restore the first
+        *     16kb of local storage from CSA.
+        */
+       send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 49:
+        *     Write INT_MASK_class0 with value of 0.
+        *     Write INT_MASK_class1 with value of 0.
+        *     Write INT_MASK_class2 with value of 0.
+        *     Write INT_STAT_class0 with value of -1.
+        *     Write INT_STAT_class1 with value of -1.
+        *     Write INT_STAT_class2 with value of -1.
+        */
+       spin_lock_irq(&spu->register_lock);
+       spu_int_mask_set(spu, 0, 0ul);
+       spu_int_mask_set(spu, 1, 0ul);
+       spu_int_mask_set(spu, 2, 0ul);
+       spu_int_stat_clear(spu, 0, ~0ul);
+       spu_int_stat_clear(spu, 1, ~0ul);
+       spu_int_stat_clear(spu, 2, ~0ul);
+       spin_unlock_irq(&spu->register_lock);
+}
+
+static inline void restore_mfc_queues(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       int i;
+
+       /* Restore, Step 50:
+        *     If MFC_Cntl[Se]!=0 then restore
+        *     MFC command queues.
+        */
+       if ((csa->priv2.mfc_control_RW & MFC_CNTL_DMA_QUEUES_EMPTY_MASK) == 0) {
+               for (i = 0; i < 8; i++) {
+                       out_be64(&priv2->puq[i].mfc_cq_data0_RW,
+                                csa->priv2.puq[i].mfc_cq_data0_RW);
+                       out_be64(&priv2->puq[i].mfc_cq_data1_RW,
+                                csa->priv2.puq[i].mfc_cq_data1_RW);
+                       out_be64(&priv2->puq[i].mfc_cq_data2_RW,
+                                csa->priv2.puq[i].mfc_cq_data2_RW);
+                       out_be64(&priv2->puq[i].mfc_cq_data3_RW,
+                                csa->priv2.puq[i].mfc_cq_data3_RW);
+               }
+               for (i = 0; i < 16; i++) {
+                       out_be64(&priv2->spuq[i].mfc_cq_data0_RW,
+                                csa->priv2.spuq[i].mfc_cq_data0_RW);
+                       out_be64(&priv2->spuq[i].mfc_cq_data1_RW,
+                                csa->priv2.spuq[i].mfc_cq_data1_RW);
+                       out_be64(&priv2->spuq[i].mfc_cq_data2_RW,
+                                csa->priv2.spuq[i].mfc_cq_data2_RW);
+                       out_be64(&priv2->spuq[i].mfc_cq_data3_RW,
+                                csa->priv2.spuq[i].mfc_cq_data3_RW);
+               }
+       }
+       eieio();
+}
+
+static inline void restore_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Restore, Step 51:
+        *     Restore the PPU_QueryMask register from CSA.
+        */
+       out_be32(&prob->dma_querymask_RW, csa->prob.dma_querymask_RW);
+       eieio();
+}
+
+static inline void restore_ppu_querytype(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Restore, Step 52:
+        *     Restore the PPU_QueryType register from CSA.
+        */
+       out_be32(&prob->dma_querytype_RW, csa->prob.dma_querytype_RW);
+       eieio();
+}
+
+static inline void restore_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 53:
+        *     Restore the MFC_CSR_TSQ register from CSA.
+        */
+       out_be64(&priv2->spu_tag_status_query_RW,
+                csa->priv2.spu_tag_status_query_RW);
+       eieio();
+}
+
+static inline void restore_mfc_csr_cmd(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 54:
+        *     Restore the MFC_CSR_CMD1 and MFC_CSR_CMD2
+        *     registers from CSA.
+        */
+       out_be64(&priv2->spu_cmd_buf1_RW, csa->priv2.spu_cmd_buf1_RW);
+       out_be64(&priv2->spu_cmd_buf2_RW, csa->priv2.spu_cmd_buf2_RW);
+       eieio();
+}
+
+static inline void restore_mfc_csr_ato(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 55:
+        *     Restore the MFC_CSR_ATO register from CSA.
+        */
+       out_be64(&priv2->spu_atomic_status_RW, csa->priv2.spu_atomic_status_RW);
+}
+
+static inline void restore_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 56:
+        *     Restore the MFC_TCLASS_ID register from CSA.
+        */
+       spu_mfc_tclass_id_set(spu, csa->priv1.mfc_tclass_id_RW);
+       eieio();
+}
+
+static inline void set_llr_event(struct spu_state *csa, struct spu *spu)
+{
+       u64 ch0_cnt, ch0_data;
+       u64 ch1_data;
+
+       /* Restore, Step 57:
+        *    Set the Lock Line Reservation Lost Event by:
+        *      1. OR CSA.SPU_Event_Status with bit 21 (Lr) set to 1.
+        *      2. If CSA.SPU_Channel_0_Count=0 and
+        *         CSA.SPU_Wr_Event_Mask[Lr]=1 and
+        *         CSA.SPU_Event_Status[Lr]=0 then set
+        *         CSA.SPU_Event_Status_Count=1.
+        */
+       ch0_cnt = csa->spu_chnlcnt_RW[0];
+       ch0_data = csa->spu_chnldata_RW[0];
+       ch1_data = csa->spu_chnldata_RW[1];
+       csa->spu_chnldata_RW[0] |= MFC_LLR_LOST_EVENT;
+       if ((ch0_cnt == 0) && !(ch0_data & MFC_LLR_LOST_EVENT) &&
+           (ch1_data & MFC_LLR_LOST_EVENT)) {
+               csa->spu_chnlcnt_RW[0] = 1;
+       }
+}
+
+static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 58:
+        *     If the status of the CSA software decrementer
+        *     "wrapped" flag is set, OR in a '1' to
+        *     CSA.SPU_Event_Status[Tm].
+        */
+       if (csa->lscsa->decr_status.slot[0] == 1) {
+               csa->spu_chnldata_RW[0] |= 0x20;
+       }
+       if ((csa->lscsa->decr_status.slot[0] == 1) &&
+           (csa->spu_chnlcnt_RW[0] == 0 &&
+            ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) &&
+            ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) {
+               csa->spu_chnlcnt_RW[0] = 1;
+       }
+}
+
+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, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       int i;
+
+       /* Restore, Step 59:
+        *     Restore the following CH: [0,1,3,4,24,25,27]
+        */
+       for (i = 0; i < 7; i++) {
+               idx = ch_indices[i];
+               out_be64(&priv2->spu_chnlcntptr_RW, idx);
+               eieio();
+               out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[idx]);
+               out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[idx]);
+               eieio();
+       }
+}
+
+static inline void restore_ch_part2(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       u64 ch_indices[3] = { 9UL, 21UL, 23UL };
+       u64 ch_counts[3] = { 1UL, 16UL, 1UL };
+       u64 idx;
+       int i;
+
+       /* Restore, Step 60:
+        *     Restore the following CH: [9,21,23].
+        */
+       ch_counts[0] = 1UL;
+       ch_counts[1] = csa->spu_chnlcnt_RW[21];
+       ch_counts[2] = 1UL;
+       for (i = 0; i < 3; i++) {
+               idx = ch_indices[i];
+               out_be64(&priv2->spu_chnlcntptr_RW, idx);
+               eieio();
+               out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+               eieio();
+       }
+}
+
+static inline void restore_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 61:
+        *     Restore the SPU_LSLR register from CSA.
+        */
+       out_be64(&priv2->spu_lslr_RW, csa->priv2.spu_lslr_RW);
+       eieio();
+}
+
+static inline void restore_spu_cfg(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 62:
+        *     Restore the SPU_Cfg register from CSA.
+        */
+       out_be64(&priv2->spu_cfg_RW, csa->priv2.spu_cfg_RW);
+       eieio();
+}
+
+static inline void restore_pm_trace(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 63:
+        *     Restore PM_Trace_Tag_Wait_Mask from CSA.
+        *     Not performed by this implementation.
+        */
+}
+
+static inline void restore_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Restore, Step 64:
+        *     Restore SPU_NPC from CSA.
+        */
+       out_be32(&prob->spu_npc_RW, csa->prob.spu_npc_RW);
+       eieio();
+}
+
+static inline void restore_spu_mb(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       int i;
+
+       /* Restore, Step 65:
+        *     Restore MFC_RdSPU_MB from CSA.
+        */
+       out_be64(&priv2->spu_chnlcntptr_RW, 29UL);
+       eieio();
+       out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]);
+       for (i = 0; i < 4; i++) {
+               out_be64(&priv2->spu_chnldata_RW, csa->spu_mailbox_data[i]);
+       }
+       eieio();
+}
+
+static inline void check_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+       u32 dummy = 0;
+
+       /* Restore, Step 66:
+        *     If CSA.MB_Stat[P]=0 (mailbox empty) then
+        *     read from the PPU_MB register.
+        */
+       if ((csa->prob.mb_stat_R & 0xFF) == 0) {
+               dummy = in_be32(&prob->pu_mb_R);
+               eieio();
+       }
+}
+
+static inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       u64 dummy = 0UL;
+
+       /* Restore, Step 66:
+        *     If CSA.MB_Stat[I]=0 (mailbox empty) then
+        *     read from the PPUINT_MB register.
+        */
+       if ((csa->prob.mb_stat_R & 0xFF0000) == 0) {
+               dummy = in_be64(&priv2->puint_mb_R);
+               eieio();
+               spu_int_stat_clear(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
+               eieio();
+       }
+}
+
+static inline void restore_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+       int i;
+
+       /* Restore, Step 68:
+        *     If MFC_SR1[R]='1', restore SLBs from CSA.
+        */
+       if (csa->priv1.mfc_sr1_RW & MFC_STATE1_RELOCATE_MASK) {
+               for (i = 0; i < 8; i++) {
+                       out_be64(&priv2->slb_index_W, i);
+                       eieio();
+                       out_be64(&priv2->slb_esid_RW, csa->slb_esid_RW[i]);
+                       out_be64(&priv2->slb_vsid_RW, csa->slb_vsid_RW[i]);
+                       eieio();
+               }
+               out_be64(&priv2->slb_index_W, csa->priv2.slb_index_W);
+               eieio();
+       }
+}
+
+static inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 69:
+        *     Restore the MFC_SR1 register from CSA.
+        */
+       spu_mfc_sr1_set(spu, csa->priv1.mfc_sr1_RW);
+       eieio();
+}
+
+static inline void restore_other_spu_access(struct spu_state *csa,
+                                           struct spu *spu)
+{
+       /* Restore, Step 70:
+        *     Restore other SPU mappings to this SPU. TBD.
+        */
+}
+
+static inline void restore_spu_runcntl(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_problem __iomem *prob = spu->problem;
+
+       /* Restore, Step 71:
+        *     If CSA.SPU_Status[R]=1 then write
+        *     SPU_RunCntl[R0R1]='01'.
+        */
+       if (csa->prob.spu_status_R & SPU_STATUS_RUNNING) {
+               out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+               eieio();
+       }
+}
+
+static inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 72:
+        *    Restore the MFC_CNTL register for the CSA.
+        */
+       out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW);
+       eieio();
+}
+
+static inline void enable_user_access(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 73:
+        *     Enable user-space access (if provided) to this
+        *     SPU by mapping the virtual pages assigned to
+        *     the SPU memory-mapped I/O (MMIO) for problem
+        *     state. TBD.
+        */
+}
+
+static inline void reset_switch_active(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 74:
+        *     Reset the "context switch active" flag.
+        */
+       clear_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
+       mb();
+}
+
+static inline void reenable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+       /* Restore, Step 75:
+        *     Re-enable SPU interrupts.
+        */
+       spin_lock_irq(&spu->register_lock);
+       spu_int_mask_set(spu, 0, csa->priv1.int_mask_class0_RW);
+       spu_int_mask_set(spu, 1, csa->priv1.int_mask_class1_RW);
+       spu_int_mask_set(spu, 2, csa->priv1.int_mask_class2_RW);
+       spin_unlock_irq(&spu->register_lock);
+}
+
+static int quiece_spu(struct spu_state *prev, struct spu *spu)
+{
+       /*
+        * Combined steps 2-18 of SPU context save sequence, which
+        * quiesce the SPU state (disable SPU execution, MFC command
+        * queues, decrementer, SPU interrupts, etc.).
+        *
+        * Returns      0 on success.
+        *              2 if failed step 2.
+        *              6 if failed step 6.
+        */
+
+       if (check_spu_isolate(prev, spu)) {     /* Step 2. */
+               return 2;
+       }
+       disable_interrupts(prev, spu);          /* Step 3. */
+       set_watchdog_timer(prev, spu);          /* Step 4. */
+       inhibit_user_access(prev, spu);         /* Step 5. */
+       if (check_spu_isolate(prev, spu)) {     /* Step 6. */
+               return 6;
+       }
+       set_switch_pending(prev, spu);          /* Step 7. */
+       save_mfc_cntl(prev, spu);               /* Step 8. */
+       save_spu_runcntl(prev, spu);            /* Step 9. */
+       save_mfc_sr1(prev, spu);                /* Step 10. */
+       save_spu_status(prev, spu);             /* Step 11. */
+       save_mfc_decr(prev, spu);               /* Step 12. */
+       halt_mfc_decr(prev, spu);               /* Step 13. */
+       save_timebase(prev, spu);               /* Step 14. */
+       remove_other_spu_access(prev, spu);     /* Step 15. */
+       do_mfc_mssync(prev, spu);               /* Step 16. */
+       issue_mfc_tlbie(prev, spu);             /* Step 17. */
+       handle_pending_interrupts(prev, spu);   /* Step 18. */
+
+       return 0;
+}
+
+static void save_csa(struct spu_state *prev, struct spu *spu)
+{
+       /*
+        * Combine steps 19-44 of SPU context save sequence, which
+        * save regions of the privileged & problem state areas.
+        */
+
+       save_mfc_queues(prev, spu);     /* Step 19. */
+       save_ppu_querymask(prev, spu);  /* Step 20. */
+       save_ppu_querytype(prev, spu);  /* Step 21. */
+       save_mfc_csr_tsq(prev, spu);    /* Step 22. */
+       save_mfc_csr_cmd(prev, spu);    /* Step 23. */
+       save_mfc_csr_ato(prev, spu);    /* Step 24. */
+       save_mfc_tclass_id(prev, spu);  /* Step 25. */
+       set_mfc_tclass_id(prev, spu);   /* Step 26. */
+       purge_mfc_queue(prev, spu);     /* Step 27. */
+       wait_purge_complete(prev, spu); /* Step 28. */
+       save_mfc_slbs(prev, spu);       /* Step 29. */
+       setup_mfc_sr1(prev, spu);       /* Step 30. */
+       save_spu_npc(prev, spu);        /* Step 31. */
+       save_spu_privcntl(prev, spu);   /* Step 32. */
+       reset_spu_privcntl(prev, spu);  /* Step 33. */
+       save_spu_lslr(prev, spu);       /* Step 34. */
+       reset_spu_lslr(prev, spu);      /* Step 35. */
+       save_spu_cfg(prev, spu);        /* Step 36. */
+       save_pm_trace(prev, spu);       /* Step 37. */
+       save_mfc_rag(prev, spu);        /* Step 38. */
+       save_ppu_mb_stat(prev, spu);    /* Step 39. */
+       save_ppu_mb(prev, spu);         /* Step 40. */
+       save_ppuint_mb(prev, spu);      /* Step 41. */
+       save_ch_part1(prev, spu);       /* Step 42. */
+       save_spu_mb(prev, spu);         /* Step 43. */
+       save_mfc_cmd(prev, spu);        /* Step 44. */
+       reset_ch(prev, spu);            /* Step 45. */
+}
+
+static void save_lscsa(struct spu_state *prev, struct spu *spu)
+{
+       /*
+        * Perform steps 46-57 of SPU context save sequence,
+        * which save regions of the local store and register
+        * file.
+        */
+
+       resume_mfc_queue(prev, spu);    /* Step 46. */
+       setup_mfc_slbs(prev, spu);      /* Step 47. */
+       set_switch_active(prev, spu);   /* Step 48. */
+       enable_interrupts(prev, spu);   /* Step 49. */
+       save_ls_16kb(prev, spu);        /* Step 50. */
+       set_spu_npc(prev, spu);         /* Step 51. */
+       set_signot1(prev, spu);         /* Step 52. */
+       set_signot2(prev, spu);         /* Step 53. */
+       send_save_code(prev, spu);      /* Step 54. */
+       set_ppu_querymask(prev, spu);   /* Step 55. */
+       wait_tag_complete(prev, spu);   /* Step 56. */
+       wait_spu_stopped(prev, spu);    /* Step 57. */
+}
+
+static void harvest(struct spu_state *prev, struct spu *spu)
+{
+       /*
+        * Perform steps 2-25 of SPU context restore sequence,
+        * which resets an SPU either after a failed save, or
+        * when using SPU for first time.
+        */
+
+       disable_interrupts(prev, spu);          /* Step 2.  */
+       inhibit_user_access(prev, spu);         /* Step 3.  */
+       terminate_spu_app(prev, spu);           /* Step 4.  */
+       set_switch_pending(prev, spu);          /* Step 5.  */
+       remove_other_spu_access(prev, spu);     /* Step 6.  */
+       suspend_mfc(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. */
+       do_mfc_mssync(prev, spu);               /* Step 11. */
+       issue_mfc_tlbie(prev, spu);             /* Step 12. */
+       handle_pending_interrupts(prev, spu);   /* Step 13. */
+       purge_mfc_queue(prev, spu);             /* Step 14. */
+       wait_purge_complete(prev, spu);         /* Step 15. */
+       reset_spu_privcntl(prev, spu);          /* Step 16. */
+       reset_spu_lslr(prev, spu);              /* Step 17. */
+       setup_mfc_sr1(prev, spu);               /* Step 18. */
+       invalidate_slbs(prev, spu);             /* Step 19. */
+       reset_ch_part1(prev, spu);              /* Step 20. */
+       reset_ch_part2(prev, spu);              /* Step 21. */
+       enable_interrupts(prev, spu);           /* Step 22. */
+       set_switch_active(prev, spu);           /* Step 23. */
+       set_mfc_tclass_id(prev, spu);           /* Step 24. */
+       resume_mfc_queue(prev, spu);            /* Step 25. */
+}
+
+static void restore_lscsa(struct spu_state *next, struct spu *spu)
+{
+       /*
+        * Perform steps 26-40 of SPU context restore sequence,
+        * which restores regions of the local store and register
+        * file.
+        */
+
+       set_watchdog_timer(next, spu);          /* Step 26. */
+       setup_spu_status_part1(next, spu);      /* Step 27. */
+       setup_spu_status_part2(next, spu);      /* Step 28. */
+       restore_mfc_rag(next, spu);             /* Step 29. */
+       setup_mfc_slbs(next, spu);              /* Step 30. */
+       set_spu_npc(next, spu);                 /* Step 31. */
+       set_signot1(next, spu);                 /* Step 32. */
+       set_signot2(next, spu);                 /* Step 33. */
+       setup_decr(next, spu);                  /* Step 34. */
+       setup_ppu_mb(next, spu);                /* Step 35. */
+       setup_ppuint_mb(next, spu);             /* Step 36. */
+       send_restore_code(next, spu);           /* Step 37. */
+       set_ppu_querymask(next, spu);           /* Step 38. */
+       wait_tag_complete(next, spu);           /* Step 39. */
+       wait_spu_stopped(next, spu);            /* Step 40. */
+}
+
+static void restore_csa(struct spu_state *next, struct spu *spu)
+{
+       /*
+        * Combine steps 41-76 of SPU context restore sequence, which
+        * restore regions of the privileged & problem state areas.
+        */
+
+       restore_spu_privcntl(next, spu);        /* Step 41. */
+       restore_status_part1(next, spu);        /* Step 42. */
+       restore_status_part2(next, spu);        /* Step 43. */
+       restore_ls_16kb(next, spu);             /* Step 44. */
+       wait_tag_complete(next, spu);           /* Step 45. */
+       suspend_mfc(next, spu);                 /* Step 46. */
+       wait_suspend_mfc_complete(next, spu);   /* Step 47. */
+       issue_mfc_tlbie(next, spu);             /* Step 48. */
+       clear_interrupts(next, spu);            /* Step 49. */
+       restore_mfc_queues(next, spu);          /* Step 50. */
+       restore_ppu_querymask(next, spu);       /* Step 51. */
+       restore_ppu_querytype(next, spu);       /* Step 52. */
+       restore_mfc_csr_tsq(next, spu);         /* Step 53. */
+       restore_mfc_csr_cmd(next, spu);         /* Step 54. */
+       restore_mfc_csr_ato(next, spu);         /* Step 55. */
+       restore_mfc_tclass_id(next, spu);       /* Step 56. */
+       set_llr_event(next, spu);               /* Step 57. */
+       restore_decr_wrapped(next, spu);        /* Step 58. */
+       restore_ch_part1(next, spu);            /* Step 59. */
+       restore_ch_part2(next, spu);            /* Step 60. */
+       restore_spu_lslr(next, spu);            /* Step 61. */
+       restore_spu_cfg(next, spu);             /* Step 62. */
+       restore_pm_trace(next, spu);            /* Step 63. */
+       restore_spu_npc(next, spu);             /* Step 64. */
+       restore_spu_mb(next, spu);              /* Step 65. */
+       check_ppu_mb_stat(next, spu);           /* Step 66. */
+       check_ppuint_mb_stat(next, spu);        /* Step 67. */
+       restore_mfc_slbs(next, spu);            /* Step 68. */
+       restore_mfc_sr1(next, spu);             /* Step 69. */
+       restore_other_spu_access(next, spu);    /* Step 70. */
+       restore_spu_runcntl(next, spu);         /* Step 71. */
+       restore_mfc_cntl(next, spu);            /* Step 72. */
+       enable_user_access(next, spu);          /* Step 73. */
+       reset_switch_active(next, spu);         /* Step 74. */
+       reenable_interrupts(next, spu);         /* Step 75. */
+}
+
+static int __do_spu_save(struct spu_state *prev, struct spu *spu)
+{
+       int rc;
+
+       /*
+        * SPU context save can be broken into three phases:
+        *
+        *     (a) quiesce [steps 2-16].
+        *     (b) save of CSA, performed by PPE [steps 17-42]
+        *     (c) save of LSCSA, mostly performed by SPU [steps 43-52].
+        *
+        * Returns      0 on success.
+        *              2,6 if failed to quiece SPU
+        *              53 if SPU-side of save failed.
+        */
+
+       rc = quiece_spu(prev, spu);             /* Steps 2-16. */
+       switch (rc) {
+       default:
+       case 2:
+       case 6:
+               harvest(prev, spu);
+               return rc;
+               break;
+       case 0:
+               break;
+       }
+       save_csa(prev, spu);                    /* Steps 17-43. */
+       save_lscsa(prev, spu);                  /* Steps 44-53. */
+       return check_save_status(prev, spu);    /* Step 54.     */
+}
+
+static int __do_spu_restore(struct spu_state *next, struct spu *spu)
+{
+       int rc;
+
+       /*
+        * SPU context restore can be broken into three phases:
+        *
+        *    (a) harvest (or reset) SPU [steps 2-24].
+        *    (b) restore LSCSA [steps 25-40], mostly performed by SPU.
+        *    (c) restore CSA [steps 41-76], performed by PPE.
+        *
+        * The 'harvest' step is not performed here, but rather
+        * as needed below.
+        */
+
+       restore_lscsa(next, spu);               /* Steps 24-39. */
+       rc = check_restore_status(next, spu);   /* Step 40.     */
+       switch (rc) {
+       default:
+               /* Failed. Return now. */
+               return rc;
+               break;
+       case 0:
+               /* Fall through to next step. */
+               break;
+       }
+       restore_csa(next, spu);
+
+       return 0;
+}
+
+/**
+ * spu_save - SPU context save, with locking.
+ * @prev: pointer to SPU context save area, to be saved.
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Acquire locks, perform the save operation then return.
+ */
+int spu_save(struct spu_state *prev, struct spu *spu)
+{
+       int rc;
+
+       acquire_spu_lock(spu);          /* Step 1.     */
+       rc = __do_spu_save(prev, spu);  /* Steps 2-53. */
+       release_spu_lock(spu);
+       if (rc) {
+               panic("%s failed on SPU[%d], rc=%d.\n",
+                     __func__, spu->number, rc);
+       }
+       return rc;
+}
+
+/**
+ * spu_restore - SPU context restore, with harvest and locking.
+ * @new: pointer to SPU context save area, to be restored.
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Perform harvest + restore, as we may not be coming
+ * from a previous succesful save operation, and the
+ * hardware state is unknown.
+ */
+int spu_restore(struct spu_state *new, struct spu *spu)
+{
+       int rc;
+
+       acquire_spu_lock(spu);
+       harvest(NULL, spu);
+       spu->stop_code = 0;
+       spu->dar = 0;
+       spu->dsisr = 0;
+       spu->slb_replace = 0;
+       spu->class_0_pending = 0;
+       rc = __do_spu_restore(new, spu);
+       release_spu_lock(spu);
+       if (rc) {
+               panic("%s failed on SPU[%d] rc=%d.\n",
+                      __func__, spu->number, rc);
+       }
+       return rc;
+}
+
+/**
+ * spu_harvest - SPU harvest (reset) operation
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Perform SPU harvest (reset) operation.
+ */
+void spu_harvest(struct spu *spu)
+{
+       acquire_spu_lock(spu);
+       harvest(NULL, spu);
+       release_spu_lock(spu);
+}
+
+static void init_prob(struct spu_state *csa)
+{
+       csa->spu_chnlcnt_RW[9] = 1;
+       csa->spu_chnlcnt_RW[21] = 16;
+       csa->spu_chnlcnt_RW[23] = 1;
+       csa->spu_chnlcnt_RW[28] = 1;
+       csa->spu_chnlcnt_RW[30] = 1;
+       csa->prob.spu_runcntl_RW = SPU_RUNCNTL_STOP;
+}
+
+static void init_priv1(struct spu_state *csa)
+{
+       /* Enable decode, relocate, tlbie response, master runcntl. */
+       csa->priv1.mfc_sr1_RW = MFC_STATE1_LOCAL_STORAGE_DECODE_MASK |
+           MFC_STATE1_MASTER_RUN_CONTROL_MASK |
+           MFC_STATE1_PROBLEM_STATE_MASK |
+           MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK;
+
+       /* Set storage description.  */
+       csa->priv1.mfc_sdr_RW = mfspr(SPRN_SDR1);
+
+       /* Enable OS-specific set of interrupts. */
+       csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR |
+           CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR |
+           CLASS0_ENABLE_SPU_ERROR_INTR;
+       csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
+           CLASS1_ENABLE_STORAGE_FAULT_INTR;
+       csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR |
+           CLASS2_ENABLE_SPU_HALT_INTR;
+}
+
+static void init_priv2(struct spu_state *csa)
+{
+       csa->priv2.spu_lslr_RW = LS_ADDR_MASK;
+       csa->priv2.mfc_control_RW = MFC_CNTL_RESUME_DMA_QUEUE |
+           MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION |
+           MFC_CNTL_DMA_QUEUES_EMPTY_MASK;
+}
+
+/**
+ * spu_alloc_csa - allocate and initialize an SPU context save area.
+ *
+ * Allocate and initialize the contents of an SPU context save area.
+ * This includes enabling address translation, interrupt masks, etc.,
+ * as appropriate for the given OS environment.
+ *
+ * Note that storage for the 'lscsa' is allocated separately,
+ * as it is by far the largest of the context save regions,
+ * and may need to be pinned or otherwise specially aligned.
+ */
+void spu_init_csa(struct spu_state *csa)
+{
+       struct spu_lscsa *lscsa;
+       unsigned char *p;
+
+       if (!csa)
+               return;
+       memset(csa, 0, sizeof(struct spu_state));
+
+       lscsa = vmalloc(sizeof(struct spu_lscsa));
+       if (!lscsa)
+               return;
+
+       memset(lscsa, 0, sizeof(struct spu_lscsa));
+       csa->lscsa = lscsa;
+       csa->register_lock = SPIN_LOCK_UNLOCKED;
+
+       /* Set LS pages reserved to allow for user-space mapping. */
+       for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+               SetPageReserved(vmalloc_to_page(p));
+
+       init_prob(csa);
+       init_priv1(csa);
+       init_priv2(csa);
+}
+
+void spu_fini_csa(struct spu_state *csa)
+{
+       /* Clear reserved bit before vfree. */
+       unsigned char *p;
+       for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+               ClearPageReserved(vmalloc_to_page(p));
+
+       vfree(csa->lscsa);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
new file mode 100644 (file)
index 0000000..d549aa7
--- /dev/null
@@ -0,0 +1,101 @@
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+/**
+ * sys_spu_run - run code loaded into an SPU
+ *
+ * @unpc:    next program counter for the SPU
+ * @ustatus: status of the SPU
+ *
+ * This system call transfers the control of execution of a
+ * user space thread to an SPU. It will return when the
+ * SPU has finished executing or when it hits an error
+ * condition and it will be interrupted if a signal needs
+ * to be delivered to a handler in user space.
+ *
+ * The next program counter is set to the passed value
+ * before the SPU starts fetching code and the user space
+ * pointer gets updated with the new value when returning
+ * from kernel space.
+ *
+ * The status value returned from spu_run reflects the
+ * value of the spu_status register after the SPU has stopped.
+ *
+ */
+long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus)
+{
+       long ret;
+       struct spufs_inode_info *i;
+       u32 npc, status;
+
+       ret = -EFAULT;
+       if (get_user(npc, unpc) || get_user(status, ustatus))
+               goto out;
+
+       /* check if this file was created by spu_create */
+       ret = -EINVAL;
+       if (filp->f_op != &spufs_context_fops)
+               goto out;
+
+       i = SPUFS_I(filp->f_dentry->d_inode);
+       ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
+
+       if (put_user(npc, unpc) || put_user(status, ustatus))
+               ret = -EFAULT;
+out:
+       return ret;
+}
+
+#ifndef MODULE
+asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
+{
+       int fput_needed;
+       struct file *filp;
+       long ret;
+
+       ret = -EBADF;
+       filp = fget_light(fd, &fput_needed);
+       if (filp) {
+               ret = do_spu_run(filp, unpc, ustatus);
+               fput_light(filp, fput_needed);
+       }
+
+       return ret;
+}
+#endif
+
+asmlinkage long sys_spu_create(const char __user *pathname,
+                                       unsigned int flags, mode_t mode)
+{
+       char *tmp;
+       int ret;
+
+       tmp = getname(pathname);
+       ret = PTR_ERR(tmp);
+       if (!IS_ERR(tmp)) {
+               struct nameidata nd;
+
+               ret = path_lookup(tmp, LOOKUP_PARENT|
+                               LOOKUP_OPEN|LOOKUP_CREATE, &nd);
+               if (!ret) {
+                       ret = spufs_create_thread(&nd, flags, mode);
+                       path_release(&nd);
+               }
+               putname(tmp);
+       }
+
+       return ret;
+}
+
+struct spufs_calls spufs_calls = {
+       .create_thread = sys_spu_create,
+       .spu_run = do_spu_run,
+       .owner = THIS_MODULE,
+};
index dda5f2c72c256f5e73e05de80eb4833bcc4d3f5a..4ec8ba737e7d71cf486abf14d6f27d9d9e1ce317 100644 (file)
@@ -49,7 +49,6 @@
 #include <asm/hydra.h>
 #include <asm/sections.h>
 #include <asm/time.h>
-#include <asm/btext.h>
 #include <asm/i8259.h>
 #include <asm/mpic.h>
 #include <asm/rtas.h>
@@ -58,7 +57,6 @@
 #include "chrp.h"
 
 void rtas_indicator_progress(char *, unsigned short);
-void btext_progress(char *, unsigned short);
 
 int _chrp_type;
 EXPORT_SYMBOL(_chrp_type);
@@ -264,11 +262,6 @@ void __init chrp_setup_arch(void)
                ppc_md.set_rtc_time     = rtas_set_rtc_time;
        }
 
-#ifdef CONFIG_BOOTX_TEXT
-       if (ppc_md.progress == NULL && boot_text_mapped)
-               ppc_md.progress = btext_progress;
-#endif
-
 #ifdef CONFIG_BLK_DEV_INITRD
        /* this is fine for chrp */
        initrd_below_start_ok = 1;
@@ -522,12 +515,3 @@ void __init chrp_init(void)
        smp_ops = &chrp_smp_ops;
 #endif /* CONFIG_SMP */
 }
-
-#ifdef CONFIG_BOOTX_TEXT
-void
-btext_progress(char *s, unsigned short hex)
-{
-       btext_drawstring(s);
-       btext_drawstring("\n");
-}
-#endif /* CONFIG_BOOTX_TEXT */
index a58daa153686db64ca16a9fb4bc6b4f84a19ae7b..42e978e4897a9d24860ed741abca38ecb2b65133 100644 (file)
 #include <linux/irq.h>
 #include <linux/spinlock.h>
 
+#include <asm/paca.h>
 #include <asm/iseries/hv_types.h>
 #include <asm/iseries/hv_lp_event.h>
 #include <asm/iseries/hv_call_xm.h>
+#include <asm/iseries/it_lp_queue.h>
 
 #include "irq.h"
 #include "call_pci.h"
 
-static long Pci_Interrupt_Count;
-static long Pci_Event_Count;
-
-enum XmPciLpEvent_Subtype {
-       XmPciLpEvent_BusCreated         = 0,    // PHB has been created
-       XmPciLpEvent_BusError           = 1,    // PHB has failed
-       XmPciLpEvent_BusFailed          = 2,    // Msg to Secondary, Primary failed bus
-       XmPciLpEvent_NodeFailed         = 4,    // Multi-adapter bridge has failed
-       XmPciLpEvent_NodeRecovered      = 5,    // Multi-adapter bridge has recovered
-       XmPciLpEvent_BusRecovered       = 12,   // PHB has been recovered
-       XmPciLpEvent_UnQuiesceBus       = 18,   // Secondary bus unqiescing
-       XmPciLpEvent_BridgeError        = 21,   // Bridge Error
-       XmPciLpEvent_SlotInterrupt      = 22    // Slot interrupt
-};
-
-struct XmPciLpEvent_BusInterrupt {
-       HvBusNumber     busNumber;
-       HvSubBusNumber  subBusNumber;
-};
+#if defined(CONFIG_SMP)
+extern void iSeries_smp_message_recv(struct pt_regs *);
+#endif
 
-struct XmPciLpEvent_NodeInterrupt {
-       HvBusNumber     busNumber;
-       HvSubBusNumber  subBusNumber;
-       HvAgentId       deviceId;
+enum pci_event_type {
+       pe_bus_created          = 0,    /* PHB has been created */
+       pe_bus_error            = 1,    /* PHB has failed */
+       pe_bus_failed           = 2,    /* Msg to Secondary, Primary failed bus */
+       pe_node_failed          = 4,    /* Multi-adapter bridge has failed */
+       pe_node_recovered       = 5,    /* Multi-adapter bridge has recovered */
+       pe_bus_recovered        = 12,   /* PHB has been recovered */
+       pe_unquiese_bus         = 18,   /* Secondary bus unqiescing */
+       pe_bridge_error         = 21,   /* Bridge Error */
+       pe_slot_interrupt       = 22    /* Slot interrupt */
 };
 
-struct XmPciLpEvent {
-       struct HvLpEvent hvLpEvent;
-
+struct pci_event {
+       struct HvLpEvent event;
        union {
-               u64 alignData;                  // Align on an 8-byte boundary
-
+               u64 __align;            /* Align on an 8-byte boundary */
                struct {
                        u32             fisr;
-                       HvBusNumber     busNumber;
-                       HvSubBusNumber  subBusNumber;
-                       HvAgentId       deviceId;
-               } slotInterrupt;
-
-               struct XmPciLpEvent_BusInterrupt busFailed;
-               struct XmPciLpEvent_BusInterrupt busRecovered;
-               struct XmPciLpEvent_BusInterrupt busCreated;
-
-               struct XmPciLpEvent_NodeInterrupt nodeFailed;
-               struct XmPciLpEvent_NodeInterrupt nodeRecovered;
-
-       } eventData;
-
+                       HvBusNumber     bus_number;
+                       HvSubBusNumber  sub_bus_number;
+                       HvAgentId       dev_id;
+               } slot;
+               struct {
+                       HvBusNumber     bus_number;
+                       HvSubBusNumber  sub_bus_number;
+               } bus;
+               struct {
+                       HvBusNumber     bus_number;
+                       HvSubBusNumber  sub_bus_number;
+                       HvAgentId       dev_id;
+               } node;
+       } data;
 };
 
-static void intReceived(struct XmPciLpEvent *eventParm,
-               struct pt_regs *regsParm)
+static DEFINE_SPINLOCK(pending_irqs_lock);
+static int num_pending_irqs;
+static int pending_irqs[NR_IRQS];
+
+static void int_received(struct pci_event *event, struct pt_regs *regs)
 {
        int irq;
-#ifdef CONFIG_IRQSTACKS
-       struct thread_info *curtp, *irqtp;
-#endif
 
-       ++Pci_Interrupt_Count;
-
-       switch (eventParm->hvLpEvent.xSubtype) {
-       case XmPciLpEvent_SlotInterrupt:
-               irq = eventParm->hvLpEvent.xCorrelationToken;
-               /* Dispatch the interrupt handlers for this irq */
-#ifdef CONFIG_IRQSTACKS
-               /* Switch to the irq stack to handle this */
-               curtp = current_thread_info();
-               irqtp = hardirq_ctx[smp_processor_id()];
-               if (curtp != irqtp) {
-                       irqtp->task = curtp->task;
-                       irqtp->flags = 0;
-                       call___do_IRQ(irq, regsParm, irqtp);
-                       irqtp->task = NULL;
-                       if (irqtp->flags)
-                               set_bits(irqtp->flags, &curtp->flags);
-               } else
-#endif
-                       __do_IRQ(irq, regsParm);
-               HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
-                       eventParm->eventData.slotInterrupt.subBusNumber,
-                       eventParm->eventData.slotInterrupt.deviceId);
+       switch (event->event.xSubtype) {
+       case pe_slot_interrupt:
+               irq = event->event.xCorrelationToken;
+               if (irq < NR_IRQS) {
+                       spin_lock(&pending_irqs_lock);
+                       pending_irqs[irq]++;
+                       num_pending_irqs++;
+                       spin_unlock(&pending_irqs_lock);
+               } else {
+                       printk(KERN_WARNING "int_received: bad irq number %d\n",
+                                       irq);
+                       HvCallPci_eoi(event->data.slot.bus_number,
+                                       event->data.slot.sub_bus_number,
+                                       event->data.slot.dev_id);
+               }
                break;
                /* Ignore error recovery events for now */
-       case XmPciLpEvent_BusCreated:
-               printk(KERN_INFO "intReceived: system bus %d created\n",
-                       eventParm->eventData.busCreated.busNumber);
+       case pe_bus_created:
+               printk(KERN_INFO "int_received: system bus %d created\n",
+                       event->data.bus.bus_number);
                break;
-       case XmPciLpEvent_BusError:
-       case XmPciLpEvent_BusFailed:
-               printk(KERN_INFO "intReceived: system bus %d failed\n",
-                       eventParm->eventData.busFailed.busNumber);
+       case pe_bus_error:
+       case pe_bus_failed:
+               printk(KERN_INFO "int_received: system bus %d failed\n",
+                       event->data.bus.bus_number);
                break;
-       case XmPciLpEvent_BusRecovered:
-       case XmPciLpEvent_UnQuiesceBus:
-               printk(KERN_INFO "intReceived: system bus %d recovered\n",
-                       eventParm->eventData.busRecovered.busNumber);
+       case pe_bus_recovered:
+       case pe_unquiese_bus:
+               printk(KERN_INFO "int_received: system bus %d recovered\n",
+                       event->data.bus.bus_number);
                break;
-       case XmPciLpEvent_NodeFailed:
-       case XmPciLpEvent_BridgeError:
+       case pe_node_failed:
+       case pe_bridge_error:
                printk(KERN_INFO
-                       "intReceived: multi-adapter bridge %d/%d/%d failed\n",
-                       eventParm->eventData.nodeFailed.busNumber,
-                       eventParm->eventData.nodeFailed.subBusNumber,
-                       eventParm->eventData.nodeFailed.deviceId);
+                       "int_received: multi-adapter bridge %d/%d/%d failed\n",
+                       event->data.node.bus_number,
+                       event->data.node.sub_bus_number,
+                       event->data.node.dev_id);
                break;
-       case XmPciLpEvent_NodeRecovered:
+       case pe_node_recovered:
                printk(KERN_INFO
-                       "intReceived: multi-adapter bridge %d/%d/%d recovered\n",
-                       eventParm->eventData.nodeRecovered.busNumber,
-                       eventParm->eventData.nodeRecovered.subBusNumber,
-                       eventParm->eventData.nodeRecovered.deviceId);
+                       "int_received: multi-adapter bridge %d/%d/%d recovered\n",
+                       event->data.node.bus_number,
+                       event->data.node.sub_bus_number,
+                       event->data.node.dev_id);
                break;
        default:
                printk(KERN_ERR
-                       "intReceived: unrecognized event subtype 0x%x\n",
-                       eventParm->hvLpEvent.xSubtype);
+                       "int_received: unrecognized event subtype 0x%x\n",
+                       event->event.xSubtype);
                break;
        }
 }
 
-static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
-               struct pt_regs *regsParm)
+static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs)
 {
-#ifdef CONFIG_PCI
-       ++Pci_Event_Count;
-
-       if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) {
-               switch (eventParm->xFlags.xFunction) {
+       if (event && (event->xType == HvLpEvent_Type_PciIo)) {
+               switch (event->xFlags.xFunction) {
                case HvLpEvent_Function_Int:
-                       intReceived((struct XmPciLpEvent *)eventParm, regsParm);
+                       int_received((struct pci_event *)event, regs);
                        break;
                case HvLpEvent_Function_Ack:
                        printk(KERN_ERR
-                               "XmPciLpEvent_handler: unexpected ack received\n");
+                               "pci_event_handler: unexpected ack received\n");
                        break;
                default:
                        printk(KERN_ERR
-                               "XmPciLpEvent_handler: unexpected event function %d\n",
-                               (int)eventParm->xFlags.xFunction);
+                               "pci_event_handler: unexpected event function %d\n",
+                               (int)event->xFlags.xFunction);
                        break;
                }
-       } else if (eventParm)
+       } else if (event)
                printk(KERN_ERR
-                       "XmPciLpEvent_handler: Unrecognized PCI event type 0x%x\n",
-                       (int)eventParm->xType);
+                       "pci_event_handler: Unrecognized PCI event type 0x%x\n",
+                       (int)event->xType);
        else
-               printk(KERN_ERR "XmPciLpEvent_handler: NULL event received\n");
-#endif
+               printk(KERN_ERR "pci_event_handler: NULL event received\n");
 }
 
 /*
@@ -199,20 +176,21 @@ static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
 void __init iSeries_init_IRQ(void)
 {
        /* Register PCI event handler and open an event path */
-       int xRc;
-
-       xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
-                       &XmPciLpEvent_handler);
-       if (xRc == 0) {
-               xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
-               if (xRc != 0)
-                       printk(KERN_ERR "iSeries_init_IRQ: open event path "
-                                       "failed with rc 0x%x\n", xRc);
+       int ret;
+
+       ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
+                       &pci_event_handler);
+       if (ret == 0) {
+               ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
+               if (ret != 0)
+                       printk(KERN_ERR "iseries_init_IRQ: open event path "
+                                       "failed with rc 0x%x\n", ret);
        } else
-               printk(KERN_ERR "iSeries_init_IRQ: register handler "
-                               "failed with rc 0x%x\n", xRc);
+               printk(KERN_ERR "iseries_init_IRQ: register handler "
+                               "failed with rc 0x%x\n", ret);
 }
 
+#define REAL_IRQ_TO_SUBBUS(irq)        (((irq) >> 14) & 0xff)
 #define REAL_IRQ_TO_BUS(irq)   ((((irq) >> 6) & 0xff) + 1)
 #define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1)
 #define REAL_IRQ_TO_FUNC(irq)  ((irq) & 7)
@@ -221,40 +199,40 @@ void __init iSeries_init_IRQ(void)
  * This will be called by device drivers (via enable_IRQ)
  * to enable INTA in the bridge interrupt status register.
  */
-static void iSeries_enable_IRQ(unsigned int irq)
+static void iseries_enable_IRQ(unsigned int irq)
 {
-       u32 bus, deviceId, function, mask;
-       const u32 subBus = 0;
+       u32 bus, dev_id, function, mask;
+       const u32 sub_bus = 0;
        unsigned int rirq = virt_irq_to_real_map[irq];
 
        /* The IRQ has already been locked by the caller */
        bus = REAL_IRQ_TO_BUS(rirq);
        function = REAL_IRQ_TO_FUNC(rirq);
-       deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+       dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
 
        /* Unmask secondary INTA */
        mask = 0x80000000;
-       HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
+       HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask);
 }
 
-/* This is called by iSeries_activate_IRQs */
-static unsigned int iSeries_startup_IRQ(unsigned int irq)
+/* This is called by iseries_activate_IRQs */
+static unsigned int iseries_startup_IRQ(unsigned int irq)
 {
-       u32 bus, deviceId, function, mask;
-       const u32 subBus = 0;
+       u32 bus, dev_id, function, mask;
+       const u32 sub_bus = 0;
        unsigned int rirq = virt_irq_to_real_map[irq];
 
        bus = REAL_IRQ_TO_BUS(rirq);
        function = REAL_IRQ_TO_FUNC(rirq);
-       deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+       dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
 
        /* Link the IRQ number to the bridge */
-       HvCallXm_connectBusUnit(bus, subBus, deviceId, irq);
+       HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq);
 
        /* Unmask bridge interrupts in the FISR */
        mask = 0x01010000 << function;
-       HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
-       iSeries_enable_IRQ(irq);
+       HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
+       iseries_enable_IRQ(irq);
        return 0;
 }
 
@@ -279,78 +257,115 @@ void __init iSeries_activate_IRQs()
 }
 
 /*  this is not called anywhere currently */
-static void iSeries_shutdown_IRQ(unsigned int irq)
+static void iseries_shutdown_IRQ(unsigned int irq)
 {
-       u32 bus, deviceId, function, mask;
-       const u32 subBus = 0;
+       u32 bus, dev_id, function, mask;
+       const u32 sub_bus = 0;
        unsigned int rirq = virt_irq_to_real_map[irq];
 
        /* irq should be locked by the caller */
        bus = REAL_IRQ_TO_BUS(rirq);
        function = REAL_IRQ_TO_FUNC(rirq);
-       deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+       dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
 
        /* Invalidate the IRQ number in the bridge */
-       HvCallXm_connectBusUnit(bus, subBus, deviceId, 0);
+       HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0);
 
        /* Mask bridge interrupts in the FISR */
        mask = 0x01010000 << function;
-       HvCallPci_maskFisr(bus, subBus, deviceId, mask);
+       HvCallPci_maskFisr(bus, sub_bus, dev_id, mask);
 }
 
 /*
  * This will be called by device drivers (via disable_IRQ)
  * to disable INTA in the bridge interrupt status register.
  */
-static void iSeries_disable_IRQ(unsigned int irq)
+static void iseries_disable_IRQ(unsigned int irq)
 {
-       u32 bus, deviceId, function, mask;
-       const u32 subBus = 0;
+       u32 bus, dev_id, function, mask;
+       const u32 sub_bus = 0;
        unsigned int rirq = virt_irq_to_real_map[irq];
 
        /* The IRQ has already been locked by the caller */
        bus = REAL_IRQ_TO_BUS(rirq);
        function = REAL_IRQ_TO_FUNC(rirq);
-       deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+       dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
 
        /* Mask secondary INTA   */
        mask = 0x80000000;
-       HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
+       HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
 }
 
-/*
- * This does nothing because there is not enough information
- * provided to do the EOI HvCall.  This is done by XmPciLpEvent.c
- */
-static void iSeries_end_IRQ(unsigned int irq)
+static void iseries_end_IRQ(unsigned int irq)
 {
+       unsigned int rirq = virt_irq_to_real_map[irq];
+
+       HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
+               (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
 }
 
 static hw_irq_controller iSeries_IRQ_handler = {
        .typename = "iSeries irq controller",
-       .startup = iSeries_startup_IRQ,
-       .shutdown = iSeries_shutdown_IRQ,
-       .enable = iSeries_enable_IRQ,
-       .disable = iSeries_disable_IRQ,
-       .end = iSeries_end_IRQ
+       .startup = iseries_startup_IRQ,
+       .shutdown = iseries_shutdown_IRQ,
+       .enable = iseries_enable_IRQ,
+       .disable = iseries_disable_IRQ,
+       .end = iseries_end_IRQ
 };
 
 /*
  * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
  * It calculates the irq value for the slot.
- * Note that subBusNumber is always 0 (at the moment at least).
+ * Note that sub_bus is always 0 (at the moment at least).
  */
-int __init iSeries_allocate_IRQ(HvBusNumber busNumber,
-               HvSubBusNumber subBusNumber, HvAgentId deviceId)
+int __init iSeries_allocate_IRQ(HvBusNumber bus,
+               HvSubBusNumber sub_bus, HvAgentId dev_id)
 {
        int virtirq;
        unsigned int realirq;
-       u8 idsel = (deviceId >> 4);
-       u8 function = deviceId & 7;
+       u8 idsel = (dev_id >> 4);
+       u8 function = dev_id & 7;
 
-       realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function;
+       realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
+               + function;
        virtirq = virt_irq_create_mapping(realirq);
 
        irq_desc[virtirq].handler = &iSeries_IRQ_handler;
        return virtirq;
 }
+
+/*
+ * Get the next pending IRQ.
+ */
+int iSeries_get_irq(struct pt_regs *regs)
+{
+       struct paca_struct *lpaca;
+       /* -2 means ignore this interrupt */
+       int irq = -2;
+
+       lpaca = get_paca();
+#ifdef CONFIG_SMP
+       if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
+               lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
+               iSeries_smp_message_recv(regs);
+       }
+#endif /* CONFIG_SMP */
+       if (hvlpevent_is_pending())
+               process_hvlpevents(regs);
+
+       if (num_pending_irqs) {
+               spin_lock(&pending_irqs_lock);
+               for (irq = 0; irq < NR_IRQS; irq++) {
+                       if (pending_irqs[irq]) {
+                               pending_irqs[irq]--;
+                               num_pending_irqs--;
+                               break;
+                       }
+               }
+               spin_unlock(&pending_irqs_lock);
+               if (irq >= NR_IRQS)
+                       irq = -2;
+       }
+
+       return irq;
+}
index 5f643f16ecc0eea1a9b6149a9a029863b5f14b61..b9c801ba5a476d103a35d454ffd89c783d901b3c 100644 (file)
@@ -4,5 +4,6 @@
 extern void iSeries_init_IRQ(void);
 extern int  iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
 extern void iSeries_activate_IRQs(void);
+extern int iSeries_get_irq(struct pt_regs *);
 
 #endif /* _ISERIES_IRQ_H */
index bb8c91537f35f7f6df54be8724f3b1044267746d..ea72385aaf0a991791a7d9a8d809e89903fd5bae 100644 (file)
@@ -225,3 +225,10 @@ struct ItVpdAreas itVpdAreas = {
                0,0
        }
 };
+
+struct ItLpRegSave iseries_reg_save[] = {
+       [0 ... (NR_CPUS-1)] = {
+               .xDesc = 0xd397d9e2,    /* "LpRS" */
+               .xSize = sizeof(struct ItLpRegSave),
+       },
+};
index da26639190dbf5807333d184b8ae0a7051d449f1..ad5ef80500ce50d74f9c58b0e97d7a0ff8584782 100644 (file)
@@ -569,16 +569,6 @@ static void iSeries_show_cpuinfo(struct seq_file *m)
        seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");
 }
 
-/*
- * Document me.
- * and Implement me.
- */
-static int iSeries_get_irq(struct pt_regs *regs)
-{
-       /* -2 means ignore this interrupt */
-       return -2;
-}
-
 /*
  * Document me.
  */
index 7ece8983a105d2b87e50155f9a10950fd5483c57..dd73e38bfb7d04f353b88c30a59e238bcdab76c3 100644 (file)
@@ -51,6 +51,7 @@
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/kexec.h>
 #include <asm/pci-bridge.h>
 #include <asm/iommu.h>
 #include <asm/machdep.h>
@@ -191,24 +192,10 @@ static void __init maple_init_early(void)
         */
        hpte_init_native();
 
-       /* Find the serial port */
-       generic_find_legacy_serial_ports(&physport, &default_speed);
-
-       DBG("phys port addr: %lx\n", (long)physport);
-
-       if (physport) {
-               void *comport;
-               /* Map the uart for udbg. */
-               comport = (void *)ioremap(physport, 16);
-               udbg_init_uart(comport, default_speed);
-
-               DBG("Hello World !\n");
-       }
-
        /* Setup interrupt mapping options */
        ppc64_interrupt_controller = IC_OPEN_PIC;
 
-       iommu_init_early_u3();
+       iommu_init_early_dart();
 
        DBG(" <- maple_init_early\n");
 }
@@ -270,7 +257,7 @@ static int __init maple_probe(int platform)
         * occupies having to be broken up so the DART itself is not
         * part of the cacheable linar mapping
         */
-       alloc_u3_dart_table();
+       alloc_dart_table();
 
        return 1;
 }
@@ -292,4 +279,9 @@ struct machdep_calls __initdata maple_md = {
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = maple_progress,
        .idle_loop              = native_idle,
+#ifdef CONFIG_KEXEC
+       .machine_kexec          = default_machine_kexec,
+       .machine_kexec_prepare  = default_machine_kexec_prepare,
+       .machine_crash_shutdown = default_machine_crash_shutdown,
+#endif
 };
index c9df44fcf5710f0ea558b39df6cb945efd090011..78093d7f97af9af6ca4bed23814f8809b4ffb1aa 100644 (file)
@@ -1,9 +1,14 @@
+CFLAGS_bootx_init.o            += -fPIC
+
 obj-y                          += pic.o setup.o time.o feature.o pci.o \
-                                  sleep.o low_i2c.o cache.o
+                                  sleep.o low_i2c.o cache.o pfunc_core.o \
+                                  pfunc_base.o
 obj-$(CONFIG_PMAC_BACKLIGHT)   += backlight.o
 obj-$(CONFIG_CPU_FREQ_PMAC)    += cpufreq_32.o
 obj-$(CONFIG_CPU_FREQ_PMAC64)  += cpufreq_64.o
 obj-$(CONFIG_NVRAM)            += nvram.o
 # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
 obj-$(CONFIG_PPC64)            += nvram.o
+obj-$(CONFIG_PPC32)            += bootx_init.o
 obj-$(CONFIG_SMP)              += smp.o
+obj-$(CONFIG_PPC_MERGE)                += udbg_scc.o udbg_adb.o
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
new file mode 100644 (file)
index 0000000..fa8b4d7
--- /dev/null
@@ -0,0 +1,547 @@
+/*
+ *  Early boot support code for BootX bootloader
+ *
+ *  Copyright (C) 2005 Ben. Herrenschmidt (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/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/bootx.h>
+#include <asm/bootinfo.h>
+#include <asm/btext.h>
+#include <asm/io.h>
+
+#undef DEBUG
+#define SET_BOOT_BAT
+
+#ifdef DEBUG
+#define DBG(fmt...) do { bootx_printf(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
+
+static unsigned long __initdata bootx_dt_strbase;
+static unsigned long __initdata bootx_dt_strend;
+static unsigned long __initdata bootx_node_chosen;
+static boot_infos_t * __initdata bootx_info;
+static char __initdata bootx_disp_path[256];
+
+/* Is boot-info compatible ? */
+#define BOOT_INFO_IS_COMPATIBLE(bi) \
+       ((bi)->compatible_version <= BOOT_INFO_VERSION)
+#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2)
+#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4)
+
+#ifdef CONFIG_BOOTX_TEXT
+static void __init bootx_printf(const char *format, ...)
+{
+       const char *p, *q, *s;
+       va_list args;
+       unsigned long v;
+
+       va_start(args, format);
+       for (p = format; *p != 0; p = q) {
+               for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)
+                       ;
+               if (q > p)
+                       btext_drawtext(p, q - p);
+               if (*q == 0)
+                       break;
+               if (*q == '\n') {
+                       ++q;
+                       btext_flushline();
+                       btext_drawstring("\r\n");
+                       btext_flushline();
+                       continue;
+               }
+               ++q;
+               if (*q == 0)
+                       break;
+               switch (*q) {
+               case 's':
+                       ++q;
+                       s = va_arg(args, const char *);
+                       if (s == NULL)
+                               s = "<NULL>";
+                       btext_drawstring(s);
+                       break;
+               case 'x':
+                       ++q;
+                       v = va_arg(args, unsigned long);
+                       btext_drawhex(v);
+                       break;
+               }
+       }
+}
+#else /* CONFIG_BOOTX_TEXT */
+static void __init bootx_printf(const char *format, ...) {}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static void * __init bootx_early_getprop(unsigned long base,
+                                        unsigned long node,
+                                        char *prop)
+{
+       struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+       u32 *ppp = &np->properties;
+
+       while(*ppp) {
+               struct bootx_dt_prop *pp =
+                       (struct bootx_dt_prop *)(base + *ppp);
+
+               if (strcmp((char *)((unsigned long)pp->name + base),
+                          prop) == 0) {
+                       return (void *)((unsigned long)pp->value + base);
+               }
+               ppp = &pp->next;
+       }
+       return NULL;
+}
+
+#define dt_push_token(token, mem) \
+       do { \
+               *(mem) = _ALIGN_UP(*(mem),4); \
+               *((u32 *)*(mem)) = token; \
+               *(mem) += 4; \
+       } while(0)
+
+static unsigned long __init bootx_dt_find_string(char *str)
+{
+       char *s, *os;
+
+       s = os = (char *)bootx_dt_strbase;
+       s += 4;
+       while (s <  (char *)bootx_dt_strend) {
+               if (strcmp(s, str) == 0)
+                       return s - os;
+               s += strlen(s) + 1;
+       }
+       return 0;
+}
+
+static void __init bootx_dt_add_prop(char *name, void *data, int size,
+                                 unsigned long *mem_end)
+{
+       unsigned long soff = bootx_dt_find_string(name);
+       if (data == NULL)
+               size = 0;
+       if (soff == 0) {
+               bootx_printf("WARNING: Can't find string index for <%s>\n",
+                            name);
+               return;
+       }
+       if (size > 0x20000) {
+               bootx_printf("WARNING: ignoring large property ");
+               bootx_printf("%s length 0x%x\n", name, size);
+               return;
+       }
+       dt_push_token(OF_DT_PROP, mem_end);
+       dt_push_token(size, mem_end);
+       dt_push_token(soff, mem_end);
+
+       /* push property content */
+       if (size && data) {
+               memcpy((void *)*mem_end, data, size);
+               *mem_end = _ALIGN_UP(*mem_end + size, 4);
+       }
+}
+
+static void __init bootx_add_chosen_props(unsigned long base,
+                                         unsigned long *mem_end)
+{
+       u32 val = _MACH_Pmac;
+
+       bootx_dt_add_prop("linux,platform", &val, 4, mem_end);
+
+       if (bootx_info->kernelParamsOffset) {
+               char *args = (char *)((unsigned long)bootx_info) +
+                       bootx_info->kernelParamsOffset;
+               bootx_dt_add_prop("bootargs", args, strlen(args) + 1, mem_end);
+       }
+       if (bootx_info->ramDisk) {
+               val = ((unsigned long)bootx_info) + bootx_info->ramDisk;
+               bootx_dt_add_prop("linux,initrd-start", &val, 4, mem_end);
+               val += bootx_info->ramDiskSize;
+               bootx_dt_add_prop("linux,initrd-end", &val, 4, mem_end);
+       }
+       if (strlen(bootx_disp_path))
+               bootx_dt_add_prop("linux,stdout-path", bootx_disp_path,
+                                 strlen(bootx_disp_path) + 1, mem_end);
+}
+
+static void __init bootx_add_display_props(unsigned long base,
+                                          unsigned long *mem_end)
+{
+       bootx_dt_add_prop("linux,boot-display", NULL, 0, mem_end);
+       bootx_dt_add_prop("linux,opened", NULL, 0, mem_end);
+}
+
+static void __init bootx_dt_add_string(char *s, unsigned long *mem_end)
+{
+       unsigned int l = strlen(s) + 1;
+       memcpy((void *)*mem_end, s, l);
+       bootx_dt_strend = *mem_end = *mem_end + l;
+}
+
+static void __init bootx_scan_dt_build_strings(unsigned long base,
+                                              unsigned long node,
+                                              unsigned long *mem_end)
+{
+       struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+       u32 *cpp, *ppp = &np->properties;
+       unsigned long soff;
+       char *namep;
+
+       /* Keep refs to known nodes */
+       namep = np->full_name ? (char *)(base + np->full_name) : NULL;
+               if (namep == NULL) {
+               bootx_printf("Node without a full name !\n");
+               namep = "";
+       }
+       DBG("* strings: %s\n", namep);
+
+       if (!strcmp(namep, "/chosen")) {
+               DBG(" detected /chosen ! adding properties names !\n");
+               bootx_dt_add_string("linux,platform", mem_end);
+               bootx_dt_add_string("linux,stdout-path", mem_end);
+               bootx_dt_add_string("linux,initrd-start", mem_end);
+               bootx_dt_add_string("linux,initrd-end", mem_end);
+               bootx_dt_add_string("bootargs", mem_end);
+               bootx_node_chosen = node;
+       }
+       if (node == bootx_info->dispDeviceRegEntryOffset) {
+               DBG(" detected display ! adding properties names !\n");
+               bootx_dt_add_string("linux,boot-display", mem_end);
+               bootx_dt_add_string("linux,opened", mem_end);
+               strncpy(bootx_disp_path, namep, 255);
+       }
+
+       /* get and store all property names */
+       while (*ppp) {
+               struct bootx_dt_prop *pp =
+                       (struct bootx_dt_prop *)(base + *ppp);
+
+               namep = pp->name ? (char *)(base + pp->name) : NULL;
+               if (namep == NULL || strcmp(namep, "name") == 0)
+                       goto next;
+               /* get/create string entry */
+               soff = bootx_dt_find_string(namep);
+               if (soff == 0)
+                       bootx_dt_add_string(namep, mem_end);
+       next:
+               ppp = &pp->next;
+       }
+
+       /* do all our children */
+       cpp = &np->child;
+       while(*cpp) {
+               np = (struct bootx_dt_node *)(base + *cpp);
+               bootx_scan_dt_build_strings(base, *cpp, mem_end);
+               cpp = &np->sibling;
+       }
+}
+
+static void __init bootx_scan_dt_build_struct(unsigned long base,
+                                             unsigned long node,
+                                             unsigned long *mem_end)
+{
+       struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+       u32 *cpp, *ppp = &np->properties;
+       char *namep, *p, *ep, *lp;
+       int l;
+
+       dt_push_token(OF_DT_BEGIN_NODE, mem_end);
+
+       /* get the node's full name */
+       namep = np->full_name ? (char *)(base + np->full_name) : NULL;
+       if (namep == NULL)
+               namep = "";
+       l = strlen(namep);
+
+       DBG("* struct: %s\n", namep);
+
+       /* Fixup an Apple bug where they have bogus \0 chars in the
+        * middle of the path in some properties, and extract
+        * the unit name (everything after the last '/').
+        */
+       memcpy((void *)*mem_end, namep, l + 1);
+       namep = (char *)*mem_end;
+       for (lp = p = namep, ep = namep + l; p < ep; p++) {
+               if (*p == '/')
+                       lp = namep;
+               else if (*p != 0)
+                       *lp++ = *p;
+       }
+       *lp = 0;
+       *mem_end = _ALIGN_UP((unsigned long)lp + 1, 4);
+
+       /* get and store all properties */
+       while (*ppp) {
+               struct bootx_dt_prop *pp =
+                       (struct bootx_dt_prop *)(base + *ppp);
+
+               namep = pp->name ? (char *)(base + pp->name) : NULL;
+               /* Skip "name" */
+               if (namep == NULL || !strcmp(namep, "name"))
+                       goto next;
+               /* Skip "bootargs" in /chosen too as we replace it */
+               if (node == bootx_node_chosen && !strcmp(namep, "bootargs"))
+                       goto next;
+
+               /* push property head */
+               bootx_dt_add_prop(namep,
+                                 pp->value ? (void *)(base + pp->value): NULL,
+                                 pp->length, mem_end);
+       next:
+               ppp = &pp->next;
+       }
+
+       if (node == bootx_node_chosen)
+               bootx_add_chosen_props(base, mem_end);
+       if (node == bootx_info->dispDeviceRegEntryOffset)
+               bootx_add_display_props(base, mem_end);
+
+       /* do all our children */
+       cpp = &np->child;
+       while(*cpp) {
+               np = (struct bootx_dt_node *)(base + *cpp);
+               bootx_scan_dt_build_struct(base, *cpp, mem_end);
+               cpp = &np->sibling;
+       }
+
+       dt_push_token(OF_DT_END_NODE, mem_end);
+}
+
+static unsigned long __init bootx_flatten_dt(unsigned long start)
+{
+       boot_infos_t *bi = bootx_info;
+       unsigned long mem_start, mem_end;
+       struct boot_param_header *hdr;
+       unsigned long base;
+       u64 *rsvmap;
+
+       /* Start using memory after the big blob passed by BootX, get
+        * some space for the header
+        */
+       mem_start = mem_end = _ALIGN_UP(((unsigned long)bi) + start, 4);
+       DBG("Boot params header at: %x\n", mem_start);
+       hdr = (struct boot_param_header *)mem_start;
+       mem_end += sizeof(struct boot_param_header);
+       rsvmap = (u64 *)(_ALIGN_UP(mem_end, 8));
+       hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - mem_start;
+       mem_end = ((unsigned long)rsvmap) + 8 * sizeof(u64);
+
+       /* Get base of tree */
+       base = ((unsigned long)bi) + bi->deviceTreeOffset;
+
+       /* Build string array */
+       DBG("Building string array at: %x\n", mem_end);
+       DBG("Device Tree Base=%x\n", base);
+       bootx_dt_strbase = mem_end;
+       mem_end += 4;
+       bootx_dt_strend = mem_end;
+       bootx_scan_dt_build_strings(base, 4, &mem_end);
+       hdr->off_dt_strings = bootx_dt_strbase - mem_start;
+       hdr->dt_strings_size = bootx_dt_strend - bootx_dt_strbase;
+
+       /* Build structure */
+       mem_end = _ALIGN(mem_end, 16);
+       DBG("Building device tree structure at: %x\n", mem_end);
+       hdr->off_dt_struct = mem_end - mem_start;
+       bootx_scan_dt_build_struct(base, 4, &mem_end);
+       dt_push_token(OF_DT_END, &mem_end);
+
+       /* Finish header */
+       hdr->boot_cpuid_phys = 0;
+       hdr->magic = OF_DT_HEADER;
+       hdr->totalsize = mem_end - mem_start;
+       hdr->version = OF_DT_VERSION;
+       /* Version 16 is not backward compatible */
+       hdr->last_comp_version = 0x10;
+
+       /* Reserve the whole thing and copy the reserve map in, we
+        * also bump mem_reserve_cnt to cause further reservations to
+        * fail since it's too late.
+        */
+       mem_end = _ALIGN(mem_end, PAGE_SIZE);
+       DBG("End of boot params: %x\n", mem_end);
+       rsvmap[0] = mem_start;
+       rsvmap[1] = mem_end;
+       rsvmap[2] = 0;
+       rsvmap[3] = 0;
+
+       return (unsigned long)hdr;
+}
+
+
+#ifdef CONFIG_BOOTX_TEXT
+static void __init btext_welcome(boot_infos_t *bi)
+{
+       unsigned long flags;
+       unsigned long pvr;
+
+       bootx_printf("Welcome to Linux, kernel " UTS_RELEASE "\n");
+       bootx_printf("\nlinked at        : 0x%x", KERNELBASE);
+       bootx_printf("\nframe buffer at  : 0x%x", bi->dispDeviceBase);
+       bootx_printf(" (phys), 0x%x", bi->logicalDisplayBase);
+       bootx_printf(" (log)");
+       bootx_printf("\nklimit           : 0x%x",(unsigned long)klimit);
+       bootx_printf("\nboot_info at     : 0x%x", bi);
+       __asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+       bootx_printf("\nMSR              : 0x%x", flags);
+       __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+       bootx_printf("\nPVR              : 0x%x", pvr);
+       pvr >>= 16;
+       if (pvr > 1) {
+           __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+           bootx_printf("\nHID0             : 0x%x", flags);
+       }
+       if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
+           __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+           bootx_printf("\nICTC             : 0x%x", flags);
+       }
+#ifdef DEBUG
+       bootx_printf("\n\n");
+       bootx_printf("bi->deviceTreeOffset   : 0x%x\n",
+                    bi->deviceTreeOffset);
+       bootx_printf("bi->deviceTreeSize     : 0x%x\n",
+                    bi->deviceTreeSize);
+#endif
+       bootx_printf("\n\n");
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+void __init bootx_init(unsigned long r3, unsigned long r4)
+{
+       boot_infos_t *bi = (boot_infos_t *) r4;
+       unsigned long hdr;
+       unsigned long space;
+       unsigned long ptr, x;
+       char *model;
+       unsigned long offset = reloc_offset();
+
+       reloc_got2(offset);
+
+       bootx_info = bi;
+
+       /* We haven't cleared any bss at this point, make sure
+        * what we need is initialized
+        */
+       bootx_dt_strbase = bootx_dt_strend = 0;
+       bootx_node_chosen = 0;
+       bootx_disp_path[0] = 0;
+
+       if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
+               bi->logicalDisplayBase = bi->dispDeviceBase;
+
+#ifdef CONFIG_BOOTX_TEXT
+       btext_setup_display(bi->dispDeviceRect[2] - bi->dispDeviceRect[0],
+                           bi->dispDeviceRect[3] - bi->dispDeviceRect[1],
+                           bi->dispDeviceDepth, bi->dispDeviceRowBytes,
+                           (unsigned long)bi->logicalDisplayBase);
+       btext_clearscreen();
+       btext_flushscreen();
+#endif /* CONFIG_BOOTX_TEXT */
+
+       /*
+        * Test if boot-info is compatible.  Done only in config
+        * CONFIG_BOOTX_TEXT since there is nothing much we can do
+        * with an incompatible version, except display a message
+        * and eventually hang the processor...
+        *
+        * I'll try to keep enough of boot-info compatible in the
+        * future to always allow display of this message;
+        */
+       if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
+               bootx_printf(" !!! WARNING - Incompatible version"
+                            " of BootX !!!\n\n\n");
+               for (;;)
+                       ;
+       }
+       if (bi->architecture != BOOT_ARCH_PCI) {
+               bootx_printf(" !!! WARNING - Usupported machine"
+                            " architecture !\n");
+               for (;;)
+                       ;
+       }
+
+#ifdef CONFIG_BOOTX_TEXT
+       btext_welcome(bi);
+#endif
+       /* New BootX enters kernel with MMU off, i/os are not allowed
+        * here. This hack will have been done by the boostrap anyway.
+        */
+       if (bi->version < 4) {
+               /*
+                * XXX If this is an iMac, turn off the USB controller.
+                */
+               model = (char *) bootx_early_getprop(r4 + bi->deviceTreeOffset,
+                                                    4, "model");
+               if (model
+                   && (strcmp(model, "iMac,1") == 0
+                       || strcmp(model, "PowerMac1,1") == 0)) {
+                       bootx_printf("iMac,1 detected, shutting down USB \n");
+                       out_le32((unsigned *)0x80880008, 1);    /* XXX */
+               }
+       }
+
+       /* Get a pointer that points above the device tree, args, ramdisk,
+        * etc... to use for generating the flattened tree
+        */
+       if (bi->version < 5) {
+               space = bi->deviceTreeOffset + bi->deviceTreeSize;
+               if (bi->ramDisk)
+                       space = bi->ramDisk + bi->ramDiskSize;
+       } else
+               space = bi->totalParamsSize;
+
+       bootx_printf("Total space used by parameters & ramdisk: %x \n", space);
+
+       /* New BootX will have flushed all TLBs and enters kernel with
+        * MMU switched OFF, so this should not be useful anymore.
+        */
+       if (bi->version < 4) {
+               bootx_printf("Touching pages...\n");
+
+               /*
+                * Touch each page to make sure the PTEs for them
+                * are in the hash table - the aim is to try to avoid
+                * getting DSI exceptions while copying the kernel image.
+                */
+               for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
+                    ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
+                       x = *(volatile unsigned long *)ptr;
+       }
+
+       /* Ok, now we need to generate a flattened device-tree to pass
+        * to the kernel
+        */
+       bootx_printf("Preparing boot params...\n");
+
+       hdr = bootx_flatten_dt(space);
+
+#ifdef CONFIG_BOOTX_TEXT
+#ifdef SET_BOOT_BAT
+       bootx_printf("Preparing BAT...\n");
+       btext_prepare_BAT();
+#else
+       btext_unmap();
+#endif
+#endif
+
+       reloc_got2(-offset);
+
+       __start(hdr, KERNELBASE + offset, 0);
+}
index 39150342c6f14bcef65074fb04891ebb275d9462..a4b50c4109c27b4268302942d3ca8da1ec6baeb1 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/cputable.h>
 #include <asm/time.h>
 #include <asm/smu.h>
+#include <asm/pmac_pfunc.h>
 
 #undef DEBUG
 
@@ -85,6 +86,10 @@ static u32 *g5_pmode_data;
 static int g5_pmode_max;
 static int g5_pmode_cur;
 
+static void (*g5_switch_volt)(int speed_mode);
+static int (*g5_switch_freq)(int speed_mode);
+static int (*g5_query_freq)(void);
+
 static DECLARE_MUTEX(g5_switch_mutex);
 
 
@@ -92,9 +97,11 @@ static struct smu_sdbp_fvt *g5_fvt_table;    /* table of op. points */
 static int g5_fvt_count;                       /* number of op. points */
 static int g5_fvt_cur;                         /* current op. point */
 
-/* ----------------- real hardware interface */
+/*
+ * SMU based voltage switching for Neo2 platforms
+ */
 
-static void g5_switch_volt(int speed_mode)
+static void g5_smu_switch_volt(int speed_mode)
 {
        struct smu_simple_cmd   cmd;
 
@@ -105,26 +112,57 @@ static void g5_switch_volt(int speed_mode)
        wait_for_completion(&comp);
 }
 
-static int g5_switch_freq(int speed_mode)
+/*
+ * Platform function based voltage/vdnap switching for Neo2
+ */
+
+static struct pmf_function *pfunc_set_vdnap0;
+static struct pmf_function *pfunc_vdnap0_complete;
+
+static void g5_vdnap_switch_volt(int speed_mode)
 {
-       struct cpufreq_freqs freqs;
-       int to;
+       struct pmf_args args;
+       u32 slew, done = 0;
+       unsigned long timeout;
 
-       if (g5_pmode_cur == speed_mode)
-               return 0;
+       slew = (speed_mode == CPUFREQ_LOW) ? 1 : 0;
+       args.count = 1;
+       args.u[0].p = &slew;
 
-       down(&g5_switch_mutex);
+       pmf_call_one(pfunc_set_vdnap0, &args);
 
-       freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
-       freqs.new = g5_cpu_freqs[speed_mode].frequency;
-       freqs.cpu = 0;
+       /* It's an irq GPIO so we should be able to just block here,
+        * I'll do that later after I've properly tested the IRQ code for
+        * platform functions
+        */
+       timeout = jiffies + HZ/10;
+       while(!time_after(jiffies, timeout)) {
+               args.count = 1;
+               args.u[0].p = &done;
+               pmf_call_one(pfunc_vdnap0_complete, &args);
+               if (done)
+                       break;
+               msleep(1);
+       }
+       if (done == 0)
+               printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
+}
 
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+/*
+ * SCOM based frequency switching for 970FX rev3
+ */
+static int g5_scom_switch_freq(int speed_mode)
+{
+       unsigned long flags;
+       int to;
 
        /* If frequency is going up, first ramp up the voltage */
        if (speed_mode < g5_pmode_cur)
                g5_switch_volt(speed_mode);
 
+       local_irq_save(flags);
+
        /* Clear PCR high */
        scom970_write(SCOM_PCR, 0);
        /* Clear PCR low */
@@ -147,6 +185,8 @@ static int g5_switch_freq(int speed_mode)
                udelay(100);
        }
 
+       local_irq_restore(flags);
+
        /* If frequency is going down, last ramp the voltage */
        if (speed_mode > g5_pmode_cur)
                g5_switch_volt(speed_mode);
@@ -154,14 +194,10 @@ static int g5_switch_freq(int speed_mode)
        g5_pmode_cur = speed_mode;
        ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
 
-       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-       up(&g5_switch_mutex);
-
        return 0;
 }
 
-static int g5_query_freq(void)
+static int g5_scom_query_freq(void)
 {
        unsigned long psr = scom970_read(SCOM_PSR);
        int i;
@@ -173,7 +209,104 @@ static int g5_query_freq(void)
        return i;
 }
 
-/* ----------------- cpufreq bookkeeping */
+/*
+ * Platform function based voltage switching for PowerMac7,2 & 7,3
+ */
+
+static struct pmf_function *pfunc_cpu0_volt_high;
+static struct pmf_function *pfunc_cpu0_volt_low;
+static struct pmf_function *pfunc_cpu1_volt_high;
+static struct pmf_function *pfunc_cpu1_volt_low;
+
+static void g5_pfunc_switch_volt(int speed_mode)
+{
+       if (speed_mode == CPUFREQ_HIGH) {
+               if (pfunc_cpu0_volt_high)
+                       pmf_call_one(pfunc_cpu0_volt_high, NULL);
+               if (pfunc_cpu1_volt_high)
+                       pmf_call_one(pfunc_cpu1_volt_high, NULL);
+       } else {
+               if (pfunc_cpu0_volt_low)
+                       pmf_call_one(pfunc_cpu0_volt_low, NULL);
+               if (pfunc_cpu1_volt_low)
+                       pmf_call_one(pfunc_cpu1_volt_low, NULL);
+       }
+       msleep(10); /* should be faster , to fix */
+}
+
+/*
+ * Platform function based frequency switching for PowerMac7,2 & 7,3
+ */
+
+static struct pmf_function *pfunc_cpu_setfreq_high;
+static struct pmf_function *pfunc_cpu_setfreq_low;
+static struct pmf_function *pfunc_cpu_getfreq;
+static struct pmf_function *pfunc_slewing_done;;
+
+static int g5_pfunc_switch_freq(int speed_mode)
+{
+       struct pmf_args args;
+       u32 done = 0;
+       unsigned long timeout;
+
+       /* If frequency is going up, first ramp up the voltage */
+       if (speed_mode < g5_pmode_cur)
+               g5_switch_volt(speed_mode);
+
+       /* Do it */
+       if (speed_mode == CPUFREQ_HIGH)
+               pmf_call_one(pfunc_cpu_setfreq_high, NULL);
+       else
+               pmf_call_one(pfunc_cpu_setfreq_low, NULL);
+
+       /* It's an irq GPIO so we should be able to just block here,
+        * I'll do that later after I've properly tested the IRQ code for
+        * platform functions
+        */
+       timeout = jiffies + HZ/10;
+       while(!time_after(jiffies, timeout)) {
+               args.count = 1;
+               args.u[0].p = &done;
+               pmf_call_one(pfunc_slewing_done, &args);
+               if (done)
+                       break;
+               msleep(1);
+       }
+       if (done == 0)
+               printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
+
+       /* If frequency is going down, last ramp the voltage */
+       if (speed_mode > g5_pmode_cur)
+               g5_switch_volt(speed_mode);
+
+       g5_pmode_cur = speed_mode;
+       ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
+
+       return 0;
+}
+
+static int g5_pfunc_query_freq(void)
+{
+       struct pmf_args args;
+       u32 val = 0;
+
+       args.count = 1;
+       args.u[0].p = &val;
+       pmf_call_one(pfunc_cpu_getfreq, &args);
+       return val ? CPUFREQ_HIGH : CPUFREQ_LOW;
+}
+
+/*
+ * Fake voltage switching for platforms with missing support
+ */
+
+static void g5_dummy_switch_volt(int speed_mode)
+{
+}
+
+/*
+ * Common interface to the cpufreq core
+ */
 
 static int g5_cpufreq_verify(struct cpufreq_policy *policy)
 {
@@ -183,13 +316,30 @@ static int g5_cpufreq_verify(struct cpufreq_policy *policy)
 static int g5_cpufreq_target(struct cpufreq_policy *policy,
        unsigned int target_freq, unsigned int relation)
 {
-       unsigned int    newstate = 0;
+       unsigned int newstate = 0;
+       struct cpufreq_freqs freqs;
+       int rc;
 
        if (cpufreq_frequency_table_target(policy, g5_cpu_freqs,
                        target_freq, relation, &newstate))
                return -EINVAL;
 
-       return g5_switch_freq(newstate);
+       if (g5_pmode_cur == newstate)
+               return 0;
+
+       down(&g5_switch_mutex);
+
+       freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
+       freqs.new = g5_cpu_freqs[newstate].frequency;
+       freqs.cpu = 0;
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+       rc = g5_switch_freq(newstate);
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       up(&g5_switch_mutex);
+
+       return rc;
 }
 
 static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
@@ -205,6 +355,7 @@ static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
+       policy->cpus = cpu_possible_map;
        cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
 
        return cpufreq_frequency_table_cpuinfo(policy,
@@ -224,19 +375,39 @@ static struct cpufreq_driver g5_cpufreq_driver = {
 };
 
 
-static int __init g5_cpufreq_init(void)
+static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
 {
        struct device_node *cpunode;
        unsigned int psize, ssize;
-       struct smu_sdbp_header *shdr;
        unsigned long max_freq;
-       u32 *valp;
+       char *freq_method, *volt_method;
+       u32 *valp, pvr_hi;
+       int use_volts_vdnap = 0;
+       int use_volts_smu = 0;
        int rc = -ENODEV;
 
-       /* Look for CPU and SMU nodes */
-       cpunode = of_find_node_by_type(NULL, "cpu");
-       if (!cpunode) {
-               DBG("No CPU node !\n");
+       /* Check supported platforms */
+       if (machine_is_compatible("PowerMac8,1") ||
+           machine_is_compatible("PowerMac8,2") ||
+           machine_is_compatible("PowerMac9,1"))
+               use_volts_smu = 1;
+       else if (machine_is_compatible("PowerMac11,2"))
+               use_volts_vdnap = 1;
+       else
+               return -ENODEV;
+
+       /* Get first CPU node */
+       for (cpunode = NULL;
+            (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
+               u32 *reg =
+                       (u32 *)get_property(cpunode, "reg", NULL);
+               if (reg == NULL || (*reg) != 0)
+                       continue;
+               if (!strcmp(cpunode->type, "cpu"))
+                       break;
+       }
+       if (cpunode == NULL) {
+               printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
                return -ENODEV;
        }
 
@@ -246,8 +417,9 @@ static int __init g5_cpufreq_init(void)
                DBG("No cpu-version property !\n");
                goto bail_noprops;
        }
-       if (((*valp) >> 16) != 0x3c) {
-               DBG("Wrong CPU version: %08x\n", *valp);
+       pvr_hi = (*valp) >> 16;
+       if (pvr_hi != 0x3c && pvr_hi != 0x44) {
+               printk(KERN_ERR "cpufreq: Unsupported CPU version\n");
                goto bail_noprops;
        }
 
@@ -259,18 +431,50 @@ static int __init g5_cpufreq_init(void)
        }
        g5_pmode_max = psize / sizeof(u32) - 1;
 
-       /* Look for the FVT table */
-       shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
-       if (!shdr)
-               goto bail_noprops;
-       g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
-       ssize = (shdr->len * sizeof(u32)) - sizeof(struct smu_sdbp_header);
-       g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
-       g5_fvt_cur = 0;
-
-       /* Sanity checking */
-       if (g5_fvt_count < 1 || g5_pmode_max < 1)
-               goto bail_noprops;
+       if (use_volts_smu) {
+               struct smu_sdbp_header *shdr;
+
+               /* Look for the FVT table */
+               shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+               if (!shdr)
+                       goto bail_noprops;
+               g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
+               ssize = (shdr->len * sizeof(u32)) -
+                       sizeof(struct smu_sdbp_header);
+               g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
+               g5_fvt_cur = 0;
+
+               /* Sanity checking */
+               if (g5_fvt_count < 1 || g5_pmode_max < 1)
+                       goto bail_noprops;
+
+               g5_switch_volt = g5_smu_switch_volt;
+               volt_method = "SMU";
+       } else if (use_volts_vdnap) {
+               struct device_node *root;
+
+               root = of_find_node_by_path("/");
+               if (root == NULL) {
+                       printk(KERN_ERR "cpufreq: Can't find root of "
+                              "device tree\n");
+                       goto bail_noprops;
+               }
+               pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0");
+               pfunc_vdnap0_complete =
+                       pmf_find_function(root, "slewing-done");
+               if (pfunc_set_vdnap0 == NULL ||
+                   pfunc_vdnap0_complete == NULL) {
+                       printk(KERN_ERR "cpufreq: Can't find required "
+                              "platform function\n");
+                       goto bail_noprops;
+               }
+
+               g5_switch_volt = g5_vdnap_switch_volt;
+               volt_method = "GPIO";
+       } else {
+               g5_switch_volt = g5_dummy_switch_volt;
+               volt_method = "none";
+       }
 
        /*
         * From what I see, clock-frequency is always the maximal frequency.
@@ -286,19 +490,23 @@ static int __init g5_cpufreq_init(void)
        g5_cpu_freqs[0].frequency = max_freq;
        g5_cpu_freqs[1].frequency = max_freq/2;
 
-       /* Check current frequency */
-       g5_pmode_cur = g5_query_freq();
-       if (g5_pmode_cur > 1)
-               /* We don't support anything but 1:1 and 1:2, fixup ... */
-               g5_pmode_cur = 1;
+       /* Set callbacks */
+       g5_switch_freq = g5_scom_switch_freq;
+       g5_query_freq = g5_scom_query_freq;
+       freq_method = "SCOM";
 
        /* Force apply current frequency to make sure everything is in
         * sync (voltage is right for example). Firmware may leave us with
         * a strange setting ...
         */
-       g5_switch_freq(g5_pmode_cur);
+       g5_switch_volt(CPUFREQ_HIGH);
+       msleep(10);
+       g5_pmode_cur = -1;
+       g5_switch_freq(g5_query_freq());
 
        printk(KERN_INFO "Registering G5 CPU frequency driver\n");
+       printk(KERN_INFO "Frequency method: %s, Voltage method: %s\n",
+              freq_method, volt_method);
        printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
                g5_cpu_freqs[1].frequency/1000,
                g5_cpu_freqs[0].frequency/1000,
@@ -317,6 +525,200 @@ static int __init g5_cpufreq_init(void)
        return rc;
 }
 
+static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
+{
+       struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
+       u8 *eeprom = NULL;
+       u32 *valp;
+       u64 max_freq, min_freq, ih, il;
+       int has_volt = 1, rc = 0;
+
+       /* Get first CPU node */
+       for (cpunode = NULL;
+            (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
+               if (!strcmp(cpunode->type, "cpu"))
+                       break;
+       }
+       if (cpunode == NULL) {
+               printk(KERN_ERR "cpufreq: Can't find any CPU node\n");
+               return -ENODEV;
+       }
+
+       /* Lookup the cpuid eeprom node */
+        cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
+       if (cpuid != NULL)
+               eeprom = (u8 *)get_property(cpuid, "cpuid", NULL);
+       if (eeprom == NULL) {
+               printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
+               rc = -ENODEV;
+               goto bail;
+       }
+
+       /* Lookup the i2c hwclock */
+       for (hwclock = NULL;
+            (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
+               char *loc = get_property(hwclock, "hwctrl-location", NULL);
+               if (loc == NULL)
+                       continue;
+               if (strcmp(loc, "CPU CLOCK"))
+                       continue;
+               if (!get_property(hwclock, "platform-get-frequency", NULL))
+                       continue;
+               break;
+       }
+       if (hwclock == NULL) {
+               printk(KERN_ERR "cpufreq: Can't find i2c clock chip !\n");
+               rc = -ENODEV;
+               goto bail;
+       }
+
+       DBG("cpufreq: i2c clock chip found: %s\n", hwclock->full_name);
+
+       /* Now get all the platform functions */
+       pfunc_cpu_getfreq =
+               pmf_find_function(hwclock, "get-frequency");
+       pfunc_cpu_setfreq_high =
+               pmf_find_function(hwclock, "set-frequency-high");
+       pfunc_cpu_setfreq_low =
+               pmf_find_function(hwclock, "set-frequency-low");
+       pfunc_slewing_done =
+               pmf_find_function(hwclock, "slewing-done");
+       pfunc_cpu0_volt_high =
+               pmf_find_function(hwclock, "set-voltage-high-0");
+       pfunc_cpu0_volt_low =
+               pmf_find_function(hwclock, "set-voltage-low-0");
+       pfunc_cpu1_volt_high =
+               pmf_find_function(hwclock, "set-voltage-high-1");
+       pfunc_cpu1_volt_low =
+               pmf_find_function(hwclock, "set-voltage-low-1");
+
+       /* Check we have minimum requirements */
+       if (pfunc_cpu_getfreq == NULL || pfunc_cpu_setfreq_high == NULL ||
+           pfunc_cpu_setfreq_low == NULL || pfunc_slewing_done == NULL) {
+               printk(KERN_ERR "cpufreq: Can't find platform functions !\n");
+               rc = -ENODEV;
+               goto bail;
+       }
+
+       /* Check that we have complete sets */
+       if (pfunc_cpu0_volt_high == NULL || pfunc_cpu0_volt_low == NULL) {
+               pmf_put_function(pfunc_cpu0_volt_high);
+               pmf_put_function(pfunc_cpu0_volt_low);
+               pfunc_cpu0_volt_high = pfunc_cpu0_volt_low = NULL;
+               has_volt = 0;
+       }
+       if (!has_volt ||
+           pfunc_cpu1_volt_high == NULL || pfunc_cpu1_volt_low == NULL) {
+               pmf_put_function(pfunc_cpu1_volt_high);
+               pmf_put_function(pfunc_cpu1_volt_low);
+               pfunc_cpu1_volt_high = pfunc_cpu1_volt_low = NULL;
+       }
+
+       /* Note: The device tree also contains a "platform-set-values"
+        * function for which I haven't quite figured out the usage. It
+        * might have to be called on init and/or wakeup, I'm not too sure
+        * but things seem to work fine without it so far ...
+        */
+
+       /* Get max frequency from device-tree */
+       valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
+       if (!valp) {
+               printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
+               rc = -ENODEV;
+               goto bail;
+       }
+
+       max_freq = (*valp)/1000;
+
+       /* Now calculate reduced frequency by using the cpuid input freq
+        * ratio. This requires 64 bits math unless we are willing to lose
+        * some precision
+        */
+       ih = *((u32 *)(eeprom + 0x10));
+       il = *((u32 *)(eeprom + 0x20));
+       min_freq = 0;
+       if (ih != 0 && il != 0)
+               min_freq = (max_freq * il) / ih;
+
+       /* Sanity check */
+       if (min_freq >= max_freq || min_freq < 1000) {
+               printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n");
+               rc = -ENODEV;
+               goto bail;
+       }
+       g5_cpu_freqs[0].frequency = max_freq;
+       g5_cpu_freqs[1].frequency = min_freq;
+
+       /* Set callbacks */
+       g5_switch_volt = g5_pfunc_switch_volt;
+       g5_switch_freq = g5_pfunc_switch_freq;
+       g5_query_freq = g5_pfunc_query_freq;
+
+       /* Force apply current frequency to make sure everything is in
+        * sync (voltage is right for example). Firmware may leave us with
+        * a strange setting ...
+        */
+       g5_switch_volt(CPUFREQ_HIGH);
+       msleep(10);
+       g5_pmode_cur = -1;
+       g5_switch_freq(g5_query_freq());
+
+       printk(KERN_INFO "Registering G5 CPU frequency driver\n");
+       printk(KERN_INFO "Frequency method: i2c/pfunc, "
+              "Voltage method: %s\n", has_volt ? "i2c/pfunc" : "none");
+       printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
+               g5_cpu_freqs[1].frequency/1000,
+               g5_cpu_freqs[0].frequency/1000,
+               g5_cpu_freqs[g5_pmode_cur].frequency/1000);
+
+       rc = cpufreq_register_driver(&g5_cpufreq_driver);
+ bail:
+       if (rc != 0) {
+               pmf_put_function(pfunc_cpu_getfreq);
+               pmf_put_function(pfunc_cpu_setfreq_high);
+               pmf_put_function(pfunc_cpu_setfreq_low);
+               pmf_put_function(pfunc_slewing_done);
+               pmf_put_function(pfunc_cpu0_volt_high);
+               pmf_put_function(pfunc_cpu0_volt_low);
+               pmf_put_function(pfunc_cpu1_volt_high);
+               pmf_put_function(pfunc_cpu1_volt_low);
+       }
+       of_node_put(hwclock);
+       of_node_put(cpuid);
+       of_node_put(cpunode);
+
+       return rc;
+}
+
+static int __init g5_rm31_cpufreq_init(struct device_node *cpus)
+{
+       /* NYI */
+       return 0;
+}
+
+static int __init g5_cpufreq_init(void)
+{
+       struct device_node *cpus;
+       int rc;
+
+       cpus = of_find_node_by_path("/cpus");
+       if (cpus == NULL) {
+               DBG("No /cpus node !\n");
+               return -ENODEV;
+       }
+
+       if (machine_is_compatible("PowerMac7,2") ||
+           machine_is_compatible("PowerMac7,3"))
+               rc = g5_pm72_cpufreq_init(cpus);
+       else if (machine_is_compatible("RackMac3,1"))
+               rc = g5_rm31_cpufreq_init(cpus);
+       else
+               rc = g5_neo2_cpufreq_init(cpus);
+
+       of_node_put(cpus);
+       return rc;
+}
+
 module_init(g5_cpufreq_init);
 
 
index f6e22da2a5daa8dd27a2bcade5b12ff19599b60f..558dd06920921f04bde22e4084d0347ba73c8209 100644 (file)
@@ -58,12 +58,11 @@ extern int powersave_lowspeed;
 extern int powersave_nap;
 extern struct device_node *k2_skiplist[2];
 
-
 /*
  * We use a single global lock to protect accesses. Each driver has
  * to take care of its own locking
  */
-static DEFINE_SPINLOCK(feature_lock);
+DEFINE_SPINLOCK(feature_lock);
 
 #define LOCK(flags)    spin_lock_irqsave(&feature_lock, flags);
 #define UNLOCK(flags)  spin_unlock_irqrestore(&feature_lock, flags);
@@ -101,26 +100,17 @@ static const char *macio_names[] =
        "Keylargo",
        "Pangea",
        "Intrepid",
-       "K2"
+       "K2",
+       "Shasta",
 };
 
 
+struct device_node *uninorth_node;
+u32 __iomem *uninorth_base;
 
-/*
- * Uninorth reg. access. Note that Uni-N regs are big endian
- */
-
-#define UN_REG(r)      (uninorth_base + ((r) >> 2))
-#define UN_IN(r)       (in_be32(UN_REG(r)))
-#define UN_OUT(r,v)    (out_be32(UN_REG(r), (v)))
-#define UN_BIS(r,v)    (UN_OUT((r), UN_IN(r) | (v)))
-#define UN_BIC(r,v)    (UN_OUT((r), UN_IN(r) & ~(v)))
-
-static struct device_node *uninorth_node;
-static u32 __iomem *uninorth_base;
 static u32 uninorth_rev;
-static int uninorth_u3;
-static void __iomem *u3_ht;
+static int uninorth_maj;
+static void __iomem *u3_ht_base;
 
 /*
  * For each motherboard family, we have a table of functions pointers
@@ -1399,8 +1389,15 @@ static long g5_fw_enable(struct device_node *node, long param, long value)
 static long g5_mpic_enable(struct device_node *node, long param, long value)
 {
        unsigned long flags;
+       struct device_node *parent = of_get_parent(node);
+       int is_u3;
 
-       if (node->parent == NULL || strcmp(node->parent->name, "u3"))
+       if (parent == NULL)
+               return 0;
+       is_u3 = strcmp(parent->name, "u3") == 0 ||
+               strcmp(parent->name, "u4") == 0;
+       of_node_put(parent);
+       if (!is_u3)
                return 0;
 
        LOCK(flags);
@@ -1445,20 +1442,53 @@ static long g5_i2s_enable(struct device_node *node, long param, long value)
        /* Very crude implementation for now */
        struct macio_chip *macio = &macio_chips[0];
        unsigned long flags;
-
-       if (value == 0)
-               return 0; /* don't disable yet */
+       int cell;
+       u32 fcrs[3][3] = {
+               { 0,
+                 K2_FCR1_I2S0_CELL_ENABLE |
+                 K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE,
+                 KL3_I2S0_CLK18_ENABLE
+               },
+               { KL0_SCC_A_INTF_ENABLE,
+                 K2_FCR1_I2S1_CELL_ENABLE |
+                 K2_FCR1_I2S1_CLK_ENABLE_BIT | K2_FCR1_I2S1_ENABLE,
+                 KL3_I2S1_CLK18_ENABLE
+               },
+               { KL0_SCC_B_INTF_ENABLE,
+                 SH_FCR1_I2S2_CELL_ENABLE |
+                 SH_FCR1_I2S2_CLK_ENABLE_BIT | SH_FCR1_I2S2_ENABLE,
+                 SH_FCR3_I2S2_CLK18_ENABLE
+               },
+       };
+
+       if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
+               return -ENODEV;
+       if (strncmp(node->name, "i2s-", 4))
+               return -ENODEV;
+       cell = node->name[4] - 'a';
+       switch(cell) {
+       case 0:
+       case 1:
+               break;
+       case 2:
+               if (macio->type == macio_shasta)
+                       break;
+       default:
+               return -ENODEV;
+       }
 
        LOCK(flags);
-       MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE |
-                 KL3_I2S0_CLK18_ENABLE);
-       udelay(10);
-       MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE |
-                 K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE);
+       if (value) {
+               MACIO_BIC(KEYLARGO_FCR0, fcrs[cell][0]);
+               MACIO_BIS(KEYLARGO_FCR1, fcrs[cell][1]);
+               MACIO_BIS(KEYLARGO_FCR3, fcrs[cell][2]);
+       } else {
+               MACIO_BIC(KEYLARGO_FCR3, fcrs[cell][2]);
+               MACIO_BIC(KEYLARGO_FCR1, fcrs[cell][1]);
+               MACIO_BIS(KEYLARGO_FCR0, fcrs[cell][0]);
+       }
        udelay(10);
-       MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET);
        UNLOCK(flags);
-       udelay(10);
 
        return 0;
 }
@@ -1473,7 +1503,7 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
        struct device_node *np;
 
        macio = &macio_chips[0];
-       if (macio->type != macio_keylargo2)
+       if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
                return -ENODEV;
 
        np = find_path_device("/cpus");
@@ -1512,14 +1542,17 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
  */
 void g5_phy_disable_cpu1(void)
 {
-       UN_OUT(U3_API_PHY_CONFIG_1, 0);
+       if (uninorth_maj == 3)
+               UN_OUT(U3_API_PHY_CONFIG_1, 0);
 }
 #endif /* CONFIG_POWER4 */
 
 #ifndef CONFIG_POWER4
 
-static void
-keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
+
+#ifdef CONFIG_PM
+
+static void keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
 {
        u32 temp;
 
@@ -1572,8 +1605,7 @@ keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
        (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
 }
 
-static void
-pangea_shutdown(struct macio_chip *macio, int sleep_mode)
+static void pangea_shutdown(struct macio_chip *macio, int sleep_mode)
 {
        u32 temp;
 
@@ -1606,8 +1638,7 @@ pangea_shutdown(struct macio_chip *macio, int sleep_mode)
        (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
 }
 
-static void
-intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
+static void intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
 {
        u32 temp;
 
@@ -1635,124 +1666,6 @@ intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
 }
 
 
-void pmac_tweak_clock_spreading(int enable)
-{
-       struct macio_chip *macio = &macio_chips[0];
-
-       /* Hack for doing clock spreading on some machines PowerBooks and
-        * iBooks. This implements the "platform-do-clockspreading" OF
-        * property as decoded manually on various models. For safety, we also
-        * check the product ID in the device-tree in cases we'll whack the i2c
-        * chip to make reasonably sure we won't set wrong values in there
-        *
-        * Of course, ultimately, we have to implement a real parser for
-        * the platform-do-* stuff...
-        */
-
-       if (macio->type == macio_intrepid) {
-               struct device_node *clock =
-                       of_find_node_by_path("/uni-n@f8000000/hw-clock");
-               if (clock && get_property(clock, "platform-do-clockspreading",
-                                         NULL)) {
-                       printk(KERN_INFO "%sabling clock spreading on Intrepid"
-                              " ASIC\n", enable ? "En" : "Dis");
-                       if (enable)
-                               UN_OUT(UNI_N_CLOCK_SPREADING, 2);
-                       else
-                               UN_OUT(UNI_N_CLOCK_SPREADING, 0);
-                       mdelay(40);
-               }
-               of_node_put(clock);
-       }
-
-       while (machine_is_compatible("PowerBook5,2") ||
-              machine_is_compatible("PowerBook5,3") ||
-              machine_is_compatible("PowerBook6,2") ||
-              machine_is_compatible("PowerBook6,3")) {
-               struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
-               struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
-               u8 buffer[9];
-               u32 *productID;
-               int i, rc, changed = 0;
-
-               if (dt == NULL)
-                       break;
-               productID = (u32 *)get_property(dt, "pid#", NULL);
-               if (productID == NULL)
-                       break;
-               while(ui2c) {
-                       struct device_node *p = of_get_parent(ui2c);
-                       if (p && !strcmp(p->name, "uni-n"))
-                               break;
-                       ui2c = of_find_node_by_type(ui2c, "i2c");
-               }
-               if (ui2c == NULL)
-                       break;
-               DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
-               rc = pmac_low_i2c_open(ui2c, 1);
-               if (rc != 0)
-                       break;
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-               DBG("read result: %d,", rc);
-               if (rc != 0) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               for (i=0; i<9; i++)
-                       DBG(" %02x", buffer[i]);
-               DBG("\n");
-
-               switch(*productID) {
-               case 0x1182:    /* AlBook 12" rev 2 */
-               case 0x1183:    /* iBook G4 12" */
-                       buffer[0] = (buffer[0] & 0x8f) | 0x70;
-                       buffer[2] = (buffer[2] & 0x7f) | 0x00;
-                       buffer[5] = (buffer[5] & 0x80) | 0x31;
-                       buffer[6] = (buffer[6] & 0x40) | 0xb0;
-                       buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
-                       buffer[8] = (buffer[8] & 0x00) | 0x30;
-                       changed = 1;
-                       break;
-               case 0x3142:    /* AlBook 15" (ATI M10) */
-               case 0x3143:    /* AlBook 17" (ATI M10) */
-                       buffer[0] = (buffer[0] & 0xaf) | 0x50;
-                       buffer[2] = (buffer[2] & 0x7f) | 0x00;
-                       buffer[5] = (buffer[5] & 0x80) | 0x31;
-                       buffer[6] = (buffer[6] & 0x40) | 0xb0;
-                       buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
-                       buffer[8] = (buffer[8] & 0x00) | 0x30;
-                       changed = 1;
-                       break;
-               default:
-                       DBG("i2c-hwclock: Machine model not handled\n");
-                       break;
-               }
-               if (!changed) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               printk(KERN_INFO "%sabling clock spreading on i2c clock chip\n",
-                      enable ? "En" : "Dis");
-
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
-               DBG("write result: %d,", rc);
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-               DBG("read result: %d,", rc);
-               if (rc != 0) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               for (i=0; i<9; i++)
-                       DBG(" %02x", buffer[i]);
-               pmac_low_i2c_close(ui2c);
-               break;
-       }
-}
-
-
 static int
 core99_sleep(void)
 {
@@ -1909,6 +1822,8 @@ core99_wake_up(void)
        return 0;
 }
 
+#endif /* CONFIG_PM */
+
 static long
 core99_sleep_state(struct device_node *node, long param, long value)
 {
@@ -1930,10 +1845,13 @@ core99_sleep_state(struct device_node *node, long param, long value)
        if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
                return -EPERM;
 
+#ifdef CONFIG_PM
        if (value == 1)
                return core99_sleep();
        else if (value == 0)
                return core99_wake_up();
+
+#endif /* CONFIG_PM */
        return 0;
 }
 
@@ -2057,7 +1975,9 @@ static struct feature_table_entry core99_features[] = {
        { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
        { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
        { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
+#ifdef CONFIG_PM
        { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
+#endif
 #ifdef CONFIG_SMP
        { PMAC_FTR_RESET_CPU,           core99_reset_cpu },
 #endif /* CONFIG_SMP */
@@ -2427,6 +2347,14 @@ static struct pmac_mb_def pmac_mb_defs[] = {
                PMAC_TYPE_POWERMAC_G5_U3L,      g5_features,
                0,
        },
+       {       "PowerMac11,2",                 "PowerMac G5 Dual Core",
+               PMAC_TYPE_POWERMAC_G5_U3L,      g5_features,
+               0,
+       },
+       {       "PowerMac12,1",                 "iMac G5 (iSight)",
+               PMAC_TYPE_POWERMAC_G5_U3L,      g5_features,
+               0,
+       },
        {       "RackMac3,1",                   "XServe G5",
                PMAC_TYPE_XSERVE_G5,            g5_features,
                0,
@@ -2539,6 +2467,11 @@ static int __init probe_motherboard(void)
                pmac_mb.model_name = "Unknown K2-based";
                pmac_mb.features = g5_features;
                break;
+       case macio_shasta:
+               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_SHASTA;
+               pmac_mb.model_name = "Unknown Shasta-based";
+               pmac_mb.features = g5_features;
+               break;
 #endif /* CONFIG_POWER4 */
        default:
                return -ENODEV;
@@ -2607,6 +2540,8 @@ found:
  */
 static void __init probe_uninorth(void)
 {
+       u32 *addrp;
+       phys_addr_t address;
        unsigned long actrl;
 
        /* Locate core99 Uni-N */
@@ -2614,22 +2549,31 @@ static void __init probe_uninorth(void)
        /* Locate G5 u3 */
        if (uninorth_node == NULL) {
                uninorth_node = of_find_node_by_name(NULL, "u3");
-               uninorth_u3 = 1;
-       }
-       if (uninorth_node && uninorth_node->n_addrs > 0) {
-               unsigned long address = uninorth_node->addrs[0].address;
-               uninorth_base = ioremap(address, 0x40000);
-               uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
-               if (uninorth_u3)
-                       u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
-       } else
-               uninorth_node = NULL;
-
-       if (!uninorth_node)
+               uninorth_maj = 3;
+       }
+       /* Locate G5 u4 */
+       if (uninorth_node == NULL) {
+               uninorth_node = of_find_node_by_name(NULL, "u4");
+               uninorth_maj = 4;
+       }
+       if (uninorth_node == NULL)
                return;
 
-       printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
-              uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
+       addrp = (u32 *)get_property(uninorth_node, "reg", NULL);
+       if (addrp == NULL)
+               return;
+       address = of_translate_address(uninorth_node, addrp);
+       if (address == 0)
+               return;
+       uninorth_base = ioremap(address, 0x40000);
+       uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+       if (uninorth_maj == 3 || uninorth_maj == 4)
+               u3_ht_base = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
+
+       printk(KERN_INFO "Found %s memory controller & host bridge"
+              " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" :
+              uninorth_maj == 4 ? "U4" : "UniNorth",
+              (unsigned int)address, uninorth_rev);
        printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
 
        /* Set the arbitrer QAck delay according to what Apple does
@@ -2637,7 +2581,8 @@ static void __init probe_uninorth(void)
        if (uninorth_rev < 0x11) {
                actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
                actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
-                       UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+                       UNI_N_ARB_CTRL_QACK_DELAY) <<
+                       UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
                UN_OUT(UNI_N_ARB_CTRL, actrl);
        }
 
@@ -2645,7 +2590,8 @@ static void __init probe_uninorth(void)
         * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
         * memory timeout
         */
-       if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
+       if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) ||
+           uninorth_rev == 0xc0)
                UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
 }
 
@@ -2653,18 +2599,17 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
 {
        struct device_node*     node;
        int                     i;
-       volatile u32 __iomem *  base;
-       u32*                    revp;
+       volatile u32 __iomem    *base;
+       u32                     *addrp, *revp;
+       phys_addr_t             addr;
+       u64                     size;
 
-       node = find_devices(name);
-       if (!node || !node->n_addrs)
-               return;
-       if (compat)
-               do {
-                       if (device_is_compatible(node, compat))
-                               break;
-                       node = node->next;
-               } while (node);
+       for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {
+               if (!compat)
+                       break;
+               if (device_is_compatible(node, compat))
+                       break;
+       }
        if (!node)
                return;
        for(i=0; i<MAX_MACIO_CHIPS; i++) {
@@ -2673,22 +2618,38 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
                if (macio_chips[i].of_node == node)
                        return;
        }
+
        if (i >= MAX_MACIO_CHIPS) {
                printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
                printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
                return;
        }
-       base = ioremap(node->addrs[0].address, node->addrs[0].size);
+       addrp = of_get_pci_address(node, 0, &size, NULL);
+       if (addrp == NULL) {
+               printk(KERN_ERR "pmac_feature: %s: can't find base !\n",
+                      node->full_name);
+               return;
+       }
+       addr = of_translate_address(node, addrp);
+       if (addr == 0) {
+               printk(KERN_ERR "pmac_feature: %s, can't translate base !\n",
+                      node->full_name);
+               return;
+       }
+       base = ioremap(addr, (unsigned long)size);
        if (!base) {
-               printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
+               printk(KERN_ERR "pmac_feature: %s, can't map mac-io chip !\n",
+                      node->full_name);
                return;
        }
-       if (type == macio_keylargo) {
+       if (type == macio_keylargo || type == macio_keylargo2) {
                u32 *did = (u32 *)get_property(node, "device-id", NULL);
                if (*did == 0x00000025)
                        type = macio_pangea;
                if (*did == 0x0000003e)
                        type = macio_intrepid;
+               if (*did == 0x0000004f)
+                       type = macio_shasta;
        }
        macio_chips[i].of_node  = node;
        macio_chips[i].type     = type;
@@ -2787,7 +2748,8 @@ set_initial_features(void)
        }
 
 #ifdef CONFIG_POWER4
-       if (macio_chips[0].type == macio_keylargo2) {
+       if (macio_chips[0].type == macio_keylargo2 ||
+           macio_chips[0].type == macio_shasta) {
 #ifndef CONFIG_SMP
                /* On SMP machines running UP, we have the second CPU eating
                 * bus cycles. We need to take it off the bus. This is done
@@ -2896,12 +2858,6 @@ set_initial_features(void)
                MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
        }
 
-       /* Some machine models need the clock chip to be properly setup for
-        * clock spreading now. This should be a platform function but we
-        * don't do these at the moment
-        */
-       pmac_tweak_clock_spreading(1);
-
 #endif /* CONFIG_POWER4 */
 
        /* On all machines, switch modem & serial ports off */
@@ -2929,9 +2885,6 @@ pmac_feature_init(void)
                return;
        }
 
-       /* Setup low-level i2c stuffs */
-       pmac_init_low_i2c();
-
        /* Probe machine type */
        if (probe_motherboard())
                printk(KERN_WARNING "Unknown PowerMac !\n");
@@ -2942,26 +2895,6 @@ pmac_feature_init(void)
        set_initial_features();
 }
 
-int __init pmac_feature_late_init(void)
-{
-#if 0
-       struct device_node *np;
-
-       /* Request some resources late */
-       if (uninorth_node)
-               request_OF_resource(uninorth_node, 0, NULL);
-       np = find_devices("hammerhead");
-       if (np)
-               request_OF_resource(np, 0, NULL);
-       np = find_devices("interrupt-controller");
-       if (np)
-               request_OF_resource(np, 0, NULL);
-#endif
-       return 0;
-}
-
-device_initcall(pmac_feature_late_init);
-
 #if 0
 static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
 {
@@ -2984,9 +2917,9 @@ void __init pmac_check_ht_link(void)
        u8      px_bus, px_devfn;
        struct pci_controller *px_hose;
 
-       (void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
-       ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
-       ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
+       (void)in_be32(u3_ht_base + U3_HT_LINK_COMMAND);
+       ucfg = cfg = in_be32(u3_ht_base + U3_HT_LINK_CONFIG);
+       ufreq = freq = in_be32(u3_ht_base + U3_HT_LINK_FREQ);
        dump_HT_speeds("U3 HyperTransport", cfg, freq);
 
        pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
index f3f39e8e337a632eda28e2103fef2042ae7901db..535c802b369fbe945dd8de334e86a910aaffb1f4 100644 (file)
@@ -1,22 +1,34 @@
 /*
- *  arch/ppc/platforms/pmac_low_i2c.c
+ * arch/powerpc/platforms/powermac/low_i2c.c
  *
- *  Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *  Copyright (C) 2003-2005 Ben. Herrenschmidt (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.
  *
- *  This file contains some low-level i2c access routines that
- *  need to be used by various bits of the PowerMac platform code
- *  at times where the real asynchronous & interrupt driven driver
- *  cannot be used. The API borrows some semantics from the darwin
- *  driver in order to ease the implementation of the platform
- *  properties parser
+ * The linux i2c layer isn't completely suitable for our needs for various
+ * reasons ranging from too late initialisation to semantics not perfectly
+ * matching some requirements of the apple platform functions etc...
+ *
+ * This file thus provides a simple low level unified i2c interface for
+ * powermac that covers the various types of i2c busses used in Apple machines.
+ * For now, keywest, PMU and SMU, though we could add Cuda, or other bit
+ * banging busses found on older chipstes in earlier machines if we ever need
+ * one of them.
+ *
+ * The drivers in this file are synchronous/blocking. In addition, the
+ * keywest one is fairly slow due to the use of msleep instead of interrupts
+ * as the interrupt is currently used by i2c-keywest. In the long run, we
+ * might want to get rid of those high-level interfaces to linux i2c layer
+ * either completely (converting all drivers) or replacing them all with a
+ * single stub driver on top of this one. Once done, the interrupt will be
+ * available for our use.
  */
 
 #undef DEBUG
+#undef DEBUG_LOW
 
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/timer.h>
 #include <asm/keylargo.h>
 #include <asm/uninorth.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
+#include <asm/smu.h>
+#include <asm/pmac_pfunc.h>
 #include <asm/pmac_low_i2c.h>
 
-#define MAX_LOW_I2C_HOST       4
-
 #ifdef DEBUG
 #define DBG(x...) do {\
-               printk(KERN_DEBUG "KW:" x);     \
+               printk(KERN_DEBUG "low_i2c:" x);        \
        } while(0)
 #else
 #define DBG(x...)
 #endif
 
-struct low_i2c_host;
-
-typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
+#ifdef DEBUG_LOW
+#define DBG_LOW(x...) do {\
+               printk(KERN_DEBUG "low_i2c:" x);        \
+       } while(0)
+#else
+#define DBG_LOW(x...)
+#endif
 
-struct low_i2c_host
-{
-       struct device_node      *np;            /* OF device node */
-       struct semaphore        mutex;          /* Access mutex for use by i2c-keywest */
-       low_i2c_func_t          func;           /* Access function */
-       unsigned int            is_open : 1;    /* Poor man's access control */
-       int                     mode;           /* Current mode */
-       int                     channel;        /* Current channel */
-       int                     num_channels;   /* Number of channels */
-       void __iomem            *base;          /* For keywest-i2c, base address */
-       int                     bsteps;         /* And register stepping */
-       int                     speed;          /* And speed */
-};
 
-static struct low_i2c_host     low_i2c_hosts[MAX_LOW_I2C_HOST];
+static int pmac_i2c_force_poll = 1;
 
-/* No locking is necessary on allocation, we are running way before
- * anything can race with us
+/*
+ * A bus structure. Each bus in the system has such a structure associated.
  */
-static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
+struct pmac_i2c_bus
 {
-       int i;
+       struct list_head        link;
+       struct device_node      *controller;
+       struct device_node      *busnode;
+       int                     type;
+       int                     flags;
+       struct i2c_adapter      *adapter;
+       void                    *hostdata;
+       int                     channel;        /* some hosts have multiple */
+       int                     mode;           /* current mode */
+       struct semaphore        sem;
+       int                     opened;
+       int                     polled;         /* open mode */
+       struct platform_device  *platform_dev;
+
+       /* ops */
+       int (*open)(struct pmac_i2c_bus *bus);
+       void (*close)(struct pmac_i2c_bus *bus);
+       int (*xfer)(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+                   u32 subaddr, u8 *data, int len);
+};
 
-       for (i = 0; i < MAX_LOW_I2C_HOST; i++)
-               if (low_i2c_hosts[i].np == np)
-                       return &low_i2c_hosts[i];
-       return NULL;
-}
+static LIST_HEAD(pmac_i2c_busses);
 
 /*
- *
- * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
- *
+ * Keywest implementation
  */
 
-/*
- * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
- * should be moved somewhere in include/asm-ppc/
- */
+struct pmac_i2c_host_kw
+{
+       struct semaphore        mutex;          /* Access mutex for use by
+                                                * i2c-keywest */
+       void __iomem            *base;          /* register base address */
+       int                     bsteps;         /* register stepping */
+       int                     speed;          /* speed */
+       int                     irq;
+       u8                      *data;
+       unsigned                len;
+       int                     state;
+       int                     rw;
+       int                     polled;
+       int                     result;
+       struct completion       complete;
+       spinlock_t              lock;
+       struct timer_list       timeout_timer;
+};
+
 /* Register indices */
 typedef enum {
        reg_mode = 0,
@@ -97,6 +134,8 @@ typedef enum {
        reg_data
 } reg_t;
 
+/* The Tumbler audio equalizer can be really slow sometimes */
+#define KW_POLL_TIMEOUT                (2*HZ)
 
 /* Mode register */
 #define KW_I2C_MODE_100KHZ     0x00
@@ -140,8 +179,9 @@ enum {
 };
 
 #define WRONG_STATE(name) do {\
-               printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
-                      name, __kw_state_names[state], isr); \
+               printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s " \
+                      "(isr: %02x)\n", \
+                      name, __kw_state_names[host->state], isr); \
        } while(0)
 
 static const char *__kw_state_names[] = {
@@ -153,120 +193,137 @@ static const char *__kw_state_names[] = {
        "state_dead"
 };
 
-static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
+static inline u8 __kw_read_reg(struct pmac_i2c_host_kw *host, reg_t reg)
 {
        return readb(host->base + (((unsigned int)reg) << host->bsteps));
 }
 
-static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
+static inline void __kw_write_reg(struct pmac_i2c_host_kw *host,
+                                 reg_t reg, u8 val)
 {
        writeb(val, host->base + (((unsigned)reg) << host->bsteps));
        (void)__kw_read_reg(host, reg_subaddr);
 }
 
-#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) 
-#define kw_read_reg(reg)       __kw_read_reg(host, reg) 
-
+#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val)
+#define kw_read_reg(reg)       __kw_read_reg(host, reg)
 
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8 kw_wait_interrupt(struct low_i2c_host* host)
+static u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host)
 {
        int i, j;
        u8 isr;
        
-       for (i = 0; i < 100000; i++) {
+       for (i = 0; i < 1000; i++) {
                isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
                if (isr != 0)
                        return isr;
 
                /* This code is used with the timebase frozen, we cannot rely
-                * on udelay ! For now, just use a bogus loop
+                * on udelay nor schedule when in polled mode !
+                * For now, just use a bogus loop....
                 */
-               for (j = 1; j < 10000; j++)
-                       mb();
+               if (host->polled) {
+                       for (j = 1; j < 100000; j++)
+                               mb();
+               } else
+                       msleep(1);
        }
        return isr;
 }
 
-static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
+static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
 {
        u8 ack;
 
-       DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr);
+       DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n",
+               __kw_state_names[host->state], isr);
+
+       if (host->state == state_idle) {
+               printk(KERN_WARNING "low_i2c: Keywest got an out of state"
+                      " interrupt, ignoring\n");
+               kw_write_reg(reg_isr, isr);
+               return;
+       }
 
        if (isr == 0) {
-               if (state != state_stop) {
-                       DBG("KW: Timeout !\n");
-                       *rc = -EIO;
+               if (host->state != state_stop) {
+                       DBG_LOW("KW: Timeout !\n");
+                       host->result = -EIO;
                        goto stop;
                }
-               if (state == state_stop) {
+               if (host->state == state_stop) {
                        ack = kw_read_reg(reg_status);
-                       if (!(ack & KW_I2C_STAT_BUSY)) {
-                               state = state_idle;
-                               kw_write_reg(reg_ier, 0x00);
-                       }
+                       if (ack & KW_I2C_STAT_BUSY)
+                               kw_write_reg(reg_status, 0);
+                       host->state = state_idle;
+                       kw_write_reg(reg_ier, 0x00);
+                       if (!host->polled)
+                               complete(&host->complete);
                }
-               return state;
+               return;
        }
 
        if (isr & KW_I2C_IRQ_ADDR) {
                ack = kw_read_reg(reg_status);
-               if (state != state_addr) {
+               if (host->state != state_addr) {
                        kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
                        WRONG_STATE("KW_I2C_IRQ_ADDR"); 
-                       *rc = -EIO;
+                       host->result = -EIO;
                        goto stop;
                }
-               if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {                        
-                       *rc = -ENODEV;
-                       DBG("KW: NAK on address\n");
-                       return state_stop;                   
+               if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+                       host->result = -ENODEV;
+                       DBG_LOW("KW: NAK on address\n");
+                       host->state = state_stop;
+                       return;
                } else {
-                       if (rw) {
-                               state = state_read;
-                               if (*len > 1)
-                                       kw_write_reg(reg_control, KW_I2C_CTL_AAK);
+                       if (host->len == 0) {
+                               kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+                               goto stop;
+                       }
+                       if (host->rw) {
+                               host->state = state_read;
+                               if (host->len > 1)
+                                       kw_write_reg(reg_control,
+                                                    KW_I2C_CTL_AAK);
                        } else {
-                               state = state_write;
-                               kw_write_reg(reg_data, **data);
-                               (*data)++; (*len)--;
+                               host->state = state_write;
+                               kw_write_reg(reg_data, *(host->data++));
+                               host->len--;
                        }
                }
                kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
        }
 
        if (isr & KW_I2C_IRQ_DATA) {
-               if (state == state_read) {
-                       **data = kw_read_reg(reg_data);
-                       (*data)++; (*len)--;
+               if (host->state == state_read) {
+                       *(host->data++) = kw_read_reg(reg_data);
+                       host->len--;
                        kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
-                       if ((*len) == 0)
-                               state = state_stop;
-                       else if ((*len) == 1)
+                       if (host->len == 0)
+                               host->state = state_stop;
+                       else if (host->len == 1)
                                kw_write_reg(reg_control, 0);
-               } else if (state == state_write) {
+               } else if (host->state == state_write) {
                        ack = kw_read_reg(reg_status);
                        if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-                               DBG("KW: nack on data write\n");
-                               *rc = -EIO;
+                               DBG_LOW("KW: nack on data write\n");
+                               host->result = -EIO;
                                goto stop;
-                       } else if (*len) {
-                               kw_write_reg(reg_data, **data);
-                               (*data)++; (*len)--;
+                       } else if (host->len) {
+                               kw_write_reg(reg_data, *(host->data++));
+                               host->len--;
                        } else {
                                kw_write_reg(reg_control, KW_I2C_CTL_STOP);
-                               state = state_stop;
-                               *rc = 0;
+                               host->state = state_stop;
+                               host->result = 0;
                        }
                        kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
                } else {
                        kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
                        WRONG_STATE("KW_I2C_IRQ_DATA"); 
-                       if (state != state_stop) {
-                               *rc = -EIO;
+                       if (host->state != state_stop) {
+                               host->result = -EIO;
                                goto stop;
                        }
                }
@@ -274,98 +331,194 @@ static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int
 
        if (isr & KW_I2C_IRQ_STOP) {
                kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
-               if (state != state_stop) {
+               if (host->state != state_stop) {
                        WRONG_STATE("KW_I2C_IRQ_STOP");
-                       *rc = -EIO;
+                       host->result = -EIO;
                }
-               return state_idle;
+               host->state = state_idle;
+               if (!host->polled)
+                       complete(&host->complete);
        }
 
        if (isr & KW_I2C_IRQ_START)
                kw_write_reg(reg_isr, KW_I2C_IRQ_START);
 
-       return state;
-
+       return;
  stop:
        kw_write_reg(reg_control, KW_I2C_CTL_STOP);     
-       return state_stop;
+       host->state = state_stop;
+       return;
 }
 
-static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
+/* Interrupt handler */
+static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
+       struct pmac_i2c_host_kw *host = dev_id;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       del_timer(&host->timeout_timer);
+       kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
+       if (host->state != state_idle) {
+               host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+               add_timer(&host->timeout_timer);
+       }
+       spin_unlock_irqrestore(&host->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static void kw_i2c_timeout(unsigned long data)
+{
+       struct pmac_i2c_host_kw *host = (struct pmac_i2c_host_kw *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
+       if (host->state != state_idle) {
+               host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+               add_timer(&host->timeout_timer);
+       }
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int kw_i2c_open(struct pmac_i2c_bus *bus)
+{
+       struct pmac_i2c_host_kw *host = bus->hostdata;
+       down(&host->mutex);
+       return 0;
+}
+
+static void kw_i2c_close(struct pmac_i2c_bus *bus)
+{
+       struct pmac_i2c_host_kw *host = bus->hostdata;
+       up(&host->mutex);
+}
+
+static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+                      u32 subaddr, u8 *data, int len)
+{
+       struct pmac_i2c_host_kw *host = bus->hostdata;
        u8 mode_reg = host->speed;
-       int state = state_addr;
-       int rc = 0;
+       int use_irq = host->irq != NO_IRQ && !bus->polled;
 
        /* Setup mode & subaddress if any */
-       switch(host->mode) {
-       case pmac_low_i2c_mode_dumb:
-               printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
+       switch(bus->mode) {
+       case pmac_i2c_mode_dumb:
                return -EINVAL;
-       case pmac_low_i2c_mode_std:
+       case pmac_i2c_mode_std:
                mode_reg |= KW_I2C_MODE_STANDARD;
+               if (subsize != 0)
+                       return -EINVAL;
                break;
-       case pmac_low_i2c_mode_stdsub:
+       case pmac_i2c_mode_stdsub:
                mode_reg |= KW_I2C_MODE_STANDARDSUB;
+               if (subsize != 1)
+                       return -EINVAL;
                break;
-       case pmac_low_i2c_mode_combined:
+       case pmac_i2c_mode_combined:
                mode_reg |= KW_I2C_MODE_COMBINED;
+               if (subsize != 1)
+                       return -EINVAL;
                break;
        }
 
        /* Setup channel & clear pending irqs */
        kw_write_reg(reg_isr, kw_read_reg(reg_isr));
-       kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
+       kw_write_reg(reg_mode, mode_reg | (bus->channel << 4));
        kw_write_reg(reg_status, 0);
 
-       /* Set up address and r/w bit */
-       kw_write_reg(reg_addr, addr);
+       /* Set up address and r/w bit, strip possible stale bus number from
+        * address top bits
+        */
+       kw_write_reg(reg_addr, addrdir & 0xff);
 
        /* Set up the sub address */
        if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
            || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
                kw_write_reg(reg_subaddr, subaddr);
 
-       /* Start sending address & disable interrupt*/
-       kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
+       /* Prepare for async operations */
+       host->data = data;
+       host->len = len;
+       host->state = state_addr;
+       host->result = 0;
+       host->rw = (addrdir & 1);
+       host->polled = bus->polled;
+
+       /* Enable interrupt if not using polled mode and interrupt is
+        * available
+        */
+       if (use_irq) {
+               /* Clear completion */
+               INIT_COMPLETION(host->complete);
+               /* Ack stale interrupts */
+               kw_write_reg(reg_isr, kw_read_reg(reg_isr));
+               /* Arm timeout */
+               host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+               add_timer(&host->timeout_timer);
+               /* Enable emission */
+               kw_write_reg(reg_ier, KW_I2C_IRQ_MASK);
+       }
+
+       /* Start sending address */
        kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
 
-       /* State machine, to turn into an interrupt handler */
-       while(state != state_idle) {
-               u8 isr = kw_wait_interrupt(host);
-               state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
+       /* Wait for completion */
+       if (use_irq)
+               wait_for_completion(&host->complete);
+       else {
+               while(host->state != state_idle) {
+                       unsigned long flags;
+
+                       u8 isr = kw_i2c_wait_interrupt(host);
+                       spin_lock_irqsave(&host->lock, flags);
+                       kw_i2c_handle_interrupt(host, isr);
+                       spin_unlock_irqrestore(&host->lock, flags);
+               }
        }
 
-       return rc;
+       /* Disable emission */
+       kw_write_reg(reg_ier, 0);
+
+       return host->result;
 }
 
-static void keywest_low_i2c_add(struct device_node *np)
+static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
 {
-       struct low_i2c_host     *host = find_low_i2c_host(NULL);
-       u32                     *psteps, *prate, steps, aoffset = 0;
-       struct device_node      *parent;
+       struct pmac_i2c_host_kw *host;
+       u32                     *psteps, *prate, *addrp, steps;
 
+       host = kzalloc(sizeof(struct pmac_i2c_host_kw), GFP_KERNEL);
        if (host == NULL) {
                printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
                       np->full_name);
-               return;
+               return NULL;
        }
-       memset(host, 0, sizeof(*host));
 
+       /* Apple is kind enough to provide a valid AAPL,address property
+        * on all i2c keywest nodes so far ... we would have to fallback
+        * to macio parsing if that wasn't the case
+        */
+       addrp = (u32 *)get_property(np, "AAPL,address", NULL);
+       if (addrp == NULL) {
+               printk(KERN_ERR "low_i2c: Can't find address for %s\n",
+                      np->full_name);
+               kfree(host);
+               return NULL;
+       }
        init_MUTEX(&host->mutex);
-       host->np = of_node_get(np);     
+       init_completion(&host->complete);
+       spin_lock_init(&host->lock);
+       init_timer(&host->timeout_timer);
+       host->timeout_timer.function = kw_i2c_timeout;
+       host->timeout_timer.data = (unsigned long)host;
+
        psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
        steps = psteps ? (*psteps) : 0x10;
        for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
                steps >>= 1;
-       parent = of_get_parent(np);
-       host->num_channels = 1;
-       if (parent && parent->name[0] == 'u') {
-               host->num_channels = 2;
-               aoffset = 3;
-       }
        /* Select interface rate */
-       host->speed = KW_I2C_MODE_100KHZ;
+       host->speed = KW_I2C_MODE_25KHZ;
        prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
        if (prate) switch(*prate) {
        case 100:
@@ -378,146 +531,981 @@ static void keywest_low_i2c_add(struct device_node *np)
                host->speed = KW_I2C_MODE_25KHZ;
                break;
        }       
+       if (np->n_intrs > 0)
+               host->irq = np->intrs[0].line;
+       else
+               host->irq = NO_IRQ;
+
+       host->base = ioremap((*addrp), 0x1000);
+       if (host->base == NULL) {
+               printk(KERN_ERR "low_i2c: Can't map registers for %s\n",
+                      np->full_name);
+               kfree(host);
+               return NULL;
+       }
+
+       /* Make sure IRA is disabled */
+       kw_write_reg(reg_ier, 0);
+
+       /* Request chip interrupt */
+       if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host))
+               host->irq = NO_IRQ;
+
+       printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
+              *addrp, host->irq, np->full_name);
 
-       host->mode = pmac_low_i2c_mode_std;
-       host->base = ioremap(np->addrs[0].address + aoffset,
-                                               np->addrs[0].size);
-       host->func = keywest_low_i2c_func;
+       return host;
 }
 
+
+static void __init kw_i2c_add(struct pmac_i2c_host_kw *host,
+                             struct device_node *controller,
+                             struct device_node *busnode,
+                             int channel)
+{
+       struct pmac_i2c_bus *bus;
+
+       bus = kzalloc(sizeof(struct pmac_i2c_bus), GFP_KERNEL);
+       if (bus == NULL)
+               return;
+
+       bus->controller = of_node_get(controller);
+       bus->busnode = of_node_get(busnode);
+       bus->type = pmac_i2c_bus_keywest;
+       bus->hostdata = host;
+       bus->channel = channel;
+       bus->mode = pmac_i2c_mode_std;
+       bus->open = kw_i2c_open;
+       bus->close = kw_i2c_close;
+       bus->xfer = kw_i2c_xfer;
+       init_MUTEX(&bus->sem);
+       if (controller == busnode)
+               bus->flags = pmac_i2c_multibus;
+       list_add(&bus->link, &pmac_i2c_busses);
+
+       printk(KERN_INFO " channel %d bus %s\n", channel,
+              (controller == busnode) ? "<multibus>" : busnode->full_name);
+}
+
+static void __init kw_i2c_probe(void)
+{
+       struct device_node *np, *child, *parent;
+
+       /* Probe keywest-i2c busses */
+       for (np = NULL;
+            (np = of_find_compatible_node(np, "i2c","keywest-i2c")) != NULL;){
+               struct pmac_i2c_host_kw *host;
+               int multibus, chans, i;
+
+               /* Found one, init a host structure */
+               host = kw_i2c_host_init(np);
+               if (host == NULL)
+                       continue;
+
+               /* Now check if we have a multibus setup (old style) or if we
+                * have proper bus nodes. Note that the "new" way (proper bus
+                * nodes) might cause us to not create some busses that are
+                * kept hidden in the device-tree. In the future, we might
+                * want to work around that by creating busses without a node
+                * but not for now
+                */
+               child = of_get_next_child(np, NULL);
+               multibus = !child || strcmp(child->name, "i2c-bus");
+               of_node_put(child);
+
+               /* For a multibus setup, we get the bus count based on the
+                * parent type
+                */
+               if (multibus) {
+                       parent = of_get_parent(np);
+                       if (parent == NULL)
+                               continue;
+                       chans = parent->name[0] == 'u' ? 2 : 1;
+                       for (i = 0; i < chans; i++)
+                               kw_i2c_add(host, np, np, i);
+               } else {
+                       for (child = NULL;
+                            (child = of_get_next_child(np, child)) != NULL;) {
+                               u32 *reg =
+                                       (u32 *)get_property(child, "reg", NULL);
+                               if (reg == NULL)
+                                       continue;
+                               kw_i2c_add(host, np, child, *reg);
+                       }
+               }
+       }
+}
+
+
 /*
  *
  * PMU implementation
  *
  */
 
-
 #ifdef CONFIG_ADB_PMU
 
-static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
+/*
+ * i2c command block to the PMU
+ */
+struct pmu_i2c_hdr {
+       u8      bus;
+       u8      mode;
+       u8      bus2;
+       u8      address;
+       u8      sub_addr;
+       u8      comb_addr;
+       u8      count;
+       u8      data[];
+};
+
+static void pmu_i2c_complete(struct adb_request *req)
 {
-       // TODO
-       return -ENODEV;
+       complete(req->arg);
 }
 
-static void pmu_low_i2c_add(struct device_node *np)
+static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+                       u32 subaddr, u8 *data, int len)
 {
-       struct low_i2c_host     *host = find_low_i2c_host(NULL);
+       struct adb_request *req = bus->hostdata;
+       struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req->data[1];
+       struct completion comp;
+       int read = addrdir & 1;
+       int retry;
+       int rc = 0;
 
-       if (host == NULL) {
-               printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
-                      np->full_name);
-               return;
+       /* For now, limit ourselves to 16 bytes transfers */
+       if (len > 16)
+               return -EINVAL;
+
+       init_completion(&comp);
+
+       for (retry = 0; retry < 16; retry++) {
+               memset(req, 0, sizeof(struct adb_request));
+               hdr->bus = bus->channel;
+               hdr->count = len;
+
+               switch(bus->mode) {
+               case pmac_i2c_mode_std:
+                       if (subsize != 0)
+                               return -EINVAL;
+                       hdr->address = addrdir;
+                       hdr->mode = PMU_I2C_MODE_SIMPLE;
+                       break;
+               case pmac_i2c_mode_stdsub:
+               case pmac_i2c_mode_combined:
+                       if (subsize != 1)
+                               return -EINVAL;
+                       hdr->address = addrdir & 0xfe;
+                       hdr->comb_addr = addrdir;
+                       hdr->sub_addr = subaddr;
+                       if (bus->mode == pmac_i2c_mode_stdsub)
+                               hdr->mode = PMU_I2C_MODE_STDSUB;
+                       else
+                               hdr->mode = PMU_I2C_MODE_COMBINED;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               INIT_COMPLETION(comp);
+               req->data[0] = PMU_I2C_CMD;
+               req->reply[0] = 0xff;
+               req->nbytes = sizeof(struct pmu_i2c_hdr) + 1;
+               req->done = pmu_i2c_complete;
+               req->arg = &comp;
+               if (!read && len) {
+                       memcpy(hdr->data, data, len);
+                       req->nbytes += len;
+               }
+               rc = pmu_queue_request(req);
+               if (rc)
+                       return rc;
+               wait_for_completion(&comp);
+               if (req->reply[0] == PMU_I2C_STATUS_OK)
+                       break;
+               msleep(15);
        }
-       memset(host, 0, sizeof(*host));
+       if (req->reply[0] != PMU_I2C_STATUS_OK)
+               return -EIO;
 
-       init_MUTEX(&host->mutex);
-       host->np = of_node_get(np);     
-       host->num_channels = 3;
-       host->mode = pmac_low_i2c_mode_std;
-       host->func = pmu_low_i2c_func;
+       for (retry = 0; retry < 16; retry++) {
+               memset(req, 0, sizeof(struct adb_request));
+
+               /* I know that looks like a lot, slow as hell, but darwin
+                * does it so let's be on the safe side for now
+                */
+               msleep(15);
+
+               hdr->bus = PMU_I2C_BUS_STATUS;
+
+               INIT_COMPLETION(comp);
+               req->data[0] = PMU_I2C_CMD;
+               req->reply[0] = 0xff;
+               req->nbytes = 2;
+               req->done = pmu_i2c_complete;
+               req->arg = &comp;
+               rc = pmu_queue_request(req);
+               if (rc)
+                       return rc;
+               wait_for_completion(&comp);
+
+               if (req->reply[0] == PMU_I2C_STATUS_OK && !read)
+                       return 0;
+               if (req->reply[0] == PMU_I2C_STATUS_DATAREAD && read) {
+                       int rlen = req->reply_len - 1;
+
+                       if (rlen != len) {
+                               printk(KERN_WARNING "low_i2c: PMU returned %d"
+                                      " bytes, expected %d !\n", rlen, len);
+                               return -EIO;
+                       }
+                       if (len)
+                               memcpy(data, &req->reply[1], len);
+                       return 0;
+               }
+       }
+       return -EIO;
+}
+
+static void __init pmu_i2c_probe(void)
+{
+       struct pmac_i2c_bus *bus;
+       struct device_node *busnode;
+       int channel, sz;
+
+       if (!pmu_present())
+               return;
+
+       /* There might or might not be a "pmu-i2c" node, we use that
+        * or via-pmu itself, whatever we find. I haven't seen a machine
+        * with separate bus nodes, so we assume a multibus setup
+        */
+       busnode = of_find_node_by_name(NULL, "pmu-i2c");
+       if (busnode == NULL)
+               busnode = of_find_node_by_name(NULL, "via-pmu");
+       if (busnode == NULL)
+               return;
+
+       printk(KERN_INFO "PMU i2c %s\n", busnode->full_name);
+
+       /*
+        * We add bus 1 and 2 only for now, bus 0 is "special"
+        */
+       for (channel = 1; channel <= 2; channel++) {
+               sz = sizeof(struct pmac_i2c_bus) + sizeof(struct adb_request);
+               bus = kzalloc(sz, GFP_KERNEL);
+               if (bus == NULL)
+                       return;
+
+               bus->controller = busnode;
+               bus->busnode = busnode;
+               bus->type = pmac_i2c_bus_pmu;
+               bus->channel = channel;
+               bus->mode = pmac_i2c_mode_std;
+               bus->hostdata = bus + 1;
+               bus->xfer = pmu_i2c_xfer;
+               init_MUTEX(&bus->sem);
+               bus->flags = pmac_i2c_multibus;
+               list_add(&bus->link, &pmac_i2c_busses);
+
+               printk(KERN_INFO " channel %d bus <multibus>\n", channel);
+       }
 }
 
 #endif /* CONFIG_ADB_PMU */
 
-void __init pmac_init_low_i2c(void)
+
+/*
+ *
+ * SMU implementation
+ *
+ */
+
+#ifdef CONFIG_PMAC_SMU
+
+static void smu_i2c_complete(struct smu_i2c_cmd *cmd, void *misc)
 {
-       struct device_node *np;
+       complete(misc);
+}
 
-       /* Probe keywest-i2c busses */
-       np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
-       while(np) {
-               keywest_low_i2c_add(np);
-               np = of_find_compatible_node(np, "i2c", "keywest-i2c");
+static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+                       u32 subaddr, u8 *data, int len)
+{
+       struct smu_i2c_cmd *cmd = bus->hostdata;
+       struct completion comp;
+       int read = addrdir & 1;
+       int rc = 0;
+
+       if ((read && len > SMU_I2C_READ_MAX) ||
+           ((!read) && len > SMU_I2C_WRITE_MAX))
+               return -EINVAL;
+
+       memset(cmd, 0, sizeof(struct smu_i2c_cmd));
+       cmd->info.bus = bus->channel;
+       cmd->info.devaddr = addrdir;
+       cmd->info.datalen = len;
+
+       switch(bus->mode) {
+       case pmac_i2c_mode_std:
+               if (subsize != 0)
+                       return -EINVAL;
+               cmd->info.type = SMU_I2C_TRANSFER_SIMPLE;
+               break;
+       case pmac_i2c_mode_stdsub:
+       case pmac_i2c_mode_combined:
+               if (subsize > 3 || subsize < 1)
+                       return -EINVAL;
+               cmd->info.sublen = subsize;
+               /* that's big-endian only but heh ! */
+               memcpy(&cmd->info.subaddr, ((char *)&subaddr) + (4 - subsize),
+                      subsize);
+               if (bus->mode == pmac_i2c_mode_stdsub)
+                       cmd->info.type = SMU_I2C_TRANSFER_STDSUB;
+               else
+                       cmd->info.type = SMU_I2C_TRANSFER_COMBINED;
+               break;
+       default:
+               return -EINVAL;
        }
+       if (!read && len)
+               memcpy(cmd->info.data, data, len);
+
+       init_completion(&comp);
+       cmd->done = smu_i2c_complete;
+       cmd->misc = &comp;
+       rc = smu_queue_i2c(cmd);
+       if (rc < 0)
+               return rc;
+       wait_for_completion(&comp);
+       rc = cmd->status;
+
+       if (read && len)
+               memcpy(data, cmd->info.data, len);
+       return rc < 0 ? rc : 0;
+}
+
+static void __init smu_i2c_probe(void)
+{
+       struct device_node *controller, *busnode;
+       struct pmac_i2c_bus *bus;
+       u32 *reg;
+       int sz;
+
+       if (!smu_present())
+               return;
+
+       controller = of_find_node_by_name(NULL, "smu-i2c-control");
+       if (controller == NULL)
+               controller = of_find_node_by_name(NULL, "smu");
+       if (controller == NULL)
+               return;
+
+       printk(KERN_INFO "SMU i2c %s\n", controller->full_name);
+
+       /* Look for childs, note that they might not be of the right
+        * type as older device trees mix i2c busses and other thigns
+        * at the same level
+        */
+       for (busnode = NULL;
+            (busnode = of_get_next_child(controller, busnode)) != NULL;) {
+               if (strcmp(busnode->type, "i2c") &&
+                   strcmp(busnode->type, "i2c-bus"))
+                       continue;
+               reg = (u32 *)get_property(busnode, "reg", NULL);
+               if (reg == NULL)
+                       continue;
+
+               sz = sizeof(struct pmac_i2c_bus) + sizeof(struct smu_i2c_cmd);
+               bus = kzalloc(sz, GFP_KERNEL);
+               if (bus == NULL)
+                       return;
+
+               bus->controller = controller;
+               bus->busnode = of_node_get(busnode);
+               bus->type = pmac_i2c_bus_smu;
+               bus->channel = *reg;
+               bus->mode = pmac_i2c_mode_std;
+               bus->hostdata = bus + 1;
+               bus->xfer = smu_i2c_xfer;
+               init_MUTEX(&bus->sem);
+               bus->flags = 0;
+               list_add(&bus->link, &pmac_i2c_busses);
+
+               printk(KERN_INFO " channel %x bus %s\n",
+                      bus->channel, busnode->full_name);
+       }
+}
+
+#endif /* CONFIG_PMAC_SMU */
+
+/*
+ *
+ * Core code
+ *
+ */
 
-#ifdef CONFIG_ADB_PMU
-       /* Probe PMU busses */
-       np = of_find_node_by_name(NULL, "via-pmu");
-       if (np)
-               pmu_low_i2c_add(np);
-#endif /* CONFIG_ADB_PMU */
 
-       /* TODO: Add CUDA support as well */
+struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node)
+{
+       struct device_node *p = of_node_get(node);
+       struct device_node *prev = NULL;
+       struct pmac_i2c_bus *bus;
+
+       while(p) {
+               list_for_each_entry(bus, &pmac_i2c_busses, link) {
+                       if (p == bus->busnode) {
+                               if (prev && bus->flags & pmac_i2c_multibus) {
+                                       u32 *reg;
+                                       reg = (u32 *)get_property(prev, "reg",
+                                                                 NULL);
+                                       if (!reg)
+                                               continue;
+                                       if (((*reg) >> 8) != bus->channel)
+                                               continue;
+                               }
+                               of_node_put(p);
+                               of_node_put(prev);
+                               return bus;
+                       }
+               }
+               of_node_put(prev);
+               prev = p;
+               p = of_get_parent(p);
+       }
+       return NULL;
 }
+EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
+
+u8 pmac_i2c_get_dev_addr(struct device_node *device)
+{
+       u32 *reg = (u32 *)get_property(device, "reg", NULL);
+
+       if (reg == NULL)
+               return 0;
+
+       return (*reg) & 0xff;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_dev_addr);
+
+struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus)
+{
+       return bus->controller;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_controller);
+
+struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus)
+{
+       return bus->busnode;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_bus_node);
+
+int pmac_i2c_get_type(struct pmac_i2c_bus *bus)
+{
+       return bus->type;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_type);
+
+int pmac_i2c_get_flags(struct pmac_i2c_bus *bus)
+{
+       return bus->flags;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_flags);
+
+int pmac_i2c_get_channel(struct pmac_i2c_bus *bus)
+{
+       return bus->channel;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_channel);
+
+
+void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
+                            struct i2c_adapter *adapter)
+{
+       WARN_ON(bus->adapter != NULL);
+       bus->adapter = adapter;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_attach_adapter);
+
+void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
+                            struct i2c_adapter *adapter)
+{
+       WARN_ON(bus->adapter != adapter);
+       bus->adapter = NULL;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_detach_adapter);
+
+struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus)
+{
+       return bus->adapter;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter);
+
+struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter)
+{
+       struct pmac_i2c_bus *bus;
+
+       list_for_each_entry(bus, &pmac_i2c_busses, link)
+               if (bus->adapter == adapter)
+                       return bus;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_adapter_to_bus);
+
+extern int pmac_i2c_match_adapter(struct device_node *dev,
+                                 struct i2c_adapter *adapter)
+{
+       struct pmac_i2c_bus *bus = pmac_i2c_find_bus(dev);
+
+       if (bus == NULL)
+               return 0;
+       return (bus->adapter == adapter);
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_match_adapter);
 
 int pmac_low_i2c_lock(struct device_node *np)
 {
-       struct low_i2c_host *host = find_low_i2c_host(np);
+       struct pmac_i2c_bus *bus, *found = NULL;
 
-       if (!host)
+       list_for_each_entry(bus, &pmac_i2c_busses, link) {
+               if (np == bus->controller) {
+                       found = bus;
+                       break;
+               }
+       }
+       if (!found)
                return -ENODEV;
-       down(&host->mutex);
-       return 0;
+       return pmac_i2c_open(bus, 0);
 }
-EXPORT_SYMBOL(pmac_low_i2c_lock);
+EXPORT_SYMBOL_GPL(pmac_low_i2c_lock);
 
 int pmac_low_i2c_unlock(struct device_node *np)
 {
-       struct low_i2c_host *host = find_low_i2c_host(np);
+       struct pmac_i2c_bus *bus, *found = NULL;
 
-       if (!host)
+       list_for_each_entry(bus, &pmac_i2c_busses, link) {
+               if (np == bus->controller) {
+                       found = bus;
+                       break;
+               }
+       }
+       if (!found)
                return -ENODEV;
-       up(&host->mutex);
+       pmac_i2c_close(bus);
        return 0;
 }
-EXPORT_SYMBOL(pmac_low_i2c_unlock);
+EXPORT_SYMBOL_GPL(pmac_low_i2c_unlock);
 
 
-int pmac_low_i2c_open(struct device_node *np, int channel)
+int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled)
 {
-       struct low_i2c_host *host = find_low_i2c_host(np);
+       int rc;
+
+       down(&bus->sem);
+       bus->polled = polled || pmac_i2c_force_poll;
+       bus->opened = 1;
+       bus->mode = pmac_i2c_mode_std;
+       if (bus->open && (rc = bus->open(bus)) != 0) {
+               bus->opened = 0;
+               up(&bus->sem);
+               return rc;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_open);
 
-       if (!host)
-               return -ENODEV;
+void pmac_i2c_close(struct pmac_i2c_bus *bus)
+{
+       WARN_ON(!bus->opened);
+       if (bus->close)
+               bus->close(bus);
+       bus->opened = 0;
+       up(&bus->sem);
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_close);
 
-       if (channel >= host->num_channels)
+int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode)
+{
+       WARN_ON(!bus->opened);
+
+       /* Report me if you see the error below as there might be a new
+        * "combined4" mode that I need to implement for the SMU bus
+        */
+       if (mode < pmac_i2c_mode_dumb || mode > pmac_i2c_mode_combined) {
+               printk(KERN_ERR "low_i2c: Invalid mode %d requested on"
+                      " bus %s !\n", mode, bus->busnode->full_name);
                return -EINVAL;
-
-       down(&host->mutex);
-       host->is_open = 1;
-       host->channel = channel;
+       }
+       bus->mode = mode;
 
        return 0;
 }
-EXPORT_SYMBOL(pmac_low_i2c_open);
+EXPORT_SYMBOL_GPL(pmac_i2c_setmode);
 
-int pmac_low_i2c_close(struct device_node *np)
+int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+                 u32 subaddr, u8 *data, int len)
 {
-       struct low_i2c_host *host = find_low_i2c_host(np);
+       int rc;
 
-       if (!host)
-               return -ENODEV;
+       WARN_ON(!bus->opened);
 
-       host->is_open = 0;
-       up(&host->mutex);
+       DBG("xfer() chan=%d, addrdir=0x%x, mode=%d, subsize=%d, subaddr=0x%x,"
+           " %d bytes, bus %s\n", bus->channel, addrdir, bus->mode, subsize,
+           subaddr, len, bus->busnode->full_name);
 
-       return 0;
+       rc = bus->xfer(bus, addrdir, subsize, subaddr, data, len);
+
+#ifdef DEBUG
+       if (rc)
+               DBG("xfer error %d\n", rc);
+#endif
+       return rc;
 }
-EXPORT_SYMBOL(pmac_low_i2c_close);
+EXPORT_SYMBOL_GPL(pmac_i2c_xfer);
+
+/* some quirks for platform function decoding */
+enum {
+       pmac_i2c_quirk_invmask = 0x00000001u,
+};
 
-int pmac_low_i2c_setmode(struct device_node *np, int mode)
+static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
+                                             int quirks))
 {
-       struct low_i2c_host *host = find_low_i2c_host(np);
+       struct pmac_i2c_bus *bus;
+       struct device_node *np;
+       static struct whitelist_ent {
+               char *name;
+               char *compatible;
+               int quirks;
+       } whitelist[] = {
+               /* XXX Study device-tree's & apple drivers are get the quirks
+                * right !
+                */
+               { "i2c-hwclock", NULL, pmac_i2c_quirk_invmask },
+               { "i2c-cpu-voltage", NULL, 0},
+               {  "temp-monitor", NULL, 0 },
+               {  "supply-monitor", NULL, 0 },
+               { NULL, NULL, 0 },
+       };
+
+       /* Only some devices need to have platform functions instanciated
+        * here. For now, we have a table. Others, like 9554 i2c GPIOs used
+        * on Xserve, if we ever do a driver for them, will use their own
+        * platform function instance
+        */
+       list_for_each_entry(bus, &pmac_i2c_busses, link) {
+               for (np = NULL;
+                    (np = of_get_next_child(bus->busnode, np)) != NULL;) {
+                       struct whitelist_ent *p;
+                       /* If multibus, check if device is on that bus */
+                       if (bus->flags & pmac_i2c_multibus)
+                               if (bus != pmac_i2c_find_bus(np))
+                                       continue;
+                       for (p = whitelist; p->name != NULL; p++) {
+                               if (strcmp(np->name, p->name))
+                                       continue;
+                               if (p->compatible &&
+                                   !device_is_compatible(np, p->compatible))
+                                       continue;
+                               callback(np, p->quirks);
+                               break;
+                       }
+               }
+       }
+}
 
-       if (!host)
-               return -ENODEV;
-       WARN_ON(!host->is_open);
-       host->mode = mode;
+#define MAX_I2C_DATA   64
+
+struct pmac_i2c_pf_inst
+{
+       struct pmac_i2c_bus     *bus;
+       u8                      addr;
+       u8                      buffer[MAX_I2C_DATA];
+       u8                      scratch[MAX_I2C_DATA];
+       int                     bytes;
+       int                     quirks;
+};
+
+static void* pmac_i2c_do_begin(struct pmf_function *func, struct pmf_args *args)
+{
+       struct pmac_i2c_pf_inst *inst;
+       struct pmac_i2c_bus     *bus;
+
+       bus = pmac_i2c_find_bus(func->node);
+       if (bus == NULL) {
+               printk(KERN_ERR "low_i2c: Can't find bus for %s (pfunc)\n",
+                      func->node->full_name);
+               return NULL;
+       }
+       if (pmac_i2c_open(bus, 0)) {
+               printk(KERN_ERR "low_i2c: Can't open i2c bus for %s (pfunc)\n",
+                      func->node->full_name);
+               return NULL;
+       }
+
+       /* XXX might need GFP_ATOMIC when called during the suspend process,
+        * but then, there are already lots of issues with suspending when
+        * near OOM that need to be resolved, the allocator itself should
+        * probably make GFP_NOIO implicit during suspend
+        */
+       inst = kzalloc(sizeof(struct pmac_i2c_pf_inst), GFP_KERNEL);
+       if (inst == NULL) {
+               pmac_i2c_close(bus);
+               return NULL;
+       }
+       inst->bus = bus;
+       inst->addr = pmac_i2c_get_dev_addr(func->node);
+       inst->quirks = (int)(long)func->driver_data;
+       return inst;
+}
+
+static void pmac_i2c_do_end(struct pmf_function *func, void *instdata)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+
+       if (inst == NULL)
+               return;
+       pmac_i2c_close(inst->bus);
+       if (inst)
+               kfree(inst);
+}
+
+static int pmac_i2c_do_read(PMF_STD_ARGS, u32 len)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+
+       inst->bytes = len;
+       return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 0, 0,
+                            inst->buffer, len);
+}
+
+static int pmac_i2c_do_write(PMF_STD_ARGS, u32 len, const u8 *data)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+
+       return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0,
+                            (u8 *)data, len);
+}
+
+/* This function is used to do the masking & OR'ing for the "rmw" type
+ * callbacks. Ze should apply the mask and OR in the values in the
+ * buffer before writing back. The problem is that it seems that
+ * various darwin drivers implement the mask/or differently, thus
+ * we need to check the quirks first
+ */
+static void pmac_i2c_do_apply_rmw(struct pmac_i2c_pf_inst *inst,
+                                 u32 len, const u8 *mask, const u8 *val)
+{
+       int i;
+
+       if (inst->quirks & pmac_i2c_quirk_invmask) {
+               for (i = 0; i < len; i ++)
+                       inst->scratch[i] = (inst->buffer[i] & mask[i]) | val[i];
+       } else {
+               for (i = 0; i < len; i ++)
+                       inst->scratch[i] = (inst->buffer[i] & ~mask[i])
+                               | (val[i] & mask[i]);
+       }
+}
+
+static int pmac_i2c_do_rmw(PMF_STD_ARGS, u32 masklen, u32 valuelen,
+                          u32 totallen, const u8 *maskdata,
+                          const u8 *valuedata)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+
+       if (masklen > inst->bytes || valuelen > inst->bytes ||
+           totallen > inst->bytes || valuelen > masklen)
+               return -EINVAL;
+
+       pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata);
+
+       return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0,
+                            inst->scratch, totallen);
+}
+
+static int pmac_i2c_do_read_sub(PMF_STD_ARGS, u8 subaddr, u32 len)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+
+       inst->bytes = len;
+       return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 1, subaddr,
+                            inst->buffer, len);
+}
+
+static int pmac_i2c_do_write_sub(PMF_STD_ARGS, u8 subaddr, u32 len,
+                                    const u8 *data)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+
+       return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1,
+                            subaddr, (u8 *)data, len);
+}
 
+static int pmac_i2c_do_set_mode(PMF_STD_ARGS, int mode)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+
+       return pmac_i2c_setmode(inst->bus, mode);
+}
+
+static int pmac_i2c_do_rmw_sub(PMF_STD_ARGS, u8 subaddr, u32 masklen,
+                              u32 valuelen, u32 totallen, const u8 *maskdata,
+                              const u8 *valuedata)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+
+       if (masklen > inst->bytes || valuelen > inst->bytes ||
+           totallen > inst->bytes || valuelen > masklen)
+               return -EINVAL;
+
+       pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata);
+
+       return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1,
+                            subaddr, inst->scratch, totallen);
+}
+
+static int pmac_i2c_do_mask_and_comp(PMF_STD_ARGS, u32 len,
+                                    const u8 *maskdata,
+                                    const u8 *valuedata)
+{
+       struct pmac_i2c_pf_inst *inst = instdata;
+       int i, match;
+
+       /* Get return value pointer, it's assumed to be a u32 */
+       if (!args || !args->count || !args->u[0].p)
+               return -EINVAL;
+
+       /* Check buffer */
+       if (len > inst->bytes)
+               return -EINVAL;
+
+       for (i = 0, match = 1; match && i < len; i ++)
+               if ((inst->buffer[i] & maskdata[i]) != valuedata[i])
+                       match = 0;
+       *args->u[0].p = match;
        return 0;
 }
-EXPORT_SYMBOL(pmac_low_i2c_setmode);
 
-int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
+static int pmac_i2c_do_delay(PMF_STD_ARGS, u32 duration)
 {
-       struct low_i2c_host *host = find_low_i2c_host(np);
+       msleep((duration + 999) / 1000);
+       return 0;
+}
 
-       if (!host)
-               return -ENODEV;
-       WARN_ON(!host->is_open);
 
-       return host->func(host, addrdir, subaddr, data, len);
+static struct pmf_handlers pmac_i2c_pfunc_handlers = {
+       .begin                  = pmac_i2c_do_begin,
+       .end                    = pmac_i2c_do_end,
+       .read_i2c               = pmac_i2c_do_read,
+       .write_i2c              = pmac_i2c_do_write,
+       .rmw_i2c                = pmac_i2c_do_rmw,
+       .read_i2c_sub           = pmac_i2c_do_read_sub,
+       .write_i2c_sub          = pmac_i2c_do_write_sub,
+       .rmw_i2c_sub            = pmac_i2c_do_rmw_sub,
+       .set_i2c_mode           = pmac_i2c_do_set_mode,
+       .mask_and_compare       = pmac_i2c_do_mask_and_comp,
+       .delay                  = pmac_i2c_do_delay,
+};
+
+static void __init pmac_i2c_dev_create(struct device_node *np, int quirks)
+{
+       DBG("dev_create(%s)\n", np->full_name);
+
+       pmf_register_driver(np, &pmac_i2c_pfunc_handlers,
+                           (void *)(long)quirks);
+}
+
+static void __init pmac_i2c_dev_init(struct device_node *np, int quirks)
+{
+       DBG("dev_create(%s)\n", np->full_name);
+
+       pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+}
+
+static void pmac_i2c_dev_suspend(struct device_node *np, int quirks)
+{
+       DBG("dev_suspend(%s)\n", np->full_name);
+       pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_SLEEP, NULL);
+}
+
+static void pmac_i2c_dev_resume(struct device_node *np, int quirks)
+{
+       DBG("dev_resume(%s)\n", np->full_name);
+       pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_WAKE, NULL);
+}
+
+void pmac_pfunc_i2c_suspend(void)
+{
+       pmac_i2c_devscan(pmac_i2c_dev_suspend);
+}
+
+void pmac_pfunc_i2c_resume(void)
+{
+       pmac_i2c_devscan(pmac_i2c_dev_resume);
+}
+
+/*
+ * Initialize us: probe all i2c busses on the machine, instantiate
+ * busses and platform functions as needed.
+ */
+/* This is non-static as it might be called early by smp code */
+int __init pmac_i2c_init(void)
+{
+       static int i2c_inited;
+
+       if (i2c_inited)
+               return 0;
+       i2c_inited = 1;
+
+       /* Probe keywest-i2c busses */
+       kw_i2c_probe();
+
+#ifdef CONFIG_ADB_PMU
+       /* Probe PMU i2c busses */
+       pmu_i2c_probe();
+#endif
+
+#ifdef CONFIG_PMAC_SMU
+       /* Probe SMU i2c busses */
+       smu_i2c_probe();
+#endif
+
+       /* Now add plaform functions for some known devices */
+       pmac_i2c_devscan(pmac_i2c_dev_create);
+
+       return 0;
 }
-EXPORT_SYMBOL(pmac_low_i2c_xfer);
+arch_initcall(pmac_i2c_init);
+
+/* Since pmac_i2c_init can be called too early for the platform device
+ * registration, we need to do it at a later time. In our case, subsys
+ * happens to fit well, though I agree it's a bit of a hack...
+ */
+static int __init pmac_i2c_create_platform_devices(void)
+{
+       struct pmac_i2c_bus *bus;
+       int i = 0;
+
+       /* In the case where we are initialized from smp_init(), we must
+        * not use the timer (and thus the irq). It's safe from now on
+        * though
+        */
+       pmac_i2c_force_poll = 0;
+
+       /* Create platform devices */
+       list_for_each_entry(bus, &pmac_i2c_busses, link) {
+               bus->platform_dev =
+                       platform_device_alloc("i2c-powermac", i++);
+               if (bus->platform_dev == NULL)
+                       return -ENOMEM;
+               bus->platform_dev->dev.platform_data = bus;
+               platform_device_add(bus->platform_dev);
+       }
+
+       /* Now call platform "init" functions */
+       pmac_i2c_devscan(pmac_i2c_dev_init);
 
+       return 0;
+}
+subsys_initcall(pmac_i2c_create_platform_devices);
index 4042e2f06ee0f671c536ec16456fe009db94adc1..3ebd045a335048a954cc401bd9dc135df0473103 100644 (file)
@@ -514,7 +514,7 @@ static void core99_nvram_sync(void)
 #endif
 }
 
-static int __init core99_nvram_setup(struct device_node *dp)
+static int __init core99_nvram_setup(struct device_node *dp, unsigned long addr)
 {
        int i;
        u32 gen_bank0, gen_bank1;
@@ -528,7 +528,7 @@ static int __init core99_nvram_setup(struct device_node *dp)
                printk(KERN_ERR "nvram: can't allocate ram image\n");
                return -ENOMEM;
        }
-       nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+       nvram_data = ioremap(addr, NVRAM_SIZE*2);
        nvram_naddrs = 1; /* Make sure we get the correct case */
 
        DBG("nvram: Checking bank 0...\n");
@@ -549,6 +549,7 @@ static int __init core99_nvram_setup(struct device_node *dp)
        ppc_md.nvram_write      = core99_nvram_write;
        ppc_md.nvram_size       = core99_nvram_size;
        ppc_md.nvram_sync       = core99_nvram_sync;
+       ppc_md.machine_shutdown = core99_nvram_sync;
        /* 
         * Maybe we could be smarter here though making an exclusive list
         * of known flash chips is a bit nasty as older OF didn't provide us
@@ -569,34 +570,48 @@ static int __init core99_nvram_setup(struct device_node *dp)
 int __init pmac_nvram_init(void)
 {
        struct device_node *dp;
+       struct resource r1, r2;
+       unsigned int s1 = 0, s2 = 0;
        int err = 0;
 
        nvram_naddrs = 0;
 
-       dp = find_devices("nvram");
+       dp = of_find_node_by_name(NULL, "nvram");
        if (dp == NULL) {
                printk(KERN_ERR "Can't find NVRAM device\n");
                return -ENODEV;
        }
-       nvram_naddrs = dp->n_addrs;
+
+       /* Try to obtain an address */
+       if (of_address_to_resource(dp, 0, &r1) == 0) {
+               nvram_naddrs = 1;
+               s1 = (r1.end - r1.start) + 1;
+               if (of_address_to_resource(dp, 1, &r2) == 0) {
+                       nvram_naddrs = 2;
+                       s2 = (r2.end - r2.start) + 1;
+               }
+       }
+
        is_core_99 = device_is_compatible(dp, "nvram,flash");
-       if (is_core_99)
-               err = core99_nvram_setup(dp);
+       if (is_core_99) {
+               err = core99_nvram_setup(dp, r1.start);
+               goto bail;
+       }
+
 #ifdef CONFIG_PPC32
-       else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
-               nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
-                                    dp->addrs[0].size);
+       if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+               nvram_data = ioremap(r1.start, s1);
                nvram_mult = 1;
                ppc_md.nvram_read_val   = direct_nvram_read_byte;
                ppc_md.nvram_write_val  = direct_nvram_write_byte;
        } else if (nvram_naddrs == 1) {
-               nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-               nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+               nvram_data = ioremap(r1.start, s1);
+               nvram_mult = (s1 + NVRAM_SIZE - 1) / NVRAM_SIZE;
                ppc_md.nvram_read_val   = direct_nvram_read_byte;
                ppc_md.nvram_write_val  = direct_nvram_write_byte;
        } else if (nvram_naddrs == 2) {
-               nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-               nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+               nvram_addr = ioremap(r1.start, s1);
+               nvram_data = ioremap(r2.start, s2);
                ppc_md.nvram_read_val   = indirect_nvram_read_byte;
                ppc_md.nvram_write_val  = indirect_nvram_write_byte;
        } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
@@ -605,13 +620,15 @@ int __init pmac_nvram_init(void)
                ppc_md.nvram_read_val   = pmu_nvram_read_byte;
                ppc_md.nvram_write_val  = pmu_nvram_write_byte;
 #endif /* CONFIG_ADB_PMU */
-       }
-#endif
-       else {
+       } else {
                printk(KERN_ERR "Incompatible type of NVRAM\n");
-               return -ENXIO;
+               err = -ENXIO;
        }
-       lookup_partitions();
+#endif /* CONFIG_PPC32 */
+bail:
+       of_node_put(dp);
+       if (err == 0)
+               lookup_partitions();
        return err;
 }
 
index 443be526cde7ec90a3b0b2e2f18f965613cd3581..f671ed2539013ed8f7299f4c2bb974489dc697c2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Support for PCI bridges found on Power Macintoshes.
  *
- * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
+ * Copyright (C) 2003-2005 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
  * Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
  *
  * This program is free software; you can redistribute it and/or
@@ -25,7 +25,7 @@
 #include <asm/pmac_feature.h>
 #include <asm/grackle.h>
 #ifdef CONFIG_PPC64
-#include <asm/iommu.h>
+//#include <asm/iommu.h>
 #include <asm/ppc-pci.h>
 #endif
 
@@ -44,6 +44,7 @@ static int add_bridge(struct device_node *dev);
 static int has_uninorth;
 #ifdef CONFIG_PPC64
 static struct pci_controller *u3_agp;
+static struct pci_controller *u4_pcie;
 static struct pci_controller *u3_ht;
 #endif /* CONFIG_PPC64 */
 
@@ -97,11 +98,8 @@ static void __init fixup_bus_range(struct device_node *bridge)
 
        /* Lookup the "bus-range" property for the hose */
        bus_range = (int *) get_property(bridge, "bus-range", &len);
-       if (bus_range == NULL || len < 2 * sizeof(int)) {
-               printk(KERN_WARNING "Can't get bus-range for %s\n",
-                              bridge->full_name);
+       if (bus_range == NULL || len < 2 * sizeof(int))
                return;
-       }
        bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
 }
 
@@ -128,14 +126,14 @@ static void __init fixup_bus_range(struct device_node *bridge)
  */
 
 #define MACRISC_CFA0(devfn, off)       \
-       ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
-       | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
-       | (((unsigned long)(off)) & 0xFCUL))
+       ((1 << (unsigned int)PCI_SLOT(dev_fn)) \
+       | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \
+       | (((unsigned int)(off)) & 0xFCUL))
 
 #define MACRISC_CFA1(bus, devfn, off)  \
-       ((((unsigned long)(bus)) << 16) \
-       |(((unsigned long)(devfn)) << 8) \
-       |(((unsigned long)(off)) & 0xFCUL) \
+       ((((unsigned int)(bus)) << 16) \
+       |(((unsigned int)(devfn)) << 8) \
+       |(((unsigned int)(off)) & 0xFCUL) \
        |1UL)
 
 static unsigned long macrisc_cfg_access(struct pci_controller* hose,
@@ -168,7 +166,8 @@ static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
        hose = pci_bus_to_host(bus);
        if (hose == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
-
+       if (offset >= 0x100)
+               return  PCIBIOS_BAD_REGISTER_NUMBER;
        addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
        if (!addr)
                return PCIBIOS_DEVICE_NOT_FOUND;
@@ -199,7 +198,8 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
        hose = pci_bus_to_host(bus);
        if (hose == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
-
+       if (offset >= 0x100)
+               return  PCIBIOS_BAD_REGISTER_NUMBER;
        addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
        if (!addr)
                return PCIBIOS_DEVICE_NOT_FOUND;
@@ -234,12 +234,13 @@ static struct pci_ops macrisc_pci_ops =
 /*
  * Verify that a specific (bus, dev_fn) exists on chaos
  */
-static int
-chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
+static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
 {
        struct device_node *np;
        u32 *vendor, *device;
 
+       if (offset >= 0x100)
+               return  PCIBIOS_BAD_REGISTER_NUMBER;
        np = pci_busdev_to_OF_node(bus, devfn);
        if (np == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
@@ -285,15 +286,13 @@ static struct pci_ops chaos_pci_ops =
 };
 
 static void __init setup_chaos(struct pci_controller *hose,
-                              struct reg_property *addr)
+                              struct resource *addr)
 {
        /* assume a `chaos' bridge */
        hose->ops = &chaos_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+       hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
 }
-#else
-#define setup_chaos(hose, addr)
 #endif /* CONFIG_PPC32 */
 
 #ifdef CONFIG_PPC64
@@ -326,7 +325,7 @@ static int u3_ht_skip_device(struct pci_controller *hose,
        else
                busdn = hose->arch_data;
        for (dn = busdn->child; dn; dn = dn->sibling)
-               if (dn->data && PCI_DN(dn)->devfn == devfn)
+               if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn)
                        break;
        if (dn == NULL)
                return -1;
@@ -343,10 +342,10 @@ static int u3_ht_skip_device(struct pci_controller *hose,
 }
 
 #define U3_HT_CFA0(devfn, off)         \
-               ((((unsigned long)devfn) << 8) | offset)
+               ((((unsigned int)devfn) << 8) | offset)
 #define U3_HT_CFA1(bus, devfn, off)    \
                (U3_HT_CFA0(devfn, off) \
-               + (((unsigned long)bus) << 16) \
+               + (((unsigned int)bus) << 16) \
                + 0x01000000UL)
 
 static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
@@ -356,9 +355,11 @@ static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
                /* For now, we don't self probe U3 HT bridge */
                if (PCI_SLOT(devfn) == 0)
                        return 0;
-               return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
+               return ((unsigned long)hose->cfg_data) +
+                       U3_HT_CFA0(devfn, offset);
        } else
-               return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset);
+               return ((unsigned long)hose->cfg_data) +
+                       U3_HT_CFA1(bus, devfn, offset);
 }
 
 static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
@@ -370,7 +371,8 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
        hose = pci_bus_to_host(bus);
        if (hose == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
-
+       if (offset >= 0x100)
+               return  PCIBIOS_BAD_REGISTER_NUMBER;
        addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
        if (!addr)
                return PCIBIOS_DEVICE_NOT_FOUND;
@@ -419,7 +421,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
        hose = pci_bus_to_host(bus);
        if (hose == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
-
+       if (offset >= 0x100)
+               return  PCIBIOS_BAD_REGISTER_NUMBER;
        addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
        if (!addr)
                return PCIBIOS_DEVICE_NOT_FOUND;
@@ -459,6 +462,112 @@ static struct pci_ops u3_ht_pci_ops =
        u3_ht_read_config,
        u3_ht_write_config
 };
+
+#define U4_PCIE_CFA0(devfn, off)       \
+       ((1 << ((unsigned int)PCI_SLOT(dev_fn)))        \
+        | (((unsigned int)PCI_FUNC(dev_fn)) << 8)      \
+        | ((((unsigned int)(off)) >> 8) << 28) \
+        | (((unsigned int)(off)) & 0xfcU))
+
+#define U4_PCIE_CFA1(bus, devfn, off)  \
+       ((((unsigned int)(bus)) << 16) \
+        |(((unsigned int)(devfn)) << 8)        \
+        | ((((unsigned int)(off)) >> 8) << 28) \
+        |(((unsigned int)(off)) & 0xfcU)       \
+        |1UL)
+
+static unsigned long u4_pcie_cfg_access(struct pci_controller* hose,
+                                       u8 bus, u8 dev_fn, int offset)
+{
+       unsigned int caddr;
+
+       if (bus == hose->first_busno) {
+               caddr = U4_PCIE_CFA0(dev_fn, offset);
+       } else
+               caddr = U4_PCIE_CFA1(bus, dev_fn, offset);
+
+       /* Uninorth will return garbage if we don't read back the value ! */
+       do {
+               out_le32(hose->cfg_addr, caddr);
+       } while (in_le32(hose->cfg_addr) != caddr);
+
+       offset &= 0x03;
+       return ((unsigned long)hose->cfg_data) + offset;
+}
+
+static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
+                              int offset, int len, u32 *val)
+{
+       struct pci_controller *hose;
+       unsigned long addr;
+
+       hose = pci_bus_to_host(bus);
+       if (hose == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (offset >= 0x1000)
+               return  PCIBIOS_BAD_REGISTER_NUMBER;
+       addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               *val = in_8((u8 *)addr);
+               break;
+       case 2:
+               *val = in_le16((u16 *)addr);
+               break;
+       default:
+               *val = in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
+                               int offset, int len, u32 val)
+{
+       struct pci_controller *hose;
+       unsigned long addr;
+
+       hose = pci_bus_to_host(bus);
+       if (hose == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (offset >= 0x1000)
+               return  PCIBIOS_BAD_REGISTER_NUMBER;
+       addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               out_8((u8 *)addr, val);
+               (void) in_8((u8 *)addr);
+               break;
+       case 2:
+               out_le16((u16 *)addr, val);
+               (void) in_le16((u16 *)addr);
+               break;
+       default:
+               out_le32((u32 *)addr, val);
+               (void) in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u4_pcie_pci_ops =
+{
+       u4_pcie_read_config,
+       u4_pcie_write_config
+};
+
 #endif /* CONFIG_PPC64 */
 
 #ifdef CONFIG_PPC32
@@ -532,7 +641,8 @@ static void __init init_p2pbridge(void)
        }
        if (early_read_config_word(hose, bus, devfn,
                                   PCI_BRIDGE_CONTROL, &val) < 0) {
-               printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+               printk(KERN_ERR "init_p2pbridge: couldn't read bridge"
+                      " control\n");
                return;
        }
        val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
@@ -576,36 +686,38 @@ static void __init fixup_nec_usb2(void)
                        continue;
                early_read_config_dword(hose, bus, devfn, 0xe4, &data);
                if (data & 1UL) {
-                       printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n");
+                       printk("Found NEC PD720100A USB2 chip with disabled"
+                              " EHCI, fixing up...\n");
                        data &= ~1UL;
                        early_write_config_dword(hose, bus, devfn, 0xe4, data);
-                       early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE,
+                       early_write_config_byte(hose, bus,
+                                               devfn | 2, PCI_INTERRUPT_LINE,
                                nec->intrs[0].line);
                }
        }
 }
 
 static void __init setup_bandit(struct pci_controller *hose,
-                               struct reg_property *addr)
+                               struct resource *addr)
 {
        hose->ops = &macrisc_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+       hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
        init_bandit(hose);
 }
 
 static int __init setup_uninorth(struct pci_controller *hose,
-                                struct reg_property *addr)
+                                struct resource *addr)
 {
        pci_assign_all_buses = 1;
        has_uninorth = 1;
        hose->ops = &macrisc_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+       hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
        /* We "know" that the bridge at f2000000 has the PCI slots. */
-       return addr->address == 0xf2000000;
+       return addr->start == 0xf2000000;
 }
-#endif
+#endif /* CONFIG_PPC32 */
 
 #ifdef CONFIG_PPC64
 static void __init setup_u3_agp(struct pci_controller* hose)
@@ -625,15 +737,36 @@ static void __init setup_u3_agp(struct pci_controller* hose)
        hose->ops = &macrisc_pci_ops;
        hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
        hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
-
        u3_agp = hose;
 }
 
+static void __init setup_u4_pcie(struct pci_controller* hose)
+{
+       /* We currently only implement the "non-atomic" config space, to
+        * be optimised later.
+        */
+       hose->ops = &u4_pcie_pci_ops;
+       hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+       /* The bus contains a bridge from root -> device, we need to
+        * make it visible on bus 0 so that we pick the right type
+        * of config cycles. If we didn't, we would have to force all
+        * config cycles to be type 1. So we override the "bus-range"
+        * property here
+        */
+       hose->first_busno = 0x00;
+       hose->last_busno = 0xff;
+       u4_pcie = hose;
+}
+
 static void __init setup_u3_ht(struct pci_controller* hose)
 {
        struct device_node *np = (struct device_node *)hose->arch_data;
+       struct pci_controller *other = NULL;
        int i, cur;
 
+
        hose->ops = &u3_ht_pci_ops;
 
        /* We hard code the address because of the different size of
@@ -667,11 +800,20 @@ static void __init setup_u3_ht(struct pci_controller* hose)
 
        u3_ht = hose;
 
-       if (u3_agp == NULL) {
-               DBG("U3 has no AGP, using full resource range\n");
+       if (u3_agp != NULL)
+               other = u3_agp;
+       else if (u4_pcie != NULL)
+               other = u4_pcie;
+
+       if (other == NULL) {
+               DBG("U3/4 has no AGP/PCIE, using full resource range\n");
                return;
        }
 
+       /* Fixup bus range vs. PCIE */
+       if (u4_pcie)
+               hose->last_busno = u4_pcie->first_busno - 1;
+
        /* We "remove" the AGP resources from the resources allocated to HT,
         * that is we create "holes". However, that code does assumptions
         * that so far happen to be true (cross fingers...), typically that
@@ -679,7 +821,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
         */
        cur = 0;
        for (i=0; i<3; i++) {
-               struct resource *res = &u3_agp->mem_resources[i];
+               struct resource *res = &other->mem_resources[i];
                if (res->flags != IORESOURCE_MEM)
                        continue;
                /* We don't care about "fine" resources */
@@ -722,7 +864,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
                hose->mem_resources[cur-1].end = res->start - 1;
        }
 }
-#endif
+#endif /* CONFIG_PPC64 */
 
 /*
  * We assume that if we have a G3 powermac, we have one bridge called
@@ -733,24 +875,17 @@ static int __init add_bridge(struct device_node *dev)
 {
        int len;
        struct pci_controller *hose;
-#ifdef CONFIG_PPC32
-       struct reg_property *addr;
-#endif
+       struct resource rsrc;
        char *disp_name;
        int *bus_range;
-       int primary = 1;
+       int primary = 1, has_address = 0;
 
        DBG("Adding PCI host bridge %s\n", dev->full_name);
 
-#ifdef CONFIG_PPC32
-       /* XXX fix this */
-       addr = (struct reg_property *) get_property(dev, "reg", &len);
-       if (addr == NULL || len < sizeof(*addr)) {
-               printk(KERN_WARNING "Can't use %s: no address\n",
-                      dev->full_name);
-               return -ENODEV;
-       }
-#endif
+       /* Fetch host bridge registers address */
+       has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+       /* Get bus range if any */
        bus_range = (int *) get_property(dev, "bus-range", &len);
        if (bus_range == NULL || len < 2 * sizeof(int)) {
                printk(KERN_WARNING "Can't get bus-range for %s, assume"
@@ -770,6 +905,8 @@ static int __init add_bridge(struct device_node *dev)
        hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
        disp_name = NULL;
+
+       /* 64 bits only bridges */
 #ifdef CONFIG_PPC64
        if (device_is_compatible(dev, "u3-agp")) {
                setup_u3_agp(hose);
@@ -779,28 +916,37 @@ static int __init add_bridge(struct device_node *dev)
                setup_u3_ht(hose);
                disp_name = "U3-HT";
                primary = 1;
+       } else if (device_is_compatible(dev, "u4-pcie")) {
+               setup_u4_pcie(hose);
+               disp_name = "U4-PCIE";
+               primary = 0;
        }
-       printk(KERN_INFO "Found %s PCI host bridge.  Firmware bus number: %d->%d\n",
-               disp_name, hose->first_busno, hose->last_busno);
-#else
+       printk(KERN_INFO "Found %s PCI host bridge.  Firmware bus number:"
+              " %d->%d\n", disp_name, hose->first_busno, hose->last_busno);
+#endif /* CONFIG_PPC64 */
+
+       /* 32 bits only bridges */
+#ifdef CONFIG_PPC32
        if (device_is_compatible(dev, "uni-north")) {
-               primary = setup_uninorth(hose, addr);
+               primary = setup_uninorth(hose, &rsrc);
                disp_name = "UniNorth";
        } else if (strcmp(dev->name, "pci") == 0) {
                /* XXX assume this is a mpc106 (grackle) */
                setup_grackle(hose);
                disp_name = "Grackle (MPC106)";
        } else if (strcmp(dev->name, "bandit") == 0) {
-               setup_bandit(hose, addr);
+               setup_bandit(hose, &rsrc);
                disp_name = "Bandit";
        } else if (strcmp(dev->name, "chaos") == 0) {
-               setup_chaos(hose, addr);
+               setup_chaos(hose, &rsrc);
                disp_name = "Chaos";
                primary = 0;
        }
-       printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n",
-               disp_name, addr->address, hose->first_busno, hose->last_busno);
-#endif
+       printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. "
+              "Firmware bus number: %d->%d\n",
+               disp_name, rsrc.start, hose->first_busno, hose->last_busno);
+#endif /* CONFIG_PPC32 */
+
        DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
                hose, hose->cfg_addr, hose->cfg_data);
 
@@ -814,8 +960,7 @@ static int __init add_bridge(struct device_node *dev)
        return 0;
 }
 
-static void __init
-pcibios_fixup_OF_interrupts(void)
+static void __init pcibios_fixup_OF_interrupts(void)
 {
        struct pci_dev* dev = NULL;
 
@@ -835,8 +980,7 @@ pcibios_fixup_OF_interrupts(void)
        }
 }
 
-void __init
-pmac_pcibios_fixup(void)
+void __init pmac_pcibios_fixup(void)
 {
        /* Fixup interrupts according to OF tree */
        pcibios_fixup_OF_interrupts();
@@ -899,6 +1043,8 @@ void __init pmac_pci_init(void)
                pci_setup_phb_io(u3_ht, 1);
        if (u3_agp)
                pci_setup_phb_io(u3_agp, 0);
+       if (u4_pcie)
+               pci_setup_phb_io(u4_pcie, 0);
 
        /*
         * On ppc64, fixup the IO resources on our host bridges as
@@ -911,7 +1057,8 @@ void __init pmac_pci_init(void)
 
        /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
         * assume there is no P2P bridge on the AGP bus, which should be a
-        * safe assumptions hopefully.
+        * safe assumptions for now. We should do something better in the
+        * future though
         */
        if (u3_agp) {
                struct device_node *np = u3_agp->arch_data;
@@ -919,7 +1066,6 @@ void __init pmac_pci_init(void)
                for (np = np->child; np; np = np->sibling)
                        PCI_DN(np)->busno = 0xf0;
        }
-
        /* pmac_check_ht_link(); */
 
        /* Tell pci.c to not use the common resource allocation mechanism */
@@ -1126,7 +1272,8 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev)
  good:
        pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
        if ((progif & 5) != 5) {
-               printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
+               printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n",
+                      pci_name(dev));
                (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
                if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
                    (progif & 5) != 5)
@@ -1152,7 +1299,8 @@ static void fixup_k2_sata(struct pci_dev* dev)
                for (i = 0; i < 6; i++) {
                        dev->resource[i].start = dev->resource[i].end = 0;
                        dev->resource[i].flags = 0;
-                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
+                                              0);
                }
        } else {
                pci_read_config_word(dev, PCI_COMMAND, &cmd);
@@ -1161,7 +1309,8 @@ static void fixup_k2_sata(struct pci_dev* dev)
                for (i = 0; i < 5; i++) {
                        dev->resource[i].start = dev->resource[i].end = 0;
                        dev->resource[i].flags = 0;
-                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
+                                              0);
                }
        }
 }
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
new file mode 100644 (file)
index 0000000..4ffd2a9
--- /dev/null
@@ -0,0 +1,405 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+
+#define DBG(fmt...)    printk(fmt)
+
+static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs)
+{
+       pmf_do_irq(data);
+
+       return IRQ_HANDLED;
+}
+
+static int macio_do_gpio_irq_enable(struct pmf_function *func)
+{
+       if (func->node->n_intrs < 1)
+               return -EINVAL;
+
+       return request_irq(func->node->intrs[0].line, macio_gpio_irq, 0,
+                          func->node->name, func);
+}
+
+static int macio_do_gpio_irq_disable(struct pmf_function *func)
+{
+       if (func->node->n_intrs < 1)
+               return -EINVAL;
+
+       free_irq(func->node->intrs[0].line, func);
+       return 0;
+}
+
+static int macio_do_gpio_write(PMF_STD_ARGS, u8 value, u8 mask)
+{
+       u8 __iomem *addr = (u8 __iomem *)func->driver_data;
+       unsigned long flags;
+       u8 tmp;
+
+       /* Check polarity */
+       if (args && args->count && !args->u[0].v)
+               value = ~value;
+
+       /* Toggle the GPIO */
+       spin_lock_irqsave(&feature_lock, flags);
+       tmp = readb(addr);
+       tmp = (tmp & ~mask) | (value & mask);
+       DBG("Do write 0x%02x to GPIO %s (%p)\n",
+           tmp, func->node->full_name, addr);
+       writeb(tmp, addr);
+       spin_unlock_irqrestore(&feature_lock, flags);
+
+       return 0;
+}
+
+static int macio_do_gpio_read(PMF_STD_ARGS, u8 mask, int rshift, u8 xor)
+{
+       u8 __iomem *addr = (u8 __iomem *)func->driver_data;
+       u32 value;
+
+       /* Check if we have room for reply */
+       if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+               return -EINVAL;
+
+       value = readb(addr);
+       *args->u[0].p = ((value & mask) >> rshift) ^ xor;
+
+       return 0;
+}
+
+static int macio_do_delay(PMF_STD_ARGS, u32 duration)
+{
+       /* assume we can sleep ! */
+       msleep((duration + 999) / 1000);
+       return 0;
+}
+
+static struct pmf_handlers macio_gpio_handlers = {
+       .irq_enable     = macio_do_gpio_irq_enable,
+       .irq_disable    = macio_do_gpio_irq_disable,
+       .write_gpio     = macio_do_gpio_write,
+       .read_gpio      = macio_do_gpio_read,
+       .delay          = macio_do_delay,
+};
+
+static void macio_gpio_init_one(struct macio_chip *macio)
+{
+       struct device_node *gparent, *gp;
+
+       /*
+        * Find the "gpio" parent node
+        */
+
+       for (gparent = NULL;
+            (gparent = of_get_next_child(macio->of_node, gparent)) != NULL;)
+               if (strcmp(gparent->name, "gpio") == 0)
+                       break;
+       if (gparent == NULL)
+               return;
+
+       DBG("Installing GPIO functions for macio %s\n",
+           macio->of_node->full_name);
+
+       /*
+        * Ok, got one, we dont need anything special to track them down, so
+        * we just create them all
+        */
+       for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) {
+               u32 *reg = (u32 *)get_property(gp, "reg", NULL);
+               unsigned long offset;
+               if (reg == NULL)
+                       continue;
+               offset = *reg;
+               /* Deal with old style device-tree. We can safely hard code the
+                * offset for now too even if it's a bit gross ...
+                */
+               if (offset < 0x50)
+                       offset += 0x50;
+               offset += (unsigned long)macio->base;
+               pmf_register_driver(gp, &macio_gpio_handlers, (void *)offset);
+       }
+
+       DBG("Calling initial GPIO functions for macio %s\n",
+           macio->of_node->full_name);
+
+       /* And now we run all the init ones */
+       for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;)
+               pmf_do_functions(gp, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+
+       /* Note: We do not at this point implement the "at sleep" or "at wake"
+        * functions. I yet to find any for GPIOs anyway
+        */
+}
+
+static int macio_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
+{
+       struct macio_chip *macio = func->driver_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&feature_lock, flags);
+       MACIO_OUT32(offset, (MACIO_IN32(offset) & ~mask) | (value & mask));
+       spin_unlock_irqrestore(&feature_lock, flags);
+       return 0;
+}
+
+static int macio_do_read_reg32(PMF_STD_ARGS, u32 offset)
+{
+       struct macio_chip *macio = func->driver_data;
+
+       /* Check if we have room for reply */
+       if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+               return -EINVAL;
+
+       *args->u[0].p = MACIO_IN32(offset);
+       return 0;
+}
+
+static int macio_do_write_reg8(PMF_STD_ARGS, u32 offset, u8 value, u8 mask)
+{
+       struct macio_chip *macio = func->driver_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&feature_lock, flags);
+       MACIO_OUT8(offset, (MACIO_IN8(offset) & ~mask) | (value & mask));
+       spin_unlock_irqrestore(&feature_lock, flags);
+       return 0;
+}
+
+static int macio_do_read_reg8(PMF_STD_ARGS, u32 offset)
+{
+       struct macio_chip *macio = func->driver_data;
+
+       /* Check if we have room for reply */
+       if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+               return -EINVAL;
+
+       *((u8 *)(args->u[0].p)) = MACIO_IN8(offset);
+       return 0;
+}
+
+static int macio_do_read_reg32_msrx(PMF_STD_ARGS, u32 offset, u32 mask,
+                                   u32 shift, u32 xor)
+{
+       struct macio_chip *macio = func->driver_data;
+
+       /* Check if we have room for reply */
+       if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+               return -EINVAL;
+
+       *args->u[0].p = ((MACIO_IN32(offset) & mask) >> shift) ^ xor;
+       return 0;
+}
+
+static int macio_do_read_reg8_msrx(PMF_STD_ARGS, u32 offset, u32 mask,
+                                  u32 shift, u32 xor)
+{
+       struct macio_chip *macio = func->driver_data;
+
+       /* Check if we have room for reply */
+       if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+               return -EINVAL;
+
+       *((u8 *)(args->u[0].p)) = ((MACIO_IN8(offset) & mask) >> shift) ^ xor;
+       return 0;
+}
+
+static int macio_do_write_reg32_slm(PMF_STD_ARGS, u32 offset, u32 shift,
+                                   u32 mask)
+{
+       struct macio_chip *macio = func->driver_data;
+       unsigned long flags;
+       u32 tmp, val;
+
+       /* Check args */
+       if (args == NULL || args->count == 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&feature_lock, flags);
+       tmp = MACIO_IN32(offset);
+       val = args->u[0].v << shift;
+       tmp = (tmp & ~mask) | (val & mask);
+       MACIO_OUT32(offset, tmp);
+       spin_unlock_irqrestore(&feature_lock, flags);
+       return 0;
+}
+
+static int macio_do_write_reg8_slm(PMF_STD_ARGS, u32 offset, u32 shift,
+                                  u32 mask)
+{
+       struct macio_chip *macio = func->driver_data;
+       unsigned long flags;
+       u32 tmp, val;
+
+       /* Check args */
+       if (args == NULL || args->count == 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&feature_lock, flags);
+       tmp = MACIO_IN8(offset);
+       val = args->u[0].v << shift;
+       tmp = (tmp & ~mask) | (val & mask);
+       MACIO_OUT8(offset, tmp);
+       spin_unlock_irqrestore(&feature_lock, flags);
+       return 0;
+}
+
+static struct pmf_handlers macio_mmio_handlers = {
+       .write_reg32            = macio_do_write_reg32,
+       .read_reg32             = macio_do_read_reg32,
+       .write_reg8             = macio_do_write_reg8,
+       .read_reg32             = macio_do_read_reg8,
+       .read_reg32_msrx        = macio_do_read_reg32_msrx,
+       .read_reg8_msrx         = macio_do_read_reg8_msrx,
+       .write_reg32_slm        = macio_do_write_reg32_slm,
+       .write_reg8_slm         = macio_do_write_reg8_slm,
+       .delay                  = macio_do_delay,
+};
+
+static void macio_mmio_init_one(struct macio_chip *macio)
+{
+       DBG("Installing MMIO functions for macio %s\n",
+           macio->of_node->full_name);
+
+       pmf_register_driver(macio->of_node, &macio_mmio_handlers, macio);
+}
+
+static struct device_node *unin_hwclock;
+
+static int unin_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&feature_lock, flags);
+       /* This is fairly bogus in darwin, but it should work for our needs
+        * implemeted that way:
+        */
+       UN_OUT(offset, (UN_IN(offset) & ~mask) | (value & mask));
+       spin_unlock_irqrestore(&feature_lock, flags);
+       return 0;
+}
+
+
+static struct pmf_handlers unin_mmio_handlers = {
+       .write_reg32            = unin_do_write_reg32,
+       .delay                  = macio_do_delay,
+};
+
+static void uninorth_install_pfunc(void)
+{
+       struct device_node *np;
+
+       DBG("Installing functions for UniN %s\n",
+           uninorth_node->full_name);
+
+       /*
+        * Install handlers for the bridge itself
+        */
+       pmf_register_driver(uninorth_node, &unin_mmio_handlers, NULL);
+       pmf_do_functions(uninorth_node, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+
+
+       /*
+        * Install handlers for the hwclock child if any
+        */
+       for (np = NULL; (np = of_get_next_child(uninorth_node, np)) != NULL;)
+               if (strcmp(np->name, "hw-clock") == 0) {
+                       unin_hwclock = np;
+                       break;
+               }
+       if (unin_hwclock) {
+               DBG("Installing functions for UniN clock %s\n",
+                   unin_hwclock->full_name);
+               pmf_register_driver(unin_hwclock, &unin_mmio_handlers, NULL);
+               pmf_do_functions(unin_hwclock, NULL, 0, PMF_FLAGS_ON_INIT,
+                                NULL);
+       }
+}
+
+/* We export this as the SMP code might init us early */
+int __init pmac_pfunc_base_install(void)
+{
+       static int pfbase_inited;
+       int i;
+
+       if (pfbase_inited)
+               return 0;
+       pfbase_inited = 1;
+
+
+       DBG("Installing base platform functions...\n");
+
+       /*
+        * Locate mac-io chips and install handlers
+        */
+       for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+               if (macio_chips[i].of_node) {
+                       macio_mmio_init_one(&macio_chips[i]);
+                       macio_gpio_init_one(&macio_chips[i]);
+               }
+       }
+
+       /*
+        * Install handlers for northbridge and direct mapped hwclock
+        * if any. We do not implement the config space access callback
+        * which is only ever used for functions that we do not call in
+        * the current driver (enabling/disabling cells in U2, mostly used
+        * to restore the PCI settings, we do that differently)
+        */
+       if (uninorth_node && uninorth_base)
+               uninorth_install_pfunc();
+
+       DBG("All base functions installed\n");
+
+       return 0;
+}
+
+arch_initcall(pmac_pfunc_base_install);
+
+#ifdef CONFIG_PM
+
+/* Those can be called by pmac_feature. Ultimately, I should use a sysdev
+ * or a device, but for now, that's good enough until I sort out some
+ * ordering issues. Also, we do not bother with GPIOs, as so far I yet have
+ * to see a case where a GPIO function has the on-suspend or on-resume bit
+ */
+void pmac_pfunc_base_suspend(void)
+{
+       int i;
+
+       for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+               if (macio_chips[i].of_node)
+                       pmf_do_functions(macio_chips[i].of_node, NULL, 0,
+                                        PMF_FLAGS_ON_SLEEP, NULL);
+       }
+       if (uninorth_node)
+               pmf_do_functions(uninorth_node, NULL, 0,
+                                PMF_FLAGS_ON_SLEEP, NULL);
+       if (unin_hwclock)
+               pmf_do_functions(unin_hwclock, NULL, 0,
+                                PMF_FLAGS_ON_SLEEP, NULL);
+}
+
+void pmac_pfunc_base_resume(void)
+{
+       int i;
+
+       if (unin_hwclock)
+               pmf_do_functions(unin_hwclock, NULL, 0,
+                                PMF_FLAGS_ON_WAKE, NULL);
+       if (uninorth_node)
+               pmf_do_functions(uninorth_node, NULL, 0,
+                                PMF_FLAGS_ON_WAKE, NULL);
+       for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+               if (macio_chips[i].of_node)
+                       pmf_do_functions(macio_chips[i].of_node, NULL, 0,
+                                        PMF_FLAGS_ON_WAKE, NULL);
+       }
+}
+
+#endif /* CONFIG_PM */
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
new file mode 100644 (file)
index 0000000..c32c623
--- /dev/null
@@ -0,0 +1,989 @@
+/*
+ *
+ * FIXME: Properly make this race free with refcounting etc...
+ *
+ * FIXME: LOCKING !!!
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/semaphore.h>
+#include <asm/prom.h>
+#include <asm/pmac_pfunc.h>
+
+/* Debug */
+#define LOG_PARSE(fmt...)
+#define LOG_ERROR(fmt...)      printk(fmt)
+#define LOG_BLOB(t,b,c)
+#define DBG(fmt...)            printk(fmt)
+
+/* Command numbers */
+#define PMF_CMD_LIST                   0
+#define PMF_CMD_WRITE_GPIO             1
+#define PMF_CMD_READ_GPIO              2
+#define PMF_CMD_WRITE_REG32            3
+#define PMF_CMD_READ_REG32             4
+#define PMF_CMD_WRITE_REG16            5
+#define PMF_CMD_READ_REG16             6
+#define PMF_CMD_WRITE_REG8             7
+#define PMF_CMD_READ_REG8              8
+#define PMF_CMD_DELAY                  9
+#define PMF_CMD_WAIT_REG32             10
+#define PMF_CMD_WAIT_REG16             11
+#define PMF_CMD_WAIT_REG8              12
+#define PMF_CMD_READ_I2C               13
+#define PMF_CMD_WRITE_I2C              14
+#define PMF_CMD_RMW_I2C                        15
+#define PMF_CMD_GEN_I2C                        16
+#define PMF_CMD_SHIFT_BYTES_RIGHT      17
+#define PMF_CMD_SHIFT_BYTES_LEFT       18
+#define PMF_CMD_READ_CFG               19
+#define PMF_CMD_WRITE_CFG              20
+#define PMF_CMD_RMW_CFG                        21
+#define PMF_CMD_READ_I2C_SUBADDR       22
+#define PMF_CMD_WRITE_I2C_SUBADDR      23
+#define PMF_CMD_SET_I2C_MODE           24
+#define PMF_CMD_RMW_I2C_SUBADDR                25
+#define PMF_CMD_READ_REG32_MASK_SHR_XOR        26
+#define PMF_CMD_READ_REG16_MASK_SHR_XOR        27
+#define PMF_CMD_READ_REG8_MASK_SHR_XOR 28
+#define PMF_CMD_WRITE_REG32_SHL_MASK   29
+#define PMF_CMD_WRITE_REG16_SHL_MASK   30
+#define PMF_CMD_WRITE_REG8_SHL_MASK    31
+#define PMF_CMD_MASK_AND_COMPARE       32
+#define PMF_CMD_COUNT                  33
+
+/* This structure holds the state of the parser while walking through
+ * a function definition
+ */
+struct pmf_cmd {
+       const void              *cmdptr;
+       const void              *cmdend;
+       struct pmf_function     *func;
+       void                    *instdata;
+       struct pmf_args         *args;
+       int                     error;
+};
+
+#if 0
+/* Debug output */
+static void print_blob(const char *title, const void *blob, int bytes)
+{
+       printk("%s", title);
+       while(bytes--) {
+               printk("%02x ", *((u8 *)blob));
+               blob += 1;
+       }
+       printk("\n");
+}
+#endif
+
+/*
+ * Parser helpers
+ */
+
+static u32 pmf_next32(struct pmf_cmd *cmd)
+{
+       u32 value;
+       if ((cmd->cmdend - cmd->cmdptr) < 4) {
+               cmd->error = 1;
+               return 0;
+       }
+       value = *((u32 *)cmd->cmdptr);
+       cmd->cmdptr += 4;
+       return value;
+}
+
+static const void* pmf_next_blob(struct pmf_cmd *cmd, int count)
+{
+       const void *value;
+       if ((cmd->cmdend - cmd->cmdptr) < count) {
+               cmd->error = 1;
+               return NULL;
+       }
+       value = cmd->cmdptr;
+       cmd->cmdptr += count;
+       return value;
+}
+
+/*
+ * Individual command parsers
+ */
+
+#define PMF_PARSE_CALL(name, cmd, handlers, p...) \
+       do { \
+               if (cmd->error) \
+                       return -ENXIO; \
+               if (handlers == NULL) \
+                       return 0; \
+               if (handlers->name)                                   \
+                       return handlers->name(cmd->func, cmd->instdata, \
+                                             cmd->args, p);          \
+               return -1; \
+       } while(0) \
+
+
+static int pmf_parser_write_gpio(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u8 value = (u8)pmf_next32(cmd);
+       u8 mask = (u8)pmf_next32(cmd);
+
+       LOG_PARSE("pmf: write_gpio(value: %02x, mask: %02x)\n", value, mask);
+
+       PMF_PARSE_CALL(write_gpio, cmd, h, value, mask);
+}
+
+static int pmf_parser_read_gpio(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u8 mask = (u8)pmf_next32(cmd);
+       int rshift = (int)pmf_next32(cmd);
+       u8 xor = (u8)pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_gpio(mask: %02x, rshift: %d, xor: %02x)\n",
+                 mask, rshift, xor);
+
+       PMF_PARSE_CALL(read_gpio, cmd, h, mask, rshift, xor);
+}
+
+static int pmf_parser_write_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 value = pmf_next32(cmd);
+       u32 mask = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: write_reg32(offset: %08x, value: %08x, mask: %08x)\n",
+                 offset, value, mask);
+
+       PMF_PARSE_CALL(write_reg32, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_reg32(offset: %08x)\n", offset);
+
+       PMF_PARSE_CALL(read_reg32, cmd, h, offset);
+}
+
+
+static int pmf_parser_write_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u16 value = (u16)pmf_next32(cmd);
+       u16 mask = (u16)pmf_next32(cmd);
+
+       LOG_PARSE("pmf: write_reg16(offset: %08x, value: %04x, mask: %04x)\n",
+                 offset, value, mask);
+
+       PMF_PARSE_CALL(write_reg16, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_reg16(offset: %08x)\n", offset);
+
+       PMF_PARSE_CALL(read_reg16, cmd, h, offset);
+}
+
+
+static int pmf_parser_write_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u8 value = (u16)pmf_next32(cmd);
+       u8 mask = (u16)pmf_next32(cmd);
+
+       LOG_PARSE("pmf: write_reg8(offset: %08x, value: %02x, mask: %02x)\n",
+                 offset, value, mask);
+
+       PMF_PARSE_CALL(write_reg8, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_reg8(offset: %08x)\n", offset);
+
+       PMF_PARSE_CALL(read_reg8, cmd, h, offset);
+}
+
+static int pmf_parser_delay(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 duration = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: delay(duration: %d us)\n", duration);
+
+       PMF_PARSE_CALL(delay, cmd, h, duration);
+}
+
+static int pmf_parser_wait_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 value = pmf_next32(cmd);
+       u32 mask = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: wait_reg32(offset: %08x, comp_value: %08x,mask: %08x)\n",
+                 offset, value, mask);
+
+       PMF_PARSE_CALL(wait_reg32, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_wait_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u16 value = (u16)pmf_next32(cmd);
+       u16 mask = (u16)pmf_next32(cmd);
+
+       LOG_PARSE("pmf: wait_reg16(offset: %08x, comp_value: %04x,mask: %04x)\n",
+                 offset, value, mask);
+
+       PMF_PARSE_CALL(wait_reg16, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_wait_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u8 value = (u8)pmf_next32(cmd);
+       u8 mask = (u8)pmf_next32(cmd);
+
+       LOG_PARSE("pmf: wait_reg8(offset: %08x, comp_value: %02x,mask: %02x)\n",
+                 offset, value, mask);
+
+       PMF_PARSE_CALL(wait_reg8, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 bytes = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_i2c(bytes: %ud)\n", bytes);
+
+       PMF_PARSE_CALL(read_i2c, cmd, h, bytes);
+}
+
+static int pmf_parser_write_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 bytes = pmf_next32(cmd);
+       const void *blob = pmf_next_blob(cmd, bytes);
+
+       LOG_PARSE("pmf: write_i2c(bytes: %ud) ...\n", bytes);
+       LOG_BLOB("pmf:   data: \n", blob, bytes);
+
+       PMF_PARSE_CALL(write_i2c, cmd, h, bytes, blob);
+}
+
+
+static int pmf_parser_rmw_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 maskbytes = pmf_next32(cmd);
+       u32 valuesbytes = pmf_next32(cmd);
+       u32 totalbytes = pmf_next32(cmd);
+       const void *maskblob = pmf_next_blob(cmd, maskbytes);
+       const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+       LOG_PARSE("pmf: rmw_i2c(maskbytes: %ud, valuebytes: %ud, "
+                 "totalbytes: %d) ...\n",
+                 maskbytes, valuesbytes, totalbytes);
+       LOG_BLOB("pmf:   mask data: \n", maskblob, maskbytes);
+       LOG_BLOB("pmf:   values data: \n", valuesblob, valuesbytes);
+
+       PMF_PARSE_CALL(rmw_i2c, cmd, h, maskbytes, valuesbytes, totalbytes,
+                      maskblob, valuesblob);
+}
+
+static int pmf_parser_read_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 bytes = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_cfg(offset: %x, bytes: %ud)\n", offset, bytes);
+
+       PMF_PARSE_CALL(read_cfg, cmd, h, offset, bytes);
+}
+
+
+static int pmf_parser_write_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 bytes = pmf_next32(cmd);
+       const void *blob = pmf_next_blob(cmd, bytes);
+
+       LOG_PARSE("pmf: write_cfg(offset: %x, bytes: %ud)\n", offset, bytes);
+       LOG_BLOB("pmf:   data: \n", blob, bytes);
+
+       PMF_PARSE_CALL(write_cfg, cmd, h, offset, bytes, blob);
+}
+
+static int pmf_parser_rmw_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 maskbytes = pmf_next32(cmd);
+       u32 valuesbytes = pmf_next32(cmd);
+       u32 totalbytes = pmf_next32(cmd);
+       const void *maskblob = pmf_next_blob(cmd, maskbytes);
+       const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+       LOG_PARSE("pmf: rmw_cfg(maskbytes: %ud, valuebytes: %ud,"
+                 " totalbytes: %d) ...\n",
+                 maskbytes, valuesbytes, totalbytes);
+       LOG_BLOB("pmf:   mask data: \n", maskblob, maskbytes);
+       LOG_BLOB("pmf:   values data: \n", valuesblob, valuesbytes);
+
+       PMF_PARSE_CALL(rmw_cfg, cmd, h, offset, maskbytes, valuesbytes,
+                      totalbytes, maskblob, valuesblob);
+}
+
+
+static int pmf_parser_read_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u8 subaddr = (u8)pmf_next32(cmd);
+       u32 bytes = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_i2c_sub(subaddr: %x, bytes: %ud)\n",
+                 subaddr, bytes);
+
+       PMF_PARSE_CALL(read_i2c_sub, cmd, h, subaddr, bytes);
+}
+
+static int pmf_parser_write_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u8 subaddr = (u8)pmf_next32(cmd);
+       u32 bytes = pmf_next32(cmd);
+       const void *blob = pmf_next_blob(cmd, bytes);
+
+       LOG_PARSE("pmf: write_i2c_sub(subaddr: %x, bytes: %ud) ...\n",
+                 subaddr, bytes);
+       LOG_BLOB("pmf:   data: \n", blob, bytes);
+
+       PMF_PARSE_CALL(write_i2c_sub, cmd, h, subaddr, bytes, blob);
+}
+
+static int pmf_parser_set_i2c_mode(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u32 mode = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: set_i2c_mode(mode: %d)\n", mode);
+
+       PMF_PARSE_CALL(set_i2c_mode, cmd, h, mode);
+}
+
+
+static int pmf_parser_rmw_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+       u8 subaddr = (u8)pmf_next32(cmd);
+       u32 maskbytes = pmf_next32(cmd);
+       u32 valuesbytes = pmf_next32(cmd);
+       u32 totalbytes = pmf_next32(cmd);
+       const void *maskblob = pmf_next_blob(cmd, maskbytes);
+       const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+       LOG_PARSE("pmf: rmw_i2c_sub(subaddr: %x, maskbytes: %ud, valuebytes: %ud"
+                 ", totalbytes: %d) ...\n",
+                 subaddr, maskbytes, valuesbytes, totalbytes);
+       LOG_BLOB("pmf:   mask data: \n", maskblob, maskbytes);
+       LOG_BLOB("pmf:   values data: \n", valuesblob, valuesbytes);
+
+       PMF_PARSE_CALL(rmw_i2c_sub, cmd, h, subaddr, maskbytes, valuesbytes,
+                      totalbytes, maskblob, valuesblob);
+}
+
+static int pmf_parser_read_reg32_msrx(struct pmf_cmd *cmd,
+                                     struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 mask = pmf_next32(cmd);
+       u32 shift = pmf_next32(cmd);
+       u32 xor = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_reg32_msrx(offset: %x, mask: %x, shift: %x,"
+                 " xor: %x\n", offset, mask, shift, xor);
+
+       PMF_PARSE_CALL(read_reg32_msrx, cmd, h, offset, mask, shift, xor);
+}
+
+static int pmf_parser_read_reg16_msrx(struct pmf_cmd *cmd,
+                                     struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 mask = pmf_next32(cmd);
+       u32 shift = pmf_next32(cmd);
+       u32 xor = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_reg16_msrx(offset: %x, mask: %x, shift: %x,"
+                 " xor: %x\n", offset, mask, shift, xor);
+
+       PMF_PARSE_CALL(read_reg16_msrx, cmd, h, offset, mask, shift, xor);
+}
+static int pmf_parser_read_reg8_msrx(struct pmf_cmd *cmd,
+                                    struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 mask = pmf_next32(cmd);
+       u32 shift = pmf_next32(cmd);
+       u32 xor = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: read_reg8_msrx(offset: %x, mask: %x, shift: %x,"
+                 " xor: %x\n", offset, mask, shift, xor);
+
+       PMF_PARSE_CALL(read_reg8_msrx, cmd, h, offset, mask, shift, xor);
+}
+
+static int pmf_parser_write_reg32_slm(struct pmf_cmd *cmd,
+                                     struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 shift = pmf_next32(cmd);
+       u32 mask = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: write_reg32_slm(offset: %x, shift: %x, mask: %x\n",
+                 offset, shift, mask);
+
+       PMF_PARSE_CALL(write_reg32_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_write_reg16_slm(struct pmf_cmd *cmd,
+                                     struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 shift = pmf_next32(cmd);
+       u32 mask = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: write_reg16_slm(offset: %x, shift: %x, mask: %x\n",
+                 offset, shift, mask);
+
+       PMF_PARSE_CALL(write_reg16_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_write_reg8_slm(struct pmf_cmd *cmd,
+                                    struct pmf_handlers *h)
+{
+       u32 offset = pmf_next32(cmd);
+       u32 shift = pmf_next32(cmd);
+       u32 mask = pmf_next32(cmd);
+
+       LOG_PARSE("pmf: write_reg8_slm(offset: %x, shift: %x, mask: %x\n",
+                 offset, shift, mask);
+
+       PMF_PARSE_CALL(write_reg8_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_mask_and_compare(struct pmf_cmd *cmd,
+                                      struct pmf_handlers *h)
+{
+       u32 bytes = pmf_next32(cmd);
+       const void *maskblob = pmf_next_blob(cmd, bytes);
+       const void *valuesblob = pmf_next_blob(cmd, bytes);
+
+       LOG_PARSE("pmf: mask_and_compare(length: %ud ...\n", bytes);
+       LOG_BLOB("pmf:   mask data: \n", maskblob, bytes);
+       LOG_BLOB("pmf:   values data: \n", valuesblob, bytes);
+
+       PMF_PARSE_CALL(mask_and_compare, cmd, h,
+                      bytes, maskblob, valuesblob);
+}
+
+
+typedef int (*pmf_cmd_parser_t)(struct pmf_cmd *cmd, struct pmf_handlers *h);
+
+static pmf_cmd_parser_t pmf_parsers[PMF_CMD_COUNT] =
+{
+       NULL,
+       pmf_parser_write_gpio,
+       pmf_parser_read_gpio,
+       pmf_parser_write_reg32,
+       pmf_parser_read_reg32,
+       pmf_parser_write_reg16,
+       pmf_parser_read_reg16,
+       pmf_parser_write_reg8,
+       pmf_parser_read_reg8,
+       pmf_parser_delay,
+       pmf_parser_wait_reg32,
+       pmf_parser_wait_reg16,
+       pmf_parser_wait_reg8,
+       pmf_parser_read_i2c,
+       pmf_parser_write_i2c,
+       pmf_parser_rmw_i2c,
+       NULL, /* Bogus command */
+       NULL, /* Shift bytes right: NYI */
+       NULL, /* Shift bytes left: NYI */
+       pmf_parser_read_cfg,
+       pmf_parser_write_cfg,
+       pmf_parser_rmw_cfg,
+       pmf_parser_read_i2c_sub,
+       pmf_parser_write_i2c_sub,
+       pmf_parser_set_i2c_mode,
+       pmf_parser_rmw_i2c_sub,
+       pmf_parser_read_reg32_msrx,
+       pmf_parser_read_reg16_msrx,
+       pmf_parser_read_reg8_msrx,
+       pmf_parser_write_reg32_slm,
+       pmf_parser_write_reg16_slm,
+       pmf_parser_write_reg8_slm,
+       pmf_parser_mask_and_compare,
+};
+
+struct pmf_device {
+       struct list_head        link;
+       struct device_node      *node;
+       struct pmf_handlers     *handlers;
+       struct list_head        functions;
+       struct kref             ref;
+};
+
+static LIST_HEAD(pmf_devices);
+static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED;
+
+static void pmf_release_device(struct kref *kref)
+{
+       struct pmf_device *dev = container_of(kref, struct pmf_device, ref);
+       kfree(dev);
+}
+
+static inline void pmf_put_device(struct pmf_device *dev)
+{
+       kref_put(&dev->ref, pmf_release_device);
+}
+
+static inline struct pmf_device *pmf_get_device(struct pmf_device *dev)
+{
+       kref_get(&dev->ref);
+       return dev;
+}
+
+static inline struct pmf_device *pmf_find_device(struct device_node *np)
+{
+       struct pmf_device *dev;
+
+       list_for_each_entry(dev, &pmf_devices, link) {
+               if (dev->node == np)
+                       return pmf_get_device(dev);
+       }
+       return NULL;
+}
+
+static int pmf_parse_one(struct pmf_function *func,
+                        struct pmf_handlers *handlers,
+                        void *instdata, struct pmf_args *args)
+{
+       struct pmf_cmd cmd;
+       u32 ccode;
+       int count, rc;
+
+       cmd.cmdptr              = func->data;
+       cmd.cmdend              = func->data + func->length;
+       cmd.func                = func;
+       cmd.instdata            = instdata;
+       cmd.args                = args;
+       cmd.error               = 0;
+
+       LOG_PARSE("pmf: func %s, %d bytes, %s...\n",
+                 func->name, func->length,
+                 handlers ? "executing" : "parsing");
+
+       /* One subcommand to parse for now */
+       count = 1;
+
+       while(count-- && cmd.cmdptr < cmd.cmdend) {
+               /* Get opcode */
+               ccode = pmf_next32(&cmd);
+               /* Check if we are hitting a command list, fetch new count */
+               if (ccode == 0) {
+                       count = pmf_next32(&cmd) - 1;
+                       ccode = pmf_next32(&cmd);
+               }
+               if (cmd.error) {
+                       LOG_ERROR("pmf: parse error, not enough data\n");
+                       return -ENXIO;
+               }
+               if (ccode >= PMF_CMD_COUNT) {
+                       LOG_ERROR("pmf: command code %d unknown !\n", ccode);
+                       return -ENXIO;
+               }
+               if (pmf_parsers[ccode] == NULL) {
+                       LOG_ERROR("pmf: no parser for command %d !\n", ccode);
+                       return -ENXIO;
+               }
+               rc = pmf_parsers[ccode](&cmd, handlers);
+               if (rc != 0) {
+                       LOG_ERROR("pmf: parser for command %d returned"
+                                 " error %d\n", ccode, rc);
+                       return rc;
+               }
+       }
+
+       /* We are doing an initial parse pass, we need to adjust the size */
+       if (handlers == NULL)
+               func->length = cmd.cmdptr - func->data;
+
+       return 0;
+}
+
+static int pmf_add_function_prop(struct pmf_device *dev, void *driverdata,
+                                const char *name, u32 *data,
+                                unsigned int length)
+{
+       int count = 0;
+       struct pmf_function *func = NULL;
+
+       DBG("pmf: Adding functions for platform-do-%s\n", name);
+
+       while (length >= 12) {
+               /* Allocate a structure */
+               func = kzalloc(sizeof(struct pmf_function), GFP_KERNEL);
+               if (func == NULL)
+                       goto bail;
+               kref_init(&func->ref);
+               INIT_LIST_HEAD(&func->irq_clients);
+               func->node = dev->node;
+               func->driver_data = driverdata;
+               func->name = name;
+               func->phandle = data[0];
+               func->flags = data[1];
+               data += 2;
+               length -= 8;
+               func->data = data;
+               func->length = length;
+               func->dev = dev;
+               DBG("pmf: idx %d: flags=%08x, phandle=%08x "
+                   " %d bytes remaining, parsing...\n",
+                   count+1, func->flags, func->phandle, length);
+               if (pmf_parse_one(func, NULL, NULL, NULL)) {
+                       kfree(func);
+                       goto bail;
+               }
+               length -= func->length;
+               data = (u32 *)(((u8 *)data) + func->length);
+               list_add(&func->link, &dev->functions);
+               pmf_get_device(dev);
+               count++;
+       }
+ bail:
+       DBG("pmf: Added %d functions\n", count);
+
+       return count;
+}
+
+static int pmf_add_functions(struct pmf_device *dev, void *driverdata)
+{
+       struct property *pp;
+#define PP_PREFIX "platform-do-"
+       const int plen = strlen(PP_PREFIX);
+       int count = 0;
+
+       for (pp = dev->node->properties; pp != 0; pp = pp->next) {
+               char *name;
+               if (strncmp(pp->name, PP_PREFIX, plen) != 0)
+                       continue;
+               name = pp->name + plen;
+               if (strlen(name) && pp->length >= 12)
+                       count += pmf_add_function_prop(dev, driverdata, name,
+                                                      (u32 *)pp->value,
+                                                      pp->length);
+       }
+       return count;
+}
+
+
+int pmf_register_driver(struct device_node *np,
+                       struct pmf_handlers *handlers,
+                       void *driverdata)
+{
+       struct pmf_device *dev;
+       unsigned long flags;
+       int rc = 0;
+
+       if (handlers == NULL)
+               return -EINVAL;
+
+       DBG("pmf: registering driver for node %s\n", np->full_name);
+
+       spin_lock_irqsave(&pmf_lock, flags);
+       dev = pmf_find_device(np);
+       spin_unlock_irqrestore(&pmf_lock, flags);
+       if (dev != NULL) {
+               DBG("pmf: already there !\n");
+               pmf_put_device(dev);
+               return -EBUSY;
+       }
+
+       dev = kzalloc(sizeof(struct pmf_device), GFP_KERNEL);
+       if (dev == NULL) {
+               DBG("pmf: no memory !\n");
+               return -ENOMEM;
+       }
+       kref_init(&dev->ref);
+       dev->node = of_node_get(np);
+       dev->handlers = handlers;
+       INIT_LIST_HEAD(&dev->functions);
+
+       rc = pmf_add_functions(dev, driverdata);
+       if (rc == 0) {
+               DBG("pmf: no functions, disposing.. \n");
+               of_node_put(np);
+               kfree(dev);
+               return -ENODEV;
+       }
+
+       spin_lock_irqsave(&pmf_lock, flags);
+       list_add(&dev->link, &pmf_devices);
+       spin_unlock_irqrestore(&pmf_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pmf_register_driver);
+
+struct pmf_function *pmf_get_function(struct pmf_function *func)
+{
+       if (!try_module_get(func->dev->handlers->owner))
+               return NULL;
+       kref_get(&func->ref);
+       return func;
+}
+EXPORT_SYMBOL_GPL(pmf_get_function);
+
+static void pmf_release_function(struct kref *kref)
+{
+       struct pmf_function *func =
+               container_of(kref, struct pmf_function, ref);
+       pmf_put_device(func->dev);
+       kfree(func);
+}
+
+static inline void __pmf_put_function(struct pmf_function *func)
+{
+       kref_put(&func->ref, pmf_release_function);
+}
+
+void pmf_put_function(struct pmf_function *func)
+{
+       if (func == NULL)
+               return;
+       module_put(func->dev->handlers->owner);
+       __pmf_put_function(func);
+}
+EXPORT_SYMBOL_GPL(pmf_put_function);
+
+void pmf_unregister_driver(struct device_node *np)
+{
+       struct pmf_device *dev;
+       unsigned long flags;
+
+       DBG("pmf: unregistering driver for node %s\n", np->full_name);
+
+       spin_lock_irqsave(&pmf_lock, flags);
+       dev = pmf_find_device(np);
+       if (dev == NULL) {
+               DBG("pmf: not such driver !\n");
+               spin_unlock_irqrestore(&pmf_lock, flags);
+               return;
+       }
+       list_del(&dev->link);
+
+       while(!list_empty(&dev->functions)) {
+               struct pmf_function *func =
+                       list_entry(dev->functions.next, typeof(*func), link);
+               list_del(&func->link);
+               __pmf_put_function(func);
+       }
+
+       pmf_put_device(dev);
+       spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_unregister_driver);
+
+struct pmf_function *__pmf_find_function(struct device_node *target,
+                                        const char *name, u32 flags)
+{
+       struct device_node *actor = of_node_get(target);
+       struct pmf_device *dev;
+       struct pmf_function *func, *result = NULL;
+       char fname[64];
+       u32 *prop, ph;
+
+       /*
+        * Look for a "platform-*" function reference. If we can't find
+        * one, then we fallback to a direct call attempt
+        */
+       snprintf(fname, 63, "platform-%s", name);
+       prop = (u32 *)get_property(target, fname, NULL);
+       if (prop == NULL)
+               goto find_it;
+       ph = *prop;
+       if (ph == 0)
+               goto find_it;
+
+       /*
+        * Ok, now try to find the actor. If we can't find it, we fail,
+        * there is no point in falling back there
+        */
+       of_node_put(actor);
+       actor = of_find_node_by_phandle(ph);
+       if (actor == NULL)
+               return NULL;
+ find_it:
+       dev = pmf_find_device(actor);
+       if (dev == NULL)
+               return NULL;
+
+       list_for_each_entry(func, &dev->functions, link) {
+               if (name && strcmp(name, func->name))
+                       continue;
+               if (func->phandle && target->node != func->phandle)
+                       continue;
+               if ((func->flags & flags) == 0)
+                       continue;
+               result = func;
+               break;
+       }
+       of_node_put(actor);
+       pmf_put_device(dev);
+       return result;
+}
+
+
+int pmf_register_irq_client(struct device_node *target,
+                           const char *name,
+                           struct pmf_irq_client *client)
+{
+       struct pmf_function *func;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmf_lock, flags);
+       func = __pmf_find_function(target, name, PMF_FLAGS_INT_GEN);
+       if (func == NULL) {
+               spin_unlock_irqrestore(&pmf_lock, flags);
+               return -ENODEV;
+       }
+       list_add(&client->link, &func->irq_clients);
+       spin_unlock_irqrestore(&pmf_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pmf_register_irq_client);
+
+void pmf_unregister_irq_client(struct device_node *np,
+                             const char *name,
+                             struct pmf_irq_client *client)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmf_lock, flags);
+       list_del(&client->link);
+       spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_unregister_irq_client);
+
+
+void pmf_do_irq(struct pmf_function *func)
+{
+       unsigned long flags;
+       struct pmf_irq_client *client;
+
+       /* For now, using a spinlock over the whole function. Can be made
+        * to drop the lock using 2 lists if necessary
+        */
+       spin_lock_irqsave(&pmf_lock, flags);
+       list_for_each_entry(client, &func->irq_clients, link) {
+               if (!try_module_get(client->owner))
+                       continue;
+               client->handler(client->data);
+               module_put(client->owner);
+       }
+       spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_do_irq);
+
+
+int pmf_call_one(struct pmf_function *func, struct pmf_args *args)
+{
+       struct pmf_device *dev = func->dev;
+       void *instdata = NULL;
+       int rc = 0;
+
+       DBG(" ** pmf_call_one(%s/%s) **\n", dev->node->full_name, func->name);
+
+       if (dev->handlers->begin)
+               instdata = dev->handlers->begin(func, args);
+       rc = pmf_parse_one(func, dev->handlers, instdata, args);
+       if (dev->handlers->end)
+               dev->handlers->end(func, instdata);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_call_one);
+
+int pmf_do_functions(struct device_node *np, const char *name,
+                    u32 phandle, u32 fflags, struct pmf_args *args)
+{
+       struct pmf_device *dev;
+       struct pmf_function *func, *tmp;
+       unsigned long flags;
+       int rc = -ENODEV;
+
+       spin_lock_irqsave(&pmf_lock, flags);
+
+       dev = pmf_find_device(np);
+       if (dev == NULL) {
+               spin_unlock_irqrestore(&pmf_lock, flags);
+               return -ENODEV;
+       }
+       list_for_each_entry_safe(func, tmp, &dev->functions, link) {
+               if (name && strcmp(name, func->name))
+                       continue;
+               if (phandle && func->phandle && phandle != func->phandle)
+                       continue;
+               if ((func->flags & fflags) == 0)
+                       continue;
+               if (pmf_get_function(func) == NULL)
+                       continue;
+               spin_unlock_irqrestore(&pmf_lock, flags);
+               rc = pmf_call_one(func, args);
+               pmf_put_function(func);
+               spin_lock_irqsave(&pmf_lock, flags);
+       }
+       pmf_put_device(dev);
+       spin_unlock_irqrestore(&pmf_lock, flags);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_do_functions);
+
+
+struct pmf_function *pmf_find_function(struct device_node *target,
+                                      const char *name)
+{
+       struct pmf_function *func;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmf_lock, flags);
+       func = __pmf_find_function(target, name, PMF_FLAGS_ON_DEMAND);
+       if (func)
+               func = pmf_get_function(func);
+       spin_unlock_irqrestore(&pmf_lock, flags);
+       return func;
+}
+EXPORT_SYMBOL_GPL(pmf_find_function);
+
+int pmf_call_function(struct device_node *target, const char *name,
+                     struct pmf_args *args)
+{
+       struct pmf_function *func = pmf_find_function(target, name);
+       int rc;
+
+       if (func == NULL)
+               return -ENODEV;
+
+       rc = pmf_call_one(func, args);
+       pmf_put_function(func);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_call_function);
+
index 90040c49494d62ce94d900d7e2380a7be15979c3..18bf3011d1e3ff103675b0bae793570f4c82606d 100644 (file)
@@ -5,8 +5,8 @@
  *  in a separate file
  *
  *  Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
- *
- *  Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *  Copyright (C) 2005 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *                     IBM, Corp.
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -54,12 +54,7 @@ struct pmac_irq_hw {
 };
 
 /* Default addresses */
-static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
-        (struct pmac_irq_hw *) 0xf3000020,
-        (struct pmac_irq_hw *) 0xf3000010,
-        (struct pmac_irq_hw *) 0xf4000020,
-        (struct pmac_irq_hw *) 0xf4000010,
-};
+static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4];
 
 #define GC_LEVEL_MASK          0x3ff00000
 #define OHARE_LEVEL_MASK       0x1ff00000
@@ -82,8 +77,7 @@ static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
  * since it can lose interrupts (see pmac_set_irq_mask).
  * -- Cort
  */
-void
-__set_lost(unsigned long irq_nr, int nokick)
+void __set_lost(unsigned long irq_nr, int nokick)
 {
        if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
                atomic_inc(&ppc_n_lost_interrupts);
@@ -92,8 +86,7 @@ __set_lost(unsigned long irq_nr, int nokick)
        }
 }
 
-static void
-pmac_mask_and_ack_irq(unsigned int irq_nr)
+static void pmac_mask_and_ack_irq(unsigned int irq_nr)
 {
         unsigned long bit = 1UL << (irq_nr & 0x1f);
         int i = irq_nr >> 5;
@@ -224,8 +217,7 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
        return IRQ_NONE;
 }
 
-int
-pmac_get_irq(struct pt_regs *regs)
+static int pmac_get_irq(struct pt_regs *regs)
 {
        int irq;
        unsigned long bits = 0;
@@ -256,34 +248,40 @@ pmac_get_irq(struct pt_regs *regs)
 
 /* This routine will fix some missing interrupt values in the device tree
  * on the gatwick mac-io controller used by some PowerBooks
+ *
+ * Walking of OF nodes could use a bit more fixing up here, but it's not
+ * very important as this is all boot time code on static portions of the
+ * device-tree.
+ *
+ * However, the modifications done to "intrs" will have to be removed and
+ * replaced with proper updates of the "interrupts" properties or
+ * AAPL,interrupts, yet to be decided, once the dynamic parsing is there.
  */
-static void __init
-pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+static void __init pmac_fix_gatwick_interrupts(struct device_node *gw,
+                                              int irq_base)
 {
        struct device_node *node;
        int count;
 
        memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
-       node = gw->child;
        count = 0;
-       while(node)
-       {
+       for (node = NULL; (node = of_get_next_child(gw, node)) != NULL;) {
                /* Fix SCC */
-               if (strcasecmp(node->name, "escc") == 0)
-                       if (node->child) {
-                               if (node->child->n_intrs < 3) {
-                                       node->child->intrs = &gatwick_int_pool[count];
-                                       count += 3;
-                               }
-                               node->child->n_intrs = 3;
-                               node->child->intrs[0].line = 15+irq_base;
-                               node->child->intrs[1].line =  4+irq_base;
-                               node->child->intrs[2].line =  5+irq_base;
-                               printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
-                                       node->child->intrs[0].line,
-                                       node->child->intrs[1].line,
-                                       node->child->intrs[2].line);
+               if ((strcasecmp(node->name, "escc") == 0) && node->child) {
+                       if (node->child->n_intrs < 3) {
+                               node->child->intrs = &gatwick_int_pool[count];
+                               count += 3;
                        }
+                       node->child->n_intrs = 3;
+                       node->child->intrs[0].line = 15+irq_base;
+                       node->child->intrs[1].line =  4+irq_base;
+                       node->child->intrs[2].line =  5+irq_base;
+                       printk(KERN_INFO "irq: fixed SCC on gatwick"
+                              " (%d,%d,%d)\n",
+                              node->child->intrs[0].line,
+                              node->child->intrs[1].line,
+                              node->child->intrs[2].line);
+               }
                /* Fix media-bay & left SWIM */
                if (strcasecmp(node->name, "media-bay") == 0) {
                        struct device_node* ya_node;
@@ -292,12 +290,11 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
                                node->intrs = &gatwick_int_pool[count++];
                        node->n_intrs = 1;
                        node->intrs[0].line = 29+irq_base;
-                       printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
-                                       node->intrs[0].line);
+                       printk(KERN_INFO "irq: fixed media-bay on gatwick"
+                              " (%d)\n", node->intrs[0].line);
 
                        ya_node = node->child;
-                       while(ya_node)
-                       {
+                       while(ya_node) {
                                if (strcasecmp(ya_node->name, "floppy") == 0) {
                                        if (ya_node->n_intrs < 2) {
                                                ya_node->intrs = &gatwick_int_pool[count];
@@ -323,7 +320,6 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
                                ya_node = ya_node->sibling;
                        }
                }
-               node = node->sibling;
        }
        if (count > 10) {
                printk("WARNING !! Gatwick interrupt pool overflow\n");
@@ -338,45 +334,41 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
  * controller.  If we find this second ohare, set it up and fix the
  * interrupt value in the device tree for the ethernet chip.
  */
-static int __init enable_second_ohare(void)
+static void __init enable_second_ohare(struct device_node *np)
 {
        unsigned char bus, devfn;
        unsigned short cmd;
-        unsigned long addr;
-       struct device_node *irqctrler = find_devices("pci106b,7");
        struct device_node *ether;
 
-       if (irqctrler == NULL || irqctrler->n_addrs <= 0)
-               return -1;
-       addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
-       pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
-       max_irqs = 64;
-       if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
-               struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
-               if (!hose)
-                   printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
-               else {
-                   early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
-                   cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-                   cmd &= ~PCI_COMMAND_IO;
-                   early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
+       /* This code doesn't strictly belong here, it could be part of
+        * either the PCI initialisation or the feature code. It's kept
+        * here for historical reasons.
+        */
+       if (pci_device_from_OF_node(np, &bus, &devfn) == 0) {
+               struct pci_controller* hose =
+                       pci_find_hose_for_OF_device(np);
+               if (!hose) {
+                       printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+                       return;
                }
+               early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
+               cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+               cmd &= ~PCI_COMMAND_IO;
+               early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
        }
 
        /* Fix interrupt for the modem/ethernet combo controller. The number
-          in the device tree (27) is bogus (correct for the ethernet-only
-          board but not the combo ethernet/modem board).
-          The real interrupt is 28 on the second controller -> 28+32 = 60.
-       */
-       ether = find_devices("pci1011,14");
+        * in the device tree (27) is bogus (correct for the ethernet-only
+        * board but not the combo ethernet/modem board).
+        * The real interrupt is 28 on the second controller -> 28+32 = 60.
+        */
+       ether = of_find_node_by_name(NULL, "pci1011,14");
        if (ether && ether->n_intrs > 0) {
                ether->intrs[0].line = 60;
                printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
                       ether->intrs[0].line);
        }
-
-       /* Return the interrupt number of the cascade */
-       return irqctrler->intrs[0].line;
+       of_node_put(ether);
 }
 
 #ifdef CONFIG_XMON
@@ -394,189 +386,251 @@ static struct irqaction gatwick_cascade_action = {
        .mask           = CPU_MASK_NONE,
        .name           = "cascade",
 };
-#endif /* CONFIG_PPC32 */
 
-static int pmac_u3_cascade(struct pt_regs *regs, void *data)
+static void __init pmac_pic_probe_oldstyle(void)
 {
-       return mpic_get_one_irq((struct mpic *)data, regs);
-}
-
-void __init pmac_pic_init(void)
-{
-        struct device_node *irqctrler  = NULL;
-        struct device_node *irqctrler2 = NULL;
-       struct device_node *np;
-#ifdef CONFIG_PPC32
         int i;
-        unsigned long addr;
        int irq_cascade = -1;
-#endif
-       struct mpic *mpic1, *mpic2;
+        struct device_node *master = NULL;
+       struct device_node *slave = NULL;
+       u8 __iomem *addr;
+       struct resource r;
 
-       /* We first try to detect Apple's new Core99 chipset, since mac-io
-        * is quite different on those machines and contains an IBM MPIC2.
-        */
-       np = find_type_devices("open-pic");
-       while (np) {
-               if (np->parent && !strcmp(np->parent->name, "u3"))
-                       irqctrler2 = np;
-               else
-                       irqctrler = np;
-               np = np->next;
-       }
-       if (irqctrler != NULL && irqctrler->n_addrs > 0) {
-               unsigned char senses[128];
-
-               printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
-                      (unsigned int)irqctrler->addrs[0].address);
-               pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
-
-               prom_get_irq_senses(senses, 0, 128);
-               mpic1 = mpic_alloc(irqctrler->addrs[0].address,
-                                  MPIC_PRIMARY | MPIC_WANTS_RESET,
-                                  0, 0, 128, 252, senses, 128, " OpenPIC  ");
-               BUG_ON(mpic1 == NULL);
-               mpic_init(mpic1);               
-
-               if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
-                   irqctrler2->n_addrs > 0) {
-                       printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
-                              (u32)irqctrler2->addrs[0].address,
-                              irqctrler2->intrs[0].line);
-
-                       pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
-                       prom_get_irq_senses(senses, 128, 128 + 124);
-
-                       /* We don't need to set MPIC_BROKEN_U3 here since we don't have
-                        * hypertransport interrupts routed to it
-                        */
-                       mpic2 = mpic_alloc(irqctrler2->addrs[0].address,
-                                          MPIC_BIG_ENDIAN | MPIC_WANTS_RESET,
-                                          0, 128, 124, 0, senses, 124,
-                                          " U3-MPIC  ");
-                       BUG_ON(mpic2 == NULL);
-                       mpic_init(mpic2);
-                       mpic_setup_cascade(irqctrler2->intrs[0].line,
-                                          pmac_u3_cascade, mpic2);
-               }
-#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
-               {
-                       struct device_node* pswitch;
-                       int nmi_irq;
-
-                       pswitch = find_devices("programmer-switch");
-                       if (pswitch && pswitch->n_intrs) {
-                               nmi_irq = pswitch->intrs[0].line;
-                               mpic_irq_set_priority(nmi_irq, 9);
-                               setup_irq(nmi_irq, &xmon_action);
-                       }
-               }
-#endif /* CONFIG_XMON */
-               return;
-       }
-       irqctrler = NULL;
+       /* Set our get_irq function */
+       ppc_md.get_irq = pmac_get_irq;
 
-#ifdef CONFIG_PPC32
-       /* Get the level/edge settings, assume if it's not
-        * a Grand Central nor an OHare, then it's an Heathrow
-        * (or Paddington).
+       /*
+        * Find the interrupt controller type & node
         */
-       ppc_md.get_irq = pmac_get_irq;
-       if (find_devices("gc"))
+
+       if ((master = of_find_node_by_name(NULL, "gc")) != NULL) {
+               max_irqs = max_real_irqs = 32;
                level_mask[0] = GC_LEVEL_MASK;
-       else if (find_devices("ohare")) {
+       } else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) {
+               max_irqs = max_real_irqs = 32;
                level_mask[0] = OHARE_LEVEL_MASK;
+
                /* We might have a second cascaded ohare */
-               level_mask[1] = OHARE_LEVEL_MASK;
-       } else {
+               slave = of_find_node_by_name(NULL, "pci106b,7");
+               if (slave) {
+                       max_irqs = 64;
+                       level_mask[1] = OHARE_LEVEL_MASK;
+                       enable_second_ohare(slave);
+               }
+       } else if ((master = of_find_node_by_name(NULL, "mac-io")) != NULL) {
+               max_irqs = max_real_irqs = 64;
                level_mask[0] = HEATHROW_LEVEL_MASK;
                level_mask[1] = 0;
+
                /* We might have a second cascaded heathrow */
-               level_mask[2] = HEATHROW_LEVEL_MASK;
-               level_mask[3] = 0;
-       }
+               slave = of_find_node_by_name(master, "mac-io");
+
+               /* Check ordering of master & slave */
+               if (device_is_compatible(master, "gatwick")) {
+                       struct device_node *tmp;
+                       BUG_ON(slave == NULL);
+                       tmp = master;
+                       master = slave;
+                       slave = tmp;
+               }
 
-       /*
-        * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
-        * 1998 G3 Series PowerBooks have 128,
-        * other powermacs have 32.
-        * The combo ethernet/modem card for the Powerstar powerbooks
-        * (2400/3400/3500, ohare based) has a second ohare chip
-        * effectively making a total of 64.
-        */
-       max_irqs = max_real_irqs = 32;
-       irqctrler = find_devices("mac-io");
-       if (irqctrler)
-       {
-               max_real_irqs = 64;
-               if (irqctrler->next)
+               /* We found a slave */
+               if (slave) {
                        max_irqs = 128;
-               else
-                       max_irqs = 64;
+                       level_mask[2] = HEATHROW_LEVEL_MASK;
+                       level_mask[3] = 0;
+                       pmac_fix_gatwick_interrupts(slave, max_real_irqs);
+               }
        }
+       BUG_ON(master == NULL);
+
+       /* Set the handler for the main PIC */
        for ( i = 0; i < max_real_irqs ; i++ )
                irq_desc[i].handler = &pmac_pic;
 
-       /* get addresses of first controller */
-       if (irqctrler) {
-               if  (irqctrler->n_addrs > 0) {
-                       addr = (unsigned long)
-                               ioremap(irqctrler->addrs[0].address, 0x40);
-                       for (i = 0; i < 2; ++i)
-                               pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-                                       (addr + (2 - i) * 0x10);
-               }
+       /* Get addresses of first controller if we have a node for it */
+       BUG_ON(of_address_to_resource(master, 0, &r));
 
-               /* get addresses of second controller */
-               irqctrler = irqctrler->next;
-               if (irqctrler && irqctrler->n_addrs > 0) {
-                       addr = (unsigned long)
-                               ioremap(irqctrler->addrs[0].address, 0x40);
-                       for (i = 2; i < 4; ++i)
-                               pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-                                       (addr + (4 - i) * 0x10);
-                       irq_cascade = irqctrler->intrs[0].line;
-                       if (device_is_compatible(irqctrler, "gatwick"))
-                               pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-               }
-       } else {
-               /* older powermacs have a GC (grand central) or ohare at
-                  f3000000, with interrupt control registers at f3000020. */
-               addr = (unsigned long) ioremap(0xf3000000, 0x40);
-               pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
+       /* Map interrupts of primary controller */
+       addr = (u8 __iomem *) ioremap(r.start, 0x40);
+       i = 0;
+       pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+               (addr + 0x20);
+       if (max_real_irqs > 32)
+               pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+                       (addr + 0x10);
+       of_node_put(master);
+
+       printk(KERN_INFO "irq: Found primary Apple PIC %s for %d irqs\n",
+              master->full_name, max_real_irqs);
+
+       /* Map interrupts of cascaded controller */
+       if (slave && !of_address_to_resource(slave, 0, &r)) {
+               addr = (u8 __iomem *)ioremap(r.start, 0x40);
+               pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+                       (addr + 0x20);
+               if (max_irqs > 64)
+                       pmac_irq_hw[i++] =
+                               (volatile struct pmac_irq_hw __iomem *)
+                               (addr + 0x10);
+               irq_cascade = slave->intrs[0].line;
+
+               printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"
+                      " cascade: %d\n", slave->full_name,
+                      max_irqs - max_real_irqs, irq_cascade);
        }
-
-       /* PowerBooks 3400 and 3500 can have a second controller in a second
-          ohare chip, on the combo ethernet/modem card */
-       if (machine_is_compatible("AAPL,3400/2400")
-            || machine_is_compatible("AAPL,3500"))
-               irq_cascade = enable_second_ohare();
+       of_node_put(slave);
 
        /* disable all interrupts in all controllers */
        for (i = 0; i * 32 < max_irqs; ++i)
                out_le32(&pmac_irq_hw[i]->enable, 0);
+
        /* mark level interrupts */
        for (i = 0; i < max_irqs; i++)
                if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
                        irq_desc[i].status = IRQ_LEVEL;
 
-       /* get interrupt line of secondary interrupt controller */
-       if (irq_cascade >= 0) {
-               printk(KERN_INFO "irq: secondary controller on irq %d\n",
-                       (int)irq_cascade);
+       /* Setup handlers for secondary controller and hook cascade irq*/
+       if (slave) {
                for ( i = max_real_irqs ; i < max_irqs ; i++ )
                        irq_desc[i].handler = &gatwick_pic;
                setup_irq(irq_cascade, &gatwick_cascade_action);
        }
-       printk("System has %d possible interrupts\n", max_irqs);
-       if (max_irqs != max_real_irqs)
-               printk(KERN_DEBUG "%d interrupts on main controller\n",
-                       max_real_irqs);
-
+       printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
 #ifdef CONFIG_XMON
        setup_irq(20, &xmon_action);
-#endif /* CONFIG_XMON */
-#endif /* CONFIG_PPC32 */
+#endif
+}
+#endif /* CONFIG_PPC32 */
+
+static int pmac_u3_cascade(struct pt_regs *regs, void *data)
+{
+       return mpic_get_one_irq((struct mpic *)data, regs);
+}
+
+static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
+{
+#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
+       struct device_node* pswitch;
+       int nmi_irq;
+
+       pswitch = of_find_node_by_name(NULL, "programmer-switch");
+       if (pswitch && pswitch->n_intrs) {
+               nmi_irq = pswitch->intrs[0].line;
+               mpic_irq_set_priority(nmi_irq, 9);
+               setup_irq(nmi_irq, &xmon_action);
+       }
+       of_node_put(pswitch);
+#endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */
+}
+
+static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
+                                               int master)
+{
+       unsigned char senses[128];
+       int offset = master ? 0 : 128;
+       int count = master ? 128 : 124;
+       const char *name = master ? " MPIC 1   " : " MPIC 2   ";
+       struct resource r;
+       struct mpic *mpic;
+       unsigned int flags = master ? MPIC_PRIMARY : 0;
+       int rc;
+
+       rc = of_address_to_resource(np, 0, &r);
+       if (rc)
+               return NULL;
+
+       pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
+
+       prom_get_irq_senses(senses, offset, offset + count);
+
+       flags |= MPIC_WANTS_RESET;
+       if (get_property(np, "big-endian", NULL))
+               flags |= MPIC_BIG_ENDIAN;
+
+       /* Primary Big Endian means HT interrupts. This is quite dodgy
+        * but works until I find a better way
+        */
+       if (master && (flags & MPIC_BIG_ENDIAN))
+               flags |= MPIC_BROKEN_U3;
+
+       mpic = mpic_alloc(r.start, flags, 0, offset, count, master ? 252 : 0,
+                         senses, count, name);
+       if (mpic == NULL)
+               return NULL;
+
+       mpic_init(mpic);
+
+       return mpic;
+ }
+
+static int __init pmac_pic_probe_mpic(void)
+{
+       struct mpic *mpic1, *mpic2;
+       struct device_node *np, *master = NULL, *slave = NULL;
+
+       /* We can have up to 2 MPICs cascaded */
+       for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
+                    != NULL;) {
+               if (master == NULL &&
+                   get_property(np, "interrupts", NULL) == NULL)
+                       master = of_node_get(np);
+               else if (slave == NULL)
+                       slave = of_node_get(np);
+               if (master && slave)
+                       break;
+       }
+
+       /* Check for bogus setups */
+       if (master == NULL && slave != NULL) {
+               master = slave;
+               slave = NULL;
+       }
+
+       /* Not found, default to good old pmac pic */
+       if (master == NULL)
+               return -ENODEV;
+
+       /* Set master handler */
+       ppc_md.get_irq = mpic_get_irq;
+
+       /* Setup master */
+       mpic1 = pmac_setup_one_mpic(master, 1);
+       BUG_ON(mpic1 == NULL);
+
+       /* Install NMI if any */
+       pmac_pic_setup_mpic_nmi(mpic1);
+
+       of_node_put(master);
+
+       /* No slave, let's go out */
+       if (slave == NULL || slave->n_intrs < 1)
+               return 0;
+
+       mpic2 = pmac_setup_one_mpic(slave, 0);
+       if (mpic2 == NULL) {
+               printk(KERN_ERR "Failed to setup slave MPIC\n");
+               of_node_put(slave);
+               return 0;
+       }
+       mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2);
+
+       of_node_put(slave);
+       return 0;
+}
+
+
+void __init pmac_pic_init(void)
+{
+       /* We first try to detect Apple's new Core99 chipset, since mac-io
+        * is quite different on those machines and contains an IBM MPIC2.
+        */
+       if (pmac_pic_probe_mpic() == 0)
+               return;
+
+#ifdef CONFIG_PPC32
+       pmac_pic_probe_oldstyle();
+#endif
 }
 
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
index 2ad25e13423ea042bdc2dc05519c0e649209da1d..21c7b0f8f32996ce7038911f28608d15169887a8 100644 (file)
@@ -42,10 +42,6 @@ extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
        unsigned long data_port, unsigned long ctrl_port, int *irq);
 
 extern int pmac_nvram_init(void);
-
-extern struct hw_interrupt_type pmac_pic;
-
-void pmac_pic_init(void);
-int pmac_get_irq(struct pt_regs *regs);
+extern void pmac_pic_init(void);
 
 #endif /* __PMAC_H__ */
index 7acb0546671fe2ea341c604573e541bd8d06cad9..3b1a9d4fcbc6c7ff1789960baa9b304f833c21e4 100644 (file)
@@ -60,6 +60,7 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
+#include <asm/kexec.h>
 #include <asm/pci-bridge.h>
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
@@ -74,8 +75,8 @@
 #include <asm/iommu.h>
 #include <asm/smu.h>
 #include <asm/pmc.h>
-#include <asm/mpic.h>
 #include <asm/lmb.h>
+#include <asm/udbg.h>
 
 #include "pmac.h"
 
@@ -321,16 +322,6 @@ void __init pmac_setup_arch(void)
        l2cr_init();
 #endif /* CONFIG_PPC32 */
 
-#ifdef CONFIG_PPC64
-       /* Probe motherboard chipset */
-       /* this is done earlier in setup_arch for 32-bit */
-       pmac_feature_init();
-
-       /* We can NAP */
-       powersave_nap = 1;
-       printk(KERN_INFO "Using native/NAP idle loop\n");
-#endif
-
 #ifdef CONFIG_KGDB
        zs_kgdb_hook(0);
 #endif
@@ -354,7 +345,7 @@ void __init pmac_setup_arch(void)
 
 #ifdef CONFIG_SMP
        /* Check for Core99 */
-       if (find_devices("uni-n") || find_devices("u3"))
+       if (find_devices("uni-n") || find_devices("u3") || find_devices("u4"))
                smp_ops = &core99_smp_ops;
 #ifdef CONFIG_PPC32
        else
@@ -621,35 +612,31 @@ static void __init pmac_init_early(void)
         * and call ioremap
         */
        hpte_init_native();
+#endif
 
-       /* Init SCC */
-       if (strstr(cmd_line, "sccdbg")) {
-               sccdbg = 1;
-               udbg_init_scc(NULL);
+       /* Enable early btext debug if requested */
+       if (strstr(cmd_line, "btextdbg")) {
+               udbg_adb_init_early();
+               register_early_udbg_console();
        }
 
-       /* Setup interrupt mapping options */
-       ppc64_interrupt_controller = IC_OPEN_PIC;
+       /* Probe motherboard chipset */
+       pmac_feature_init();
 
-       iommu_init_early_u3();
-#endif
-}
+       /* We can NAP */
+       powersave_nap = 1;
+       printk(KERN_INFO "Using native/NAP idle loop\n");
+
+       /* Initialize debug stuff */
+       udbg_scc_init(!!strstr(cmd_line, "sccdbg"));
+       udbg_adb_init(!!strstr(cmd_line, "btextdbg"));
 
-static void __init pmac_progress(char *s, unsigned short hex)
-{
 #ifdef CONFIG_PPC64
-       if (sccdbg) {
-               udbg_puts(s);
-               udbg_puts("\n");
-               return;
-       }
+       /* Setup interrupt mapping options */
+       ppc64_interrupt_controller = IC_OPEN_PIC;
+
+       iommu_init_early_dart();
 #endif
-#ifdef CONFIG_BOOTX_TEXT
-       if (boot_text_mapped) {
-               btext_drawstring(s);
-               btext_drawchar('\n');
-       }
-#endif /* CONFIG_BOOTX_TEXT */
 }
 
 /*
@@ -663,35 +650,14 @@ static int pmac_check_legacy_ioport(unsigned int baseport)
 
 static int __init pmac_declare_of_platform_devices(void)
 {
-       struct device_node *np, *npp;
-
-       np = find_devices("uni-n");
-       if (np) {
-               for (np = np->child; np != NULL; np = np->sibling)
-                       if (strncmp(np->name, "i2c", 3) == 0) {
-                               of_platform_device_create(np, "uni-n-i2c",
-                                                         NULL);
-                               break;
-                       }
-       }
-       np = find_devices("valkyrie");
+       struct device_node *np;
+
+       np = of_find_node_by_name(NULL, "valkyrie");
        if (np)
                of_platform_device_create(np, "valkyrie", NULL);
-       np = find_devices("platinum");
+       np = of_find_node_by_name(NULL, "platinum");
        if (np)
                of_platform_device_create(np, "platinum", NULL);
-
-       npp = of_find_node_by_name(NULL, "u3");
-       if (npp) {
-               for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) {
-                       if (strncmp(np->name, "i2c", 3) == 0) {
-                               of_platform_device_create(np, "u3-i2c", NULL);
-                               of_node_put(np);
-                               break;
-                       }
-               }
-               of_node_put(npp);
-       }
         np = of_find_node_by_type(NULL, "smu");
         if (np) {
                of_platform_device_create(np, "smu", NULL);
@@ -718,7 +684,7 @@ static int __init pmac_probe(int platform)
         * occupies having to be broken up so the DART itself is not
         * part of the cacheable linar mapping
         */
-       alloc_u3_dart_table();
+       alloc_dart_table();
 #endif
 
 #ifdef CONFIG_PMAC_SMU
@@ -734,15 +700,17 @@ static int __init pmac_probe(int platform)
 }
 
 #ifdef CONFIG_PPC64
-static int pmac_probe_mode(struct pci_bus *bus)
+/* Move that to pci.c */
+static int pmac_pci_probe_mode(struct pci_bus *bus)
 {
        struct device_node *node = bus->sysdata;
 
        /* We need to use normal PCI probing for the AGP bus,
-          since the device for the AGP bridge isn't in the tree. */
-       if (bus->self == NULL && device_is_compatible(node, "u3-agp"))
+        * since the device for the AGP bridge isn't in the tree.
+        */
+       if (bus->self == NULL && (device_is_compatible(node, "u3-agp") ||
+                                 device_is_compatible(node, "u4-pcie")))
                return PCI_PROBE_NORMAL;
-
        return PCI_PROBE_DEVTREE;
 }
 #endif
@@ -756,7 +724,7 @@ struct machdep_calls __initdata pmac_md = {
        .init_early             = pmac_init_early,
        .show_cpuinfo           = pmac_show_cpuinfo,
        .init_IRQ               = pmac_pic_init,
-       .get_irq                = mpic_get_irq, /* changed later */
+       .get_irq                = NULL, /* changed later */
        .pcibios_fixup          = pmac_pcibios_fixup,
        .restart                = pmac_restart,
        .power_off              = pmac_power_off,
@@ -768,12 +736,17 @@ struct machdep_calls __initdata pmac_md = {
        .calibrate_decr         = pmac_calibrate_decr,
        .feature_call           = pmac_do_feature_call,
        .check_legacy_ioport    = pmac_check_legacy_ioport,
-       .progress               = pmac_progress,
+       .progress               = udbg_progress,
 #ifdef CONFIG_PPC64
-       .pci_probe_mode         = pmac_probe_mode,
+       .pci_probe_mode         = pmac_pci_probe_mode,
        .idle_loop              = native_idle,
        .enable_pmcs            = power4_enable_pmcs,
+#ifdef CONFIG_KEXEC
+       .machine_kexec          = default_machine_kexec,
+       .machine_kexec_prepare  = default_machine_kexec_prepare,
+       .machine_crash_shutdown = default_machine_crash_shutdown,
 #endif
+#endif /* CONFIG_PPC64 */
 #ifdef CONFIG_PPC32
        .pcibios_enable_device_hook = pmac_pci_enable_device_hook,
        .pcibios_after_init     = pmac_pcibios_after_init,
index fb2a7c798e8278c51e8019e844f5600c134006e2..0df2cdcd805c1776ecd85b2de340bf3db0742390 100644 (file)
@@ -52,8 +52,9 @@
 #include <asm/cacheflush.h>
 #include <asm/keylargo.h>
 #include <asm/pmac_low_i2c.h>
+#include <asm/pmac_pfunc.h>
 
-#undef DEBUG
+#define DEBUG
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -62,6 +63,7 @@
 #endif
 
 extern void __secondary_start_pmac_0(void);
+extern int pmac_pfunc_base_install(void);
 
 #ifdef CONFIG_PPC32
 
@@ -361,7 +363,6 @@ static void __init psurge_dual_sync_tb(int cpu_nr)
        set_dec(tb_ticks_per_jiffy);
        /* XXX fixme */
        set_tb(0, 0);
-       last_jiffy_stamp(cpu_nr) = 0;
 
        if (cpu_nr > 0) {
                mb();
@@ -429,15 +430,62 @@ struct smp_ops_t psurge_smp_ops = {
 };
 #endif /* CONFIG_PPC32 - actually powersurge support */
 
+/*
+ * Core 99 and later support
+ */
+
+static void (*pmac_tb_freeze)(int freeze);
+static unsigned long timebase;
+static int tb_req;
+
+static void smp_core99_give_timebase(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       while(!tb_req)
+               barrier();
+       tb_req = 0;
+       (*pmac_tb_freeze)(1);
+       mb();
+       timebase = get_tb();
+       mb();
+       while (timebase)
+               barrier();
+       mb();
+       (*pmac_tb_freeze)(0);
+       mb();
+
+       local_irq_restore(flags);
+}
+
+
+static void __devinit smp_core99_take_timebase(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       tb_req = 1;
+       mb();
+       while (!timebase)
+               barrier();
+       mb();
+       set_tb(timebase >> 32, timebase & 0xffffffff);
+       timebase = 0;
+       mb();
+       set_dec(tb_ticks_per_jiffy/2);
+
+       local_irq_restore(flags);
+}
+
 #ifdef CONFIG_PPC64
 /*
  * G5s enable/disable the timebase via an i2c-connected clock chip.
  */
-static struct device_node *pmac_tb_clock_chip_host;
+static struct pmac_i2c_bus *pmac_tb_clock_chip_host;
 static u8 pmac_tb_pulsar_addr;
-static void (*pmac_tb_freeze)(int freeze);
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned long timebase;
 
 static void smp_core99_cypress_tb_freeze(int freeze)
 {
@@ -447,19 +495,20 @@ static void smp_core99_cypress_tb_freeze(int freeze)
        /* Strangely, the device-tree says address is 0xd2, but darwin
         * accesses 0xd0 ...
         */
-       pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
-       rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-                              0xd0 | pmac_low_i2c_read,
-                              0x81, &data, 1);
+       pmac_i2c_setmode(pmac_tb_clock_chip_host,
+                        pmac_i2c_mode_combined);
+       rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+                          0xd0 | pmac_i2c_read,
+                          1, 0x81, &data, 1);
        if (rc != 0)
                goto bail;
 
        data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);
 
-               pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
-       rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-                              0xd0 | pmac_low_i2c_write,
-                              0x81, &data, 1);
+               pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
+       rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+                          0xd0 | pmac_i2c_write,
+                          1, 0x81, &data, 1);
 
  bail:
        if (rc != 0) {
@@ -475,19 +524,20 @@ static void smp_core99_pulsar_tb_freeze(int freeze)
        u8 data;
        int rc;
 
-       pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
-       rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-                              pmac_tb_pulsar_addr | pmac_low_i2c_read,
-                              0x2e, &data, 1);
+       pmac_i2c_setmode(pmac_tb_clock_chip_host,
+                        pmac_i2c_mode_combined);
+       rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+                          pmac_tb_pulsar_addr | pmac_i2c_read,
+                          1, 0x2e, &data, 1);
        if (rc != 0)
                goto bail;
 
        data = (data & 0x88) | (freeze ? 0x11 : 0x22);
 
-       pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
-       rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
-                              pmac_tb_pulsar_addr | pmac_low_i2c_write,
-                              0x2e, &data, 1);
+       pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
+       rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+                          pmac_tb_pulsar_addr | pmac_i2c_write,
+                          1, 0x2e, &data, 1);
  bail:
        if (rc != 0) {
                printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",
@@ -496,54 +546,14 @@ static void smp_core99_pulsar_tb_freeze(int freeze)
        }
 }
 
-
-static void smp_core99_give_timebase(void)
-{
-       /* Open i2c bus for synchronous access */
-       if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0))
-               panic("Can't open i2c for TB sync !\n");
-
-       spin_lock(&timebase_lock);
-       (*pmac_tb_freeze)(1);
-       mb();
-       timebase = get_tb();
-       spin_unlock(&timebase_lock);
-
-       while (timebase)
-               barrier();
-
-       spin_lock(&timebase_lock);
-       (*pmac_tb_freeze)(0);
-       spin_unlock(&timebase_lock);
-
-       /* Close i2c bus */
-       pmac_low_i2c_close(pmac_tb_clock_chip_host);
-}
-
-
-static void __devinit smp_core99_take_timebase(void)
-{
-       while (!timebase)
-               barrier();
-       spin_lock(&timebase_lock);
-       set_tb(timebase >> 32, timebase & 0xffffffff);
-       timebase = 0;
-       spin_unlock(&timebase_lock);
-}
-
-static void __init smp_core99_setup(int ncpus)
+static void __init smp_core99_setup_i2c_hwsync(int ncpus)
 {
        struct device_node *cc = NULL;  
        struct device_node *p;
+       const char *name = NULL;
        u32 *reg;
        int ok;
 
-       /* HW sync only on these platforms */
-       if (!machine_is_compatible("PowerMac7,2") &&
-           !machine_is_compatible("PowerMac7,3") &&
-           !machine_is_compatible("RackMac3,1"))
-               return;
-
        /* Look for the clock chip */
        while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {
                p = of_get_parent(cc);
@@ -552,124 +562,86 @@ static void __init smp_core99_setup(int ncpus)
                if (!ok)
                        continue;
 
+               pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
+               if (pmac_tb_clock_chip_host == NULL)
+                       continue;
                reg = (u32 *)get_property(cc, "reg", NULL);
                if (reg == NULL)
                        continue;
-
                switch (*reg) {
                case 0xd2:
-                       if (device_is_compatible(cc, "pulsar-legacy-slewing")) {
+                       if (device_is_compatible(cc,"pulsar-legacy-slewing")) {
                                pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
                                pmac_tb_pulsar_addr = 0xd2;
-                               printk(KERN_INFO "Timebase clock is Pulsar chip\n");
+                               name = "Pulsar";
                        } else if (device_is_compatible(cc, "cy28508")) {
                                pmac_tb_freeze = smp_core99_cypress_tb_freeze;
-                               printk(KERN_INFO "Timebase clock is Cypress chip\n");
+                               name = "Cypress";
                        }
                        break;
                case 0xd4:
                        pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
                        pmac_tb_pulsar_addr = 0xd4;
-                       printk(KERN_INFO "Timebase clock is Pulsar chip\n");
+                       name = "Pulsar";
                        break;
                }
-               if (pmac_tb_freeze != NULL) {
-                       pmac_tb_clock_chip_host = of_get_parent(cc);
-                       of_node_put(cc);
+               if (pmac_tb_freeze != NULL)
                        break;
-               }
        }
-       if (pmac_tb_freeze == NULL) {
-               smp_ops->give_timebase = smp_generic_give_timebase;
-               smp_ops->take_timebase = smp_generic_take_timebase;
+       if (pmac_tb_freeze != NULL) {
+               /* Open i2c bus for synchronous access */
+               if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) {
+                       printk(KERN_ERR "Failed top open i2c bus for clock"
+                              " sync, fallback to software sync !\n");
+                       goto no_i2c_sync;
+               }
+               printk(KERN_INFO "Processor timebase sync using %s i2c clock\n",
+                      name);
+               return;
        }
+ no_i2c_sync:
+       pmac_tb_freeze = NULL;
+       pmac_tb_clock_chip_host = NULL;
 }
 
-/* nothing to do here, caches are already set up by service processor */
-static inline void __devinit core99_init_caches(int cpu)
+
+
+/*
+ * Newer G5s uses a platform function
+ */
+
+static void smp_core99_pfunc_tb_freeze(int freeze)
 {
+       struct device_node *cpus;
+       struct pmf_args args;
+
+       cpus = of_find_node_by_path("/cpus");
+       BUG_ON(cpus == NULL);
+       args.count = 1;
+       args.u[0].v = !freeze;
+       pmf_call_function(cpus, "cpu-timebase", &args);
+       of_node_put(cpus);
 }
 
 #else /* CONFIG_PPC64 */
 
 /*
- * SMP G4 powermacs use a GPIO to enable/disable the timebase.
+ * SMP G4 use a GPIO to enable/disable the timebase.
  */
 
 static unsigned int core99_tb_gpio;    /* Timebase freeze GPIO */
 
-static unsigned int pri_tb_hi, pri_tb_lo;
-static unsigned int pri_tb_stamp;
-
-/* not __init, called in sleep/wakeup code */
-void smp_core99_give_timebase(void)
+static void smp_core99_gpio_tb_freeze(int freeze)
 {
-       unsigned long flags;
-       unsigned int t;
-
-       /* wait for the secondary to be in take_timebase */
-       for (t = 100000; t > 0 && !sec_tb_reset; --t)
-               udelay(10);
-       if (!sec_tb_reset) {
-               printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
-               return;
-       }
-
-       /* freeze the timebase and read it */
-       /* disable interrupts so the timebase is disabled for the
-          shortest possible time */
-       local_irq_save(flags);
-       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+       if (freeze)
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+       else
+               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
        pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-       mb();
-       pri_tb_hi = get_tbu();
-       pri_tb_lo = get_tbl();
-       pri_tb_stamp = last_jiffy_stamp(smp_processor_id());
-       mb();
-
-       /* tell the secondary we're ready */
-       sec_tb_reset = 2;
-       mb();
-
-       /* wait for the secondary to have taken it */
-       /* note: can't use udelay here, since it needs the timebase running */
-       for (t = 10000000; t > 0 && sec_tb_reset; --t)
-               barrier();
-       if (sec_tb_reset)
-               /* XXX BUG_ON here? */
-               printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
-
-       /* Now, restart the timebase by leaving the GPIO to an open collector */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
-        pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-       local_irq_restore(flags);
 }
 
-/* not __init, called in sleep/wakeup code */
-void smp_core99_take_timebase(void)
-{
-       unsigned long flags;
-
-       /* tell the primary we're here */
-       sec_tb_reset = 1;
-       mb();
-
-       /* wait for the primary to set pri_tb_hi/lo */
-       while (sec_tb_reset < 2)
-               mb();
-
-       /* set our stuff the same as the primary */
-       local_irq_save(flags);
-       set_dec(1);
-       set_tb(pri_tb_hi, pri_tb_lo);
-       last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;
-       mb();
 
-       /* tell the primary we're done */
-               sec_tb_reset = 0;
-       mb();
-       local_irq_restore(flags);
-}
+#endif /* !CONFIG_PPC64 */
 
 /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */
 volatile static long int core99_l2_cache;
@@ -677,6 +649,7 @@ volatile static long int core99_l3_cache;
 
 static void __devinit core99_init_caches(int cpu)
 {
+#ifndef CONFIG_PPC64
        if (!cpu_has_feature(CPU_FTR_L2CR))
                return;
 
@@ -702,30 +675,76 @@ static void __devinit core99_init_caches(int cpu)
                _set_L3CR(core99_l3_cache);
                printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
        }
+#endif /* !CONFIG_PPC64 */
 }
 
 static void __init smp_core99_setup(int ncpus)
 {
-       struct device_node *cpu;
-       u32 *tbprop = NULL;
-       int i;
+#ifdef CONFIG_PPC64
+
+       /* i2c based HW sync on some G5s */
+       if (machine_is_compatible("PowerMac7,2") ||
+           machine_is_compatible("PowerMac7,3") ||
+           machine_is_compatible("RackMac3,1"))
+               smp_core99_setup_i2c_hwsync(ncpus);
 
-       core99_tb_gpio = KL_GPIO_TB_ENABLE;     /* default value */
-       cpu = of_find_node_by_type(NULL, "cpu");
-       if (cpu != NULL) {
-               tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL);
-               if (tbprop)
-                       core99_tb_gpio = *tbprop;
-               of_node_put(cpu);
+       /* pfunc based HW sync on recent G5s */
+       if (pmac_tb_freeze == NULL) {
+               struct device_node *cpus =
+                       of_find_node_by_path("/cpus");
+               if (cpus &&
+                   get_property(cpus, "platform-cpu-timebase", NULL)) {
+                       pmac_tb_freeze = smp_core99_pfunc_tb_freeze;
+                       printk(KERN_INFO "Processor timebase sync using"
+                              " platform function\n");
+               }
        }
 
-       /* XXX should get this from reg properties */
-       for (i = 1; i < ncpus; ++i)
-               smp_hw_index[i] = i;
-       powersave_nap = 0;
-}
+#else /* CONFIG_PPC64 */
+
+       /* GPIO based HW sync on ppc32 Core99 */
+       if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) {
+               struct device_node *cpu;
+               u32 *tbprop = NULL;
+
+               core99_tb_gpio = KL_GPIO_TB_ENABLE;     /* default value */
+               cpu = of_find_node_by_type(NULL, "cpu");
+               if (cpu != NULL) {
+                       tbprop = (u32 *)get_property(cpu, "timebase-enable",
+                                                    NULL);
+                       if (tbprop)
+                               core99_tb_gpio = *tbprop;
+                       of_node_put(cpu);
+               }
+               pmac_tb_freeze = smp_core99_gpio_tb_freeze;
+               printk(KERN_INFO "Processor timebase sync using"
+                      " GPIO 0x%02x\n", core99_tb_gpio);
+       }
+
+#endif /* CONFIG_PPC64 */
+
+       /* No timebase sync, fallback to software */
+       if (pmac_tb_freeze == NULL) {
+               smp_ops->give_timebase = smp_generic_give_timebase;
+               smp_ops->take_timebase = smp_generic_take_timebase;
+               printk(KERN_INFO "Processor timebase sync using software\n");
+       }
+
+#ifndef CONFIG_PPC64
+       {
+               int i;
+
+               /* XXX should get this from reg properties */
+               for (i = 1; i < ncpus; ++i)
+                       smp_hw_index[i] = i;
+       }
 #endif
 
+       /* 32 bits SMP can't NAP */
+       if (!machine_is_compatible("MacRISC4"))
+               powersave_nap = 0;
+}
+
 static int __init smp_core99_probe(void)
 {
        struct device_node *cpus;
@@ -743,8 +762,19 @@ static int __init smp_core99_probe(void)
        if (ncpus <= 1)
                return 1;
 
+       /* We need to perform some early initialisations before we can start
+        * setting up SMP as we are running before initcalls
+        */
+       pmac_pfunc_base_install();
+       pmac_i2c_init();
+
+       /* Setup various bits like timebase sync method, ability to nap, ... */
        smp_core99_setup(ncpus);
+
+       /* Install IPIs */
        mpic_request_ipis();
+
+       /* Collect l2cr and l3cr values from CPU 0 */
        core99_init_caches(0);
 
        return ncpus;
@@ -753,14 +783,15 @@ static int __init smp_core99_probe(void)
 static void __devinit smp_core99_kick_cpu(int nr)
 {
        unsigned int save_vector;
-       unsigned long new_vector;
-       unsigned long flags;
+       unsigned long target, flags;
        volatile unsigned int *vector
                 = ((volatile unsigned int *)(KERNELBASE+0x100));
 
        if (nr < 0 || nr > 3)
                return;
-       if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
+
+       if (ppc_md.progress)
+               ppc_md.progress("smp_core99_kick_cpu", 0x346);
 
        local_irq_save(flags);
        local_irq_disable();
@@ -768,14 +799,11 @@ static void __devinit smp_core99_kick_cpu(int nr)
        /* Save reset vector */
        save_vector = *vector;
 
-       /* Setup fake reset vector that does    
+       /* Setup fake reset vector that does
         *   b __secondary_start_pmac_0 + nr*8 - KERNELBASE
         */
-       new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8;
-       *vector = 0x48000002 + new_vector - KERNELBASE;
-
-       /* flush data cache and inval instruction cache */
-       flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+       target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
+       create_branch((unsigned long)vector, target, BRANCH_SET_LINK);
 
        /* Put some life in our friend */
        pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
@@ -805,17 +833,25 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
        mpic_setup_this_cpu();
 
        if (cpu_nr == 0) {
-#ifdef CONFIG_POWER4
+#ifdef CONFIG_PPC64
                extern void g5_phy_disable_cpu1(void);
 
+               /* Close i2c bus if it was used for tb sync */
+               if (pmac_tb_clock_chip_host) {
+                       pmac_i2c_close(pmac_tb_clock_chip_host);
+                       pmac_tb_clock_chip_host = NULL;
+               }
+
                /* If we didn't start the second CPU, we must take
                 * it off the bus
                 */
                if (machine_is_compatible("MacRISC4") &&
                    num_online_cpus() < 2)              
                        g5_phy_disable_cpu1();
-#endif /* CONFIG_POWER4 */
-               if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+#endif /* CONFIG_PPC64 */
+
+               if (ppc_md.progress)
+                       ppc_md.progress("core99_setup_cpu 0 done", 0x349);
        }
 }
 
index feb0a94e78192e28010b6635473e45780a0a3862..5d9afa1fa02d0d6d9262040716425852a73753a5 100644 (file)
@@ -258,15 +258,20 @@ int __init via_calibrate_decr(void)
        volatile unsigned char __iomem *via;
        int count = VIA_TIMER_FREQ_6 / 100;
        unsigned int dstart, dend;
+       struct resource rsrc;
 
-       vias = find_devices("via-cuda");
+       vias = of_find_node_by_name(NULL, "via-cuda");
        if (vias == 0)
-               vias = find_devices("via-pmu");
+               vias = of_find_node_by_name(NULL, "via-pmu");
        if (vias == 0)
-               vias = find_devices("via");
-       if (vias == 0 || vias->n_addrs == 0)
+               vias = of_find_node_by_name(NULL, "via");
+       if (vias == 0 || of_address_to_resource(vias, 0, &rsrc))
                return 0;
-       via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
+       via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+       if (via == NULL) {
+               printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
+               return 0;
+       }
 
        /* set timer 1 for continuous interrupts */
        out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c
new file mode 100644 (file)
index 0000000..06c8265
--- /dev/null
@@ -0,0 +1,221 @@
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/bitops.h>
+#include <linux/ptrace.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/cuda.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/xmon.h>
+#include <asm/prom.h>
+#include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/errno.h>
+#include <asm/pmac_feature.h>
+#include <asm/processor.h>
+#include <asm/delay.h>
+#include <asm/btext.h>
+#include <asm/time.h>
+#include <asm/udbg.h>
+
+/*
+ * This implementation is "special", it can "patch" the current
+ * udbg implementation and work on top of it. It must thus be
+ * initialized last
+ */
+
+static void (*udbg_adb_old_putc)(char c);
+static int (*udbg_adb_old_getc)(void);
+static int (*udbg_adb_old_getc_poll)(void);
+
+static enum {
+       input_adb_none,
+       input_adb_pmu,
+       input_adb_cuda,
+} input_type = input_adb_none;
+
+int xmon_wants_key, xmon_adb_keycode;
+
+static inline void udbg_adb_poll(void)
+{
+#ifdef CONFIG_ADB_PMU
+       if (input_type == input_adb_pmu)
+               pmu_poll_adb();
+#endif /* CONFIG_ADB_PMU */
+#ifdef CONFIG_ADB_CUDA
+       if (input_type == input_adb_cuda)
+               cuda_poll();
+#endif /* CONFIG_ADB_CUDA */
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+
+static int udbg_adb_use_btext;
+static int xmon_adb_shiftstate;
+
+static unsigned char xmon_keytab[128] =
+       "asdfhgzxcv\000bqwer"                           /* 0x00 - 0x0f */
+       "yt123465=97-80]o"                              /* 0x10 - 0x1f */
+       "u[ip\rlj'k;\\,/nm."                            /* 0x20 - 0x2f */
+       "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
+       "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
+       "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
+
+static unsigned char xmon_shift_keytab[128] =
+       "ASDFHGZXCV\000BQWER"                           /* 0x00 - 0x0f */
+       "YT!@#$^%+(&_*)}O"                              /* 0x10 - 0x1f */
+       "U{IP\rLJ\"K:|<?NM>"                            /* 0x20 - 0x2f */
+       "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
+       "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
+       "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
+
+static int udbg_adb_local_getc(void)
+{
+       int k, t, on;
+
+       xmon_wants_key = 1;
+       for (;;) {
+               xmon_adb_keycode = -1;
+               t = 0;
+               on = 0;
+               k = -1;
+               do {
+                       if (--t < 0) {
+                               on = 1 - on;
+                               btext_drawchar(on? 0xdb: 0x20);
+                               btext_drawchar('\b');
+                               t = 200000;
+                       }
+                       udbg_adb_poll();
+                       if (udbg_adb_old_getc_poll)
+                               k = udbg_adb_old_getc_poll();
+               } while (k == -1 && xmon_adb_keycode == -1);
+               if (on)
+                       btext_drawstring(" \b");
+               if (k != -1)
+                       return k;
+               k = xmon_adb_keycode;
+
+               /* test for shift keys */
+               if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
+                       xmon_adb_shiftstate = (k & 0x80) == 0;
+                       continue;
+               }
+               if (k >= 0x80)
+                       continue;       /* ignore up transitions */
+               k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
+               if (k != 0)
+                       break;
+       }
+       xmon_wants_key = 0;
+       return k;
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static int udbg_adb_getc(void)
+{
+#ifdef CONFIG_BOOTX_TEXT
+       if (udbg_adb_use_btext && input_type != input_adb_none)
+               return udbg_adb_local_getc();
+#endif
+       if (udbg_adb_old_getc)
+               return udbg_adb_old_getc();
+       return -1;
+}
+
+/* getc_poll() is not really used, unless you have the xmon-over modem
+ * hack that doesn't quite concern us here, thus we just poll the low level
+ * ADB driver to prevent it from timing out and call back the original poll
+ * routine.
+ */
+static int udbg_adb_getc_poll(void)
+{
+       udbg_adb_poll();
+
+       if (udbg_adb_old_getc_poll)
+               return udbg_adb_old_getc_poll();
+       return -1;
+}
+
+static void udbg_adb_putc(char c)
+{
+#ifdef CONFIG_BOOTX_TEXT
+       if (udbg_adb_use_btext)
+               btext_drawchar(c);
+#endif
+       if (udbg_adb_old_putc)
+               return udbg_adb_old_putc(c);
+}
+
+void udbg_adb_init_early(void)
+{
+#ifdef CONFIG_BOOTX_TEXT
+       if (btext_find_display(1) == 0) {
+               udbg_adb_use_btext = 1;
+               udbg_putc = udbg_adb_putc;
+       }
+#endif
+}
+
+int udbg_adb_init(int force_btext)
+{
+       struct device_node *np;
+
+       /* Capture existing callbacks */
+       udbg_adb_old_putc = udbg_putc;
+       udbg_adb_old_getc = udbg_getc;
+       udbg_adb_old_getc_poll = udbg_getc_poll;
+
+       /* Check if our early init was already called */
+       if (udbg_adb_old_putc == udbg_adb_putc)
+               udbg_adb_old_putc = NULL;
+#ifdef CONFIG_BOOTX_TEXT
+       if (udbg_adb_old_putc == btext_drawchar)
+               udbg_adb_old_putc = NULL;
+#endif
+
+       /* Set ours as output */
+       udbg_putc = udbg_adb_putc;
+       udbg_getc = udbg_adb_getc;
+       udbg_getc_poll = udbg_adb_getc_poll;
+
+#ifdef CONFIG_BOOTX_TEXT
+       /* Check if we should use btext output */
+       if (btext_find_display(force_btext) == 0)
+               udbg_adb_use_btext = 1;
+#endif
+
+       /* See if there is a keyboard in the device tree with a parent
+        * of type "adb". If not, we return a failure, but we keep the
+        * bext output set for now
+        */
+       for (np = NULL; (np = of_find_node_by_name(np, "keyboard")) != NULL;) {
+               struct device_node *parent = of_get_parent(np);
+               int found = (parent && strcmp(parent->type, "adb") == 0);
+               of_node_put(parent);
+               if (found)
+                       break;
+       }
+       if (np == NULL)
+               return -ENODEV;
+       of_node_put(np);
+
+#ifdef CONFIG_ADB_PMU
+       if (find_via_pmu())
+               input_type = input_adb_pmu;
+#endif
+#ifdef CONFIG_ADB_CUDA
+       if (find_via_cuda())
+               input_type = input_adb_cuda;
+#endif
+
+       /* Same as above: nothing found, keep btext set for output */
+       if (input_type == input_adb_none)
+               return -ENODEV;
+
+       return 0;
+}
similarity index 66%
rename from arch/powerpc/kernel/udbg_scc.c
rename to arch/powerpc/platforms/powermac/udbg_scc.c
index 820c5355150761997aab89aa10fec5b44a9d1c69..e87d53acfb61827936bb200badbc794f0f569c91 100644 (file)
@@ -25,7 +25,7 @@ extern void real_writeb(u8 data, volatile u8 __iomem *addr);
 static volatile u8 __iomem *sccc;
 static volatile u8 __iomem *sccd;
 
-static void udbg_scc_putc(unsigned char c)
+static void udbg_scc_putc(char c)
 {
        if (sccc) {
                while ((in_8(sccc) & SCC_TXRDY) == 0)
@@ -47,14 +47,14 @@ static int udbg_scc_getc_poll(void)
        return -1;
 }
 
-static unsigned char udbg_scc_getc(void)
+static int udbg_scc_getc(void)
 {
        if (sccc) {
                while ((in_8(sccc) & SCC_RXRDY) == 0)
                        ;
                return in_8(sccd);
        }
-       return 0;
+       return -1;
 }
 
 static unsigned char scc_inittab[] = {
@@ -67,38 +67,59 @@ static unsigned char scc_inittab[] = {
     3,  0xc1,          /* rx enable, 8 bits */
 };
 
-void udbg_init_scc(struct device_node *np)
+void udbg_scc_init(int force_scc)
 {
        u32 *reg;
        unsigned long addr;
+       struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
+       struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
+       char *path;
        int i, x;
 
-       if (np == NULL)
-               np = of_find_node_by_name(NULL, "escc");
-       if (np == NULL || np->parent == NULL)
-               return;
+       escc = of_find_node_by_name(NULL, "escc");
+       if (escc == NULL)
+               goto bail;
+       macio = of_get_parent(escc);
+       if (macio == NULL)
+               goto bail;
+       path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+       if (path != NULL)
+               stdout = of_find_node_by_path(path);
+       for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
+               if (ch == stdout)
+                       ch_def = of_node_get(ch);
+               if (strcmp(ch->name, "ch-a") == 0)
+                       ch_a = of_node_get(ch);
+       }
+       if (ch_def == NULL && !force_scc)
+               goto bail;
+
+       ch = ch_def ? ch_def : ch_a;
 
-       udbg_printf("found SCC...\n");
        /* Get address within mac-io ASIC */
-       reg = (u32 *)get_property(np, "reg", NULL);
+       reg = (u32 *)get_property(escc, "reg", NULL);
        if (reg == NULL)
-               return;
+               goto bail;
        addr = reg[0];
-       udbg_printf("local addr: %lx\n", addr);
+
        /* Get address of mac-io PCI itself */
-       reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
+       reg = (u32 *)get_property(macio, "assigned-addresses", NULL);
        if (reg == NULL)
-               return;
+               goto bail;
        addr += reg[2];
-       udbg_printf("final addr: %lx\n", addr);
+
+       /* Lock the serial port */
+       pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
+                         PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
+
 
        /* Setup for 57600 8N1 */
-       addr += 0x20;
+       if (ch == ch_a)
+               addr += 0x20;
        sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
        sccc += addr & ~PAGE_MASK;
        sccd = sccc + 0x10;
 
-       udbg_printf("ioremap result sccc: %p\n", sccc);
        mb();
 
        for (i = 20000; i != 0; --i)
@@ -113,9 +134,17 @@ void udbg_init_scc(struct device_node *np)
        udbg_getc_poll = udbg_scc_getc_poll;
 
        udbg_puts("Hello World !\n");
+
+ bail:
+       of_node_put(macio);
+       of_node_put(escc);
+       of_node_put(stdout);
+       of_node_put(ch_def);
+       of_node_put(ch_a);
 }
 
-static void udbg_real_scc_putc(unsigned char c)
+#ifdef CONFIG_PPC64
+static void udbg_real_scc_putc(char c)
 {
        while ((real_readb(sccc) & SCC_TXRDY) == 0)
                ;
@@ -133,3 +162,4 @@ void udbg_init_pmac_realmode(void)
        udbg_getc = NULL;
        udbg_getc_poll = NULL;
 }
+#endif /* CONFIG_PPC64 */
index 06d5ef501218c8d5f1a638a0906d859a5cc083f8..6accdd1555058861a08ab43fadf6caa0582ad415 100644 (file)
@@ -1,5 +1,5 @@
 obj-y                  := pci.o lpar.o hvCall.o nvram.o reconfig.o \
-                          setup.o iommu.o ras.o rtasd.o
+                          setup.o iommu.o ras.o rtasd.o pci_dlpar.o
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_IBMVIO)   += vio.o
 obj-$(CONFIG_XICS)     += xics.o
index c8d2a40dc5b48ceb6038b3f9fcbc8bc036850efa..7fbfd16d72b703b91b2e1e91a5f60935018e0af2 100644 (file)
@@ -1093,6 +1093,15 @@ void eeh_add_device_early(struct device_node *dn)
 }
 EXPORT_SYMBOL_GPL(eeh_add_device_early);
 
+void eeh_add_device_tree_early(struct device_node *dn)
+{
+       struct device_node *sib;
+       for (sib = dn->child; sib; sib = sib->sibling)
+               eeh_add_device_tree_early(sib);
+       eeh_add_device_early(dn);
+}
+EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
+
 /**
  * eeh_add_device_late - perform EEH initialization for the indicated pci device
  * @dev: pci device for which to set up EEH
@@ -1147,6 +1156,23 @@ void eeh_remove_device(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(eeh_remove_device);
 
+void eeh_remove_bus_device(struct pci_dev *dev)
+{
+       eeh_remove_device(dev);
+       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+               struct pci_bus *bus = dev->subordinate;
+               struct list_head *ln;
+               if (!bus)
+                       return; 
+               for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+                       struct pci_dev *pdev = pci_dev_b(ln);
+                       if (pdev)
+                               eeh_remove_bus_device(pdev);
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(eeh_remove_bus_device);
+
 static int proc_eeh_show(struct seq_file *m, void *v)
 {
        unsigned int cpu;
index 2043659ea7b19cfb4fcde1ea7d2ce8ddd4768a3b..169f9148789c7317e721a887b35164f24fee0868 100644 (file)
@@ -436,7 +436,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
                return;
        }
 
-       ppci = pdn->data;
+       ppci = PCI_DN(pdn);
        if (!ppci->iommu_table) {
                /* Bussubno hasn't been copied yet.
                 * Do it now because iommu_table_setparms_lpar needs it.
@@ -483,10 +483,10 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev)
         * an already allocated iommu table is found and use that.
         */
 
-       while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL)
+       while (dn && PCI_DN(dn) && PCI_DN(dn)->iommu_table == NULL)
                dn = dn->parent;
 
-       if (dn && dn->data) {
+       if (dn && PCI_DN(dn)) {
                PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table;
        } else {
                DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, pci_name(dev));
@@ -497,7 +497,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
 {
        int err = NOTIFY_OK;
        struct device_node *np = node;
-       struct pci_dn *pci = np->data;
+       struct pci_dn *pci = PCI_DN(np);
 
        switch (action) {
        case PSERIES_RECONFIG_REMOVE:
@@ -533,7 +533,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
         */
        dn = pci_device_to_OF_node(dev);
 
-       for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table;
+       for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
             pdn = pdn->parent) {
                dma_window = (unsigned int *)
                        get_property(pdn, "ibm,dma-window", NULL);
@@ -552,7 +552,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
                DBG("Found DMA window, allocating table\n");
        }
 
-       pci = pdn->data;
+       pci = PCI_DN(pdn);
        if (!pci->iommu_table) {
                /* iommu_table_setparms_lpar needs bussubno. */
                pci->bussubno = pci->phb->bus->number;
index cf1bc11b334685264c296363f0a0dd06ca1b38cf..1fe445ab78a6342f0efed8e96349045d5a33eec2 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/dma-mapping.h>
+#include <linux/console.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/page.h>
@@ -60,7 +61,7 @@ extern void pSeries_find_serial_port(void);
 int vtermno;   /* virtual terminal# for udbg  */
 
 #define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
-static void udbg_hvsi_putc(unsigned char c)
+static void udbg_hvsi_putc(char c)
 {
        /* packet's seqno isn't used anyways */
        uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c };
@@ -111,7 +112,7 @@ static int udbg_hvsi_getc_poll(void)
        return ch;
 }
 
-static unsigned char udbg_hvsi_getc(void)
+static int udbg_hvsi_getc(void)
 {
        int ch;
        for (;;) {
@@ -127,7 +128,7 @@ static unsigned char udbg_hvsi_getc(void)
        }
 }
 
-static void udbg_putcLP(unsigned char c)
+static void udbg_putcLP(char c)
 {
        char buf[16];
        unsigned long rc;
@@ -172,7 +173,7 @@ static int udbg_getc_pollLP(void)
        return ch;
 }
 
-static unsigned char udbg_getcLP(void)
+static int udbg_getcLP(void)
 {
        int ch;
        for (;;) {
@@ -191,7 +192,7 @@ static unsigned char udbg_getcLP(void)
 /* call this from early_init() for a working debug console on
  * vterm capable LPAR machines
  */
-void udbg_init_debug_lpar(void)
+void __init udbg_init_debug_lpar(void)
 {
        vtermno = 0;
        udbg_putc = udbg_putcLP;
@@ -200,63 +201,54 @@ void udbg_init_debug_lpar(void)
 }
 
 /* returns 0 if couldn't find or use /chosen/stdout as console */
-int find_udbg_vterm(void)
+void __init find_udbg_vterm(void)
 {
        struct device_node *stdout_node;
        u32 *termno;
        char *name;
-       int found = 0;
+       int add_console;
 
        /* find the boot console from /chosen/stdout */
        if (!of_chosen)
-               return 0;
+               return;
        name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
        if (name == NULL)
-               return 0;
+               return;
        stdout_node = of_find_node_by_path(name);
        if (!stdout_node)
-               return 0;
-
-       /* now we have the stdout node; figure out what type of device it is. */
+               return;
        name = (char *)get_property(stdout_node, "name", NULL);
        if (!name) {
                printk(KERN_WARNING "stdout node missing 'name' property!\n");
                goto out;
        }
+       /* The user has requested a console so this is already set up. */
+       add_console = !strstr(cmd_line, "console=");
 
-       if (strncmp(name, "vty", 3) == 0) {
-               if (device_is_compatible(stdout_node, "hvterm1")) {
-                       termno = (u32 *)get_property(stdout_node, "reg", NULL);
-                       if (termno) {
-                               vtermno = termno[0];
-                               udbg_putc = udbg_putcLP;
-                               udbg_getc = udbg_getcLP;
-                               udbg_getc_poll = udbg_getc_pollLP;
-                               found = 1;
-                       }
-               } else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
-                       termno = (u32 *)get_property(stdout_node, "reg", NULL);
-                       if (termno) {
-                               vtermno = termno[0];
-                               udbg_putc = udbg_hvsi_putc;
-                               udbg_getc = udbg_hvsi_getc;
-                               udbg_getc_poll = udbg_hvsi_getc_poll;
-                               found = 1;
-                       }
-               }
-       } else if (strncmp(name, "serial", 6)) {
-               /* XXX fix ISA serial console */
-               printk(KERN_WARNING "serial stdout on LPAR ('%s')! "
-                               "can't print udbg messages\n",
-                      stdout_node->full_name);
-       } else {
-               printk(KERN_WARNING "don't know how to print to stdout '%s'\n",
-                      stdout_node->full_name);
+       /* Check if it's a virtual terminal */
+       if (strncmp(name, "vty", 3) != 0)
+               goto out;
+       termno = (u32 *)get_property(stdout_node, "reg", NULL);
+       if (termno == NULL)
+               goto out;
+       vtermno = termno[0];
+
+       if (device_is_compatible(stdout_node, "hvterm1")) {
+               udbg_putc = udbg_putcLP;
+               udbg_getc = udbg_getcLP;
+               udbg_getc_poll = udbg_getc_pollLP;
+               if (add_console)
+                       add_preferred_console("hvc", termno[0] & 0xff, NULL);
+       } else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
+               vtermno = termno[0];
+               udbg_putc = udbg_hvsi_putc;
+               udbg_getc = udbg_hvsi_getc;
+               udbg_getc_poll = udbg_hvsi_getc_poll;
+               if (add_console)
+                       add_preferred_console("hvsi", termno[0] & 0xff, NULL);
        }
-
 out:
        of_node_put(stdout_node);
-       return found;
 }
 
 void vpa_init(int cpu)
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
new file mode 100644 (file)
index 0000000..2193478
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code
+ * for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ * Copyright (C) 2005 International Business Machines
+ *
+ * Updates, 2005, John Rose <johnrose@austin.ibm.com>
+ * Updates, 2005, Linas Vepstas <linas@austin.ibm.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 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/pci.h>
+#include <asm/pci-bridge.h>
+
+static struct pci_bus *
+find_bus_among_children(struct pci_bus *bus,
+                        struct device_node *dn)
+{
+       struct pci_bus *child = NULL;
+       struct list_head *tmp;
+       struct device_node *busdn;
+
+       busdn = pci_bus_to_OF_node(bus);
+       if (busdn == dn)
+               return bus;
+
+       list_for_each(tmp, &bus->children) {
+               child = find_bus_among_children(pci_bus_b(tmp), dn);
+               if (child)
+                       break;
+       };
+       return child;
+}
+
+struct pci_bus *
+pcibios_find_pci_bus(struct device_node *dn)
+{
+       struct pci_dn *pdn = dn->data;
+
+       if (!pdn  || !pdn->phb || !pdn->phb->bus)
+               return NULL;
+
+       return find_bus_among_children(pdn->phb->bus, dn);
+}
+
+/**
+ * pcibios_remove_pci_devices - remove all devices under this bus
+ *
+ * Remove all of the PCI devices under this bus both from the
+ * linux pci device tree, and from the powerpc EEH address cache.
+ */
+void
+pcibios_remove_pci_devices(struct pci_bus *bus)
+{
+       struct pci_dev *dev, *tmp;
+
+       list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
+               eeh_remove_bus_device(dev);
+               pci_remove_bus_device(dev);
+       }
+}
+
+/* Must be called before pci_bus_add_devices */
+void
+pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               /*
+                * Skip already-present devices (which are on the
+                * global device list.)
+                */
+               if (list_empty(&dev->global_list)) {
+                       int i;
+
+                       /* Need to setup IOMMU tables */
+                       ppc_md.iommu_dev_setup(dev);
+
+                       if(fix_bus)
+                               pcibios_fixup_device_resources(dev, bus);
+                       pci_read_irq_line(dev);
+                       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+                               struct resource *r = &dev->resource[i];
+
+                               if (r->parent || !r->start || !r->flags)
+                                       continue;
+                               pci_claim_resource(dev, i);
+                       }
+               }
+       }
+}
+
+static int
+pcibios_pci_config_bridge(struct pci_dev *dev)
+{
+       u8 sec_busno;
+       struct pci_bus *child_bus;
+       struct pci_dev *child_dev;
+
+       /* Get busno of downstream bus */
+       pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
+
+       /* Add to children of PCI bridge dev->bus */
+       child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
+       if (!child_bus) {
+               printk (KERN_ERR "%s: could not add second bus\n", __FUNCTION__);
+               return -EIO;
+       }
+       sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
+
+       pci_scan_child_bus(child_bus);
+
+       list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
+               eeh_add_device_late(child_dev);
+       }
+
+       /* Fixup new pci devices without touching bus struct */
+       pcibios_fixup_new_pci_devices(child_bus, 0);
+
+       /* Make the discovered devices available */
+       pci_bus_add_devices(child_bus);
+       return 0;
+}
+
+/**
+ * pcibios_add_pci_devices - adds new pci devices to bus
+ *
+ * This routine will find and fixup new pci devices under
+ * the indicated bus. This routine presumes that there
+ * might already be some devices under this bridge, so
+ * it carefully tries to add only new devices.  (And that
+ * is how this routine differs from other, similar pcibios
+ * routines.)
+ */
+void
+pcibios_add_pci_devices(struct pci_bus * bus)
+{
+       int slotno, num;
+       struct pci_dev *dev;
+       struct device_node *dn = pci_bus_to_OF_node(bus);
+
+       eeh_add_device_tree_early(dn);
+
+       /* pci_scan_slot should find all children */
+       slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
+       num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
+       if (num) {
+               pcibios_fixup_new_pci_devices(bus, 1);
+               pci_bus_add_devices(bus);
+       }
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               eeh_add_device_late (dev);
+               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+                       pcibios_pci_config_bridge(dev);
+       }
+}
index fbd214d68b0717573ed443632bde26d055038345..b046bcf7443d4e51048e91de3004876ed7111380 100644 (file)
 #include <asm/machdep.h>
 #include <asm/rtas.h>
 #include <asm/udbg.h>
+#include <asm/firmware.h>
+
+#include "ras.h"
 
 static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
 static DEFINE_SPINLOCK(ras_log_buf_lock);
 
-char mce_data_buf[RTAS_ERROR_LOG_MAX]
-;
-/* This is true if we are using the firmware NMI handler (typically LPAR) */
-extern int fwnmi_active;
+char mce_data_buf[RTAS_ERROR_LOG_MAX];
 
 static int ras_get_sensor_state_token;
 static int ras_check_exception_token;
@@ -280,7 +280,7 @@ static void fwnmi_release_errinfo(void)
                printk("FWNMI: nmi-interlock failed: %d\n", ret);
 }
 
-void pSeries_system_reset_exception(struct pt_regs *regs)
+int pSeries_system_reset_exception(struct pt_regs *regs)
 {
        if (fwnmi_active) {
                struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
@@ -289,6 +289,7 @@ void pSeries_system_reset_exception(struct pt_regs *regs)
                }
                fwnmi_release_errinfo();
        }
+       return 0; /* need to perform reset */
 }
 
 /*
diff --git a/arch/powerpc/platforms/pseries/ras.h b/arch/powerpc/platforms/pseries/ras.h
new file mode 100644 (file)
index 0000000..0e66b0d
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _PSERIES_RAS_H
+#define _PSERIES_RAS_H
+
+struct pt_regs;
+
+extern int pSeries_system_reset_exception(struct pt_regs *regs);
+extern int pSeries_machine_check_exception(struct pt_regs *regs);
+
+#endif /* _PSERIES_RAS_H */
index 4a465f067ede53b64481574092f8bc7fe4c4735c..8903cf63236a273bfd2f77828cc89b5904bf2a62 100644 (file)
@@ -56,6 +56,7 @@
 #include <asm/dma.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
+#include <asm/kexec.h>
 #include <asm/time.h>
 #include <asm/nvram.h>
 #include "xics.h"
@@ -68,6 +69,7 @@
 #include <asm/smp.h>
 
 #include "plpar_wrappers.h"
+#include "ras.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
 #endif
 
 extern void find_udbg_vterm(void);
-extern void system_reset_fwnmi(void);  /* from head.S */
-extern void machine_check_fwnmi(void); /* from head.S */
-extern void generic_find_legacy_serial_ports(u64 *physport,
-               unsigned int *default_speed);
 
 int fwnmi_active;  /* TRUE if an FWNMI handler is present */
 
-extern void pSeries_system_reset_exception(struct pt_regs *regs);
-extern int pSeries_machine_check_exception(struct pt_regs *regs);
-
 static void pseries_shared_idle(void);
 static void pseries_dedicated_idle(void);
 
@@ -105,18 +100,22 @@ void pSeries_show_cpuinfo(struct seq_file *m)
 
 /* Initialize firmware assisted non-maskable interrupts if
  * the firmware supports this feature.
- *
  */
 static void __init fwnmi_init(void)
 {
-       int ret;
+       unsigned long system_reset_addr, machine_check_addr;
+
        int ibm_nmi_register = rtas_token("ibm,nmi-register");
        if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE)
                return;
-       ret = rtas_call(ibm_nmi_register, 2, 1, NULL,
-                       __pa((unsigned long)system_reset_fwnmi),
-                       __pa((unsigned long)machine_check_fwnmi));
-       if (ret == 0)
+
+       /* If the kernel's not linked at zero we point the firmware at low
+        * addresses anyway, and use a trampoline to get to the real code. */
+       system_reset_addr  = __pa(system_reset_fwnmi) - PHYSICAL_START;
+       machine_check_addr = __pa(machine_check_fwnmi) - PHYSICAL_START;
+
+       if (0 == rtas_call(ibm_nmi_register, 2, 1, NULL, system_reset_addr,
+                               machine_check_addr))
                fwnmi_active = 1;
 }
 
@@ -323,15 +322,18 @@ static  void __init pSeries_discover_pic(void)
        ppc64_interrupt_controller = IC_INVALID;
        for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) {
                typep = (char *)get_property(np, "compatible", NULL);
-               if (strstr(typep, "open-pic"))
+               if (strstr(typep, "open-pic")) {
                        ppc64_interrupt_controller = IC_OPEN_PIC;
-               else if (strstr(typep, "ppc-xicp"))
+                       break;
+               } else if (strstr(typep, "ppc-xicp")) {
                        ppc64_interrupt_controller = IC_PPC_XIC;
-               else
-                       printk("pSeries_discover_pic: failed to recognize"
-                              " interrupt-controller\n");
-               break;
+                       break;
+               }
        }
+       if (ppc64_interrupt_controller == IC_INVALID)
+               printk("pSeries_discover_pic: failed to recognize"
+                       " interrupt-controller\n");
+
 }
 
 static void pSeries_mach_cpu_die(void)
@@ -365,10 +367,7 @@ static int pseries_set_xdabr(unsigned long dabr)
  */
 static void __init pSeries_init_early(void)
 {
-       void *comport;
        int iommu_off = 0;
-       unsigned int default_speed;
-       u64 physport;
 
        DBG(" -> pSeries_init_early()\n");
 
@@ -382,17 +381,8 @@ static void __init pSeries_init_early(void)
                             get_property(of_chosen, "linux,iommu-off", NULL));
        }
 
-       generic_find_legacy_serial_ports(&physport, &default_speed);
-
        if (platform_is_lpar())
                find_udbg_vterm();
-       else if (physport) {
-               /* Map the uart for udbg. */
-               comport = (void *)ioremap(physport, 16);
-               udbg_init_uart(comport, default_speed);
-
-               DBG("Hello World !\n");
-       }
 
        if (firmware_has_feature(FW_FEATURE_DABR))
                ppc_md.set_dabr = pseries_set_dabr;
@@ -638,5 +628,8 @@ struct machdep_calls __initdata pSeries_md = {
        .machine_check_exception = pSeries_machine_check_exception,
 #ifdef CONFIG_KEXEC
        .kexec_cpu_down         = pseries_kexec_cpu_down,
+       .machine_kexec          = default_machine_kexec,
+       .machine_kexec_prepare  = default_machine_kexec_prepare,
+       .machine_crash_shutdown = default_machine_crash_shutdown,
 #endif
 };
index 0377decc07190a4f6b7629f41ad73a43a82e921a..0c0cfa32eb58f57344b915ea8137cac8d308d5c4 100644 (file)
@@ -407,7 +407,7 @@ irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
                        smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
                }
 #endif
-#ifdef CONFIG_DEBUGGER
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
                if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
                                       &xics_ipi_message[cpu].value)) {
                        mb();
index 6b7efcfc352a2ed266ee08f8da00ad90f58041a5..14b9abde2d27eaf85fd55b092728bfc7ab7bb467 100644 (file)
@@ -4,5 +4,6 @@ obj-$(CONFIG_PPC_I8259)         += i8259.o
 obj-$(CONFIG_PPC_MPC106)       += grackle.o
 obj-$(CONFIG_BOOKE)            += dcr.o
 obj-$(CONFIG_40x)              += dcr.o
-obj-$(CONFIG_U3_DART)          += u3_iommu.o
+obj-$(CONFIG_U3_DART)          += dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)       += mmio_nvram.o
+obj-$(CONFIG_83xx)             += ipic.o
index 33ed9ed7fc1e35f693d41d0369d47c8658d613af..c2d05763ccbe679b09a24fe57563b4fc1287b956 100644 (file)
 #define _POWERPC_SYSDEV_DART_H
 
 
-/* physical base of DART registers */
-#define DART_BASE        0xf8033000UL
-
 /* Offset from base to control register */
-#define DARTCNTL   0
+#define DART_CNTL      0
+
 /* Offset from base to exception register */
-#define DARTEXCP   0x10
+#define DART_EXCP_U3   0x10
 /* Offset from base to TLB tag registers */
-#define DARTTAG    0x1000
+#define DART_TAGS_U3   0x1000
 
+/* U4 registers */
+#define DART_BASE_U4   0x10
+#define DART_SIZE_U4   0x20
+#define DART_EXCP_U4   0x30
+#define DART_TAGS_U4   0x1000
 
 /* Control Register fields */
 
-/* base address of table (pfn) */
-#define DARTCNTL_BASE_MASK    0xfffff
-#define DARTCNTL_BASE_SHIFT   12
+/* U3 registers */
+#define DART_CNTL_U3_BASE_MASK 0xfffff
+#define DART_CNTL_U3_BASE_SHIFT        12
+#define DART_CNTL_U3_FLUSHTLB  0x400
+#define DART_CNTL_U3_ENABLE    0x200
+#define DART_CNTL_U3_SIZE_MASK 0x1ff
+#define DART_CNTL_U3_SIZE_SHIFT        0
+
+/* U4 registers */
+#define DART_BASE_U4_BASE_MASK 0xffffff
+#define DART_BASE_U4_BASE_SHIFT        0
+#define DART_CNTL_U4_FLUSHTLB  0x20000000
+#define DART_CNTL_U4_ENABLE    0x80000000
+#define DART_SIZE_U4_SIZE_MASK 0x1fff
+#define DART_SIZE_U4_SIZE_SHIFT        0
+
+#define DART_REG(r)    (dart + ((r) >> 2))
+#define DART_IN(r)     (in_be32(DART_REG(r)))
+#define DART_OUT(r,v)  (out_be32(DART_REG(r), (v)))
 
-#define DARTCNTL_FLUSHTLB     0x400
-#define DARTCNTL_ENABLE       0x200
 
 /* size of table in pages */
-#define DARTCNTL_SIZE_MASK    0x1ff
-#define DARTCNTL_SIZE_SHIFT   0
 
 
 /* DART table fields */
similarity index 65%
rename from arch/powerpc/sysdev/u3_iommu.c
rename to arch/powerpc/sysdev/dart_iommu.c
index 5c1a26a6d00c3cd28e4ec1937e3824d62da4c0f5..e00b46b9514edb3159385d87adcd986e569e8874 100644 (file)
@@ -1,25 +1,27 @@
 /*
- * arch/powerpc/sysdev/u3_iommu.c
+ * arch/powerpc/sysdev/dart_iommu.c
  *
  * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
+ * Copyright (C) 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>,
+ *                    IBM Corporation
  *
  * Based on pSeries_iommu.c:
  * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
  * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
  *
- * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu.
+ * Dynamic DMA mapping support, Apple U3, U4 & IBM CPC925 "DART" iommu.
+ *
  *
- * 
  * 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
@@ -57,21 +59,22 @@ static unsigned long dart_tablesize;
 static u32 *dart_vbase;
 
 /* Mapped base address for the dart */
-static unsigned int *dart; 
+static unsigned int *__iomem dart;
 
 /* Dummy val that entries are set to when unused */
 static unsigned int dart_emptyval;
 
-static struct iommu_table iommu_table_u3;
-static int iommu_table_u3_inited;
+static struct iommu_table iommu_table_dart;
+static int iommu_table_dart_inited;
 static int dart_dirty;
+static int dart_is_u4;
 
 #define DBG(...)
 
 static inline void dart_tlb_invalidate_all(void)
 {
        unsigned long l = 0;
-       unsigned int reg;
+       unsigned int reg, inv_bit;
        unsigned long limit;
 
        DBG("dart: flush\n");
@@ -81,29 +84,28 @@ static inline void dart_tlb_invalidate_all(void)
         *
         * Gotcha: Sometimes, the DART won't detect that the bit gets
         * set. If so, clear it and set it again.
-        */ 
+        */
 
        limit = 0;
 
+       inv_bit = dart_is_u4 ? DART_CNTL_U4_FLUSHTLB : DART_CNTL_U3_FLUSHTLB;
 retry:
-       reg = in_be32((unsigned int *)dart+DARTCNTL);
-       reg |= DARTCNTL_FLUSHTLB;
-       out_be32((unsigned int *)dart+DARTCNTL, reg);
-
        l = 0;
-       while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) &&
-               l < (1L<<limit)) {
+       reg = DART_IN(DART_CNTL);
+       reg |= inv_bit;
+       DART_OUT(DART_CNTL, reg);
+
+       while ((DART_IN(DART_CNTL) & inv_bit) && l < (1L << limit))
                l++;
-       }
-       if (l == (1L<<limit)) {
+       if (l == (1L << limit)) {
                if (limit < 4) {
                        limit++;
-                       reg = in_be32((unsigned int *)dart+DARTCNTL);
-                       reg &= ~DARTCNTL_FLUSHTLB;
-                       out_be32((unsigned int *)dart+DARTCNTL, reg);
+                       reg = DART_IN(DART_CNTL);
+                       reg &= ~inv_bit;
+                       DART_OUT(DART_CNTL, reg);
                        goto retry;
                } else
-                       panic("U3-DART: TLB did not flush after waiting a long "
+                       panic("DART: TLB did not flush after waiting a long "
                              "time. Buggy U3 ?");
        }
 }
@@ -115,7 +117,7 @@ static void dart_flush(struct iommu_table *tbl)
        dart_dirty = 0;
 }
 
-static void dart_build(struct iommu_table *tbl, long index, 
+static void dart_build(struct iommu_table *tbl, long index,
                       long npages, unsigned long uaddr,
                       enum dma_data_direction direction)
 {
@@ -128,7 +130,7 @@ static void dart_build(struct iommu_table *tbl, long index,
        npages <<= DART_PAGE_FACTOR;
 
        dp = ((unsigned int*)tbl->it_base) + index;
-       
+
        /* On U3, all memory is contigous, so we can move this
         * out of the loop.
         */
@@ -148,7 +150,7 @@ static void dart_build(struct iommu_table *tbl, long index,
 static void dart_free(struct iommu_table *tbl, long index, long npages)
 {
        unsigned int *dp;
-       
+
        /* We don't worry about flushing the TLB cache. The only drawback of
         * not doing it is that we won't catch buggy device drivers doing
         * bad DMAs, but then no 32-bit architecture ever does either.
@@ -160,7 +162,7 @@ static void dart_free(struct iommu_table *tbl, long index, long npages)
        npages <<= DART_PAGE_FACTOR;
 
        dp  = ((unsigned int *)tbl->it_base) + index;
-               
+
        while (npages--)
                *(dp++) = dart_emptyval;
 }
@@ -168,20 +170,25 @@ static void dart_free(struct iommu_table *tbl, long index, long npages)
 
 static int dart_init(struct device_node *dart_node)
 {
-       unsigned int regword;
        unsigned int i;
-       unsigned long tmp;
+       unsigned long tmp, base, size;
+       struct resource r;
 
        if (dart_tablebase == 0 || dart_tablesize == 0) {
-               printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n");
+               printk(KERN_INFO "DART: table not allocated, using "
+                      "direct DMA\n");
                return -ENODEV;
        }
 
+       if (of_address_to_resource(dart_node, 0, &r))
+               panic("DART: can't get register base ! ");
+
        /* Make sure nothing from the DART range remains in the CPU cache
         * from a previous mapping that existed before the kernel took
         * over
         */
-       flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize);
+       flush_dcache_phys_range(dart_tablebase,
+                               dart_tablebase + dart_tablesize);
 
        /* Allocate a spare page to map all invalid DART pages. We need to do
         * that to work around what looks like a problem with the HT bridge
@@ -189,21 +196,16 @@ static int dart_init(struct device_node *dart_node)
         */
        tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
        if (!tmp)
-               panic("U3-DART: Cannot allocate spare page!");
-       dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & DARTMAP_RPNMASK);
+               panic("DART: Cannot allocate spare page!");
+       dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) &
+                                        DARTMAP_RPNMASK);
 
-       /* Map in DART registers. FIXME: Use device node to get base address */
-       dart = ioremap(DART_BASE, 0x7000);
+       /* Map in DART registers */
+       dart = ioremap(r.start, r.end - r.start + 1);
        if (dart == NULL)
-               panic("U3-DART: Cannot map registers!");
+               panic("DART: Cannot map registers!");
 
-       /* Set initial control register contents: table base, 
-        * table size and enable bit
-        */
-       regword = DARTCNTL_ENABLE | 
-               ((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) |
-               (((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
-                                << DARTCNTL_SIZE_SHIFT);
+       /* Map in DART table */
        dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize);
 
        /* Fill initial table */
@@ -211,36 +213,50 @@ static int dart_init(struct device_node *dart_node)
                dart_vbase[i] = dart_emptyval;
 
        /* Initialize DART with table base and enable it. */
-       out_be32((unsigned int *)dart, regword);
+       base = dart_tablebase >> DART_PAGE_SHIFT;
+       size = dart_tablesize >> DART_PAGE_SHIFT;
+       if (dart_is_u4) {
+               size &= DART_SIZE_U4_SIZE_MASK;
+               DART_OUT(DART_BASE_U4, base);
+               DART_OUT(DART_SIZE_U4, size);
+               DART_OUT(DART_CNTL, DART_CNTL_U4_ENABLE);
+       } else {
+               size &= DART_CNTL_U3_SIZE_MASK;
+               DART_OUT(DART_CNTL,
+                        DART_CNTL_U3_ENABLE |
+                        (base << DART_CNTL_U3_BASE_SHIFT) |
+                        (size << DART_CNTL_U3_SIZE_SHIFT));
+       }
 
        /* Invalidate DART to get rid of possible stale TLBs */
        dart_tlb_invalidate_all();
 
-       printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n");
+       printk(KERN_INFO "DART IOMMU initialized for %s type chipset\n",
+              dart_is_u4 ? "U4" : "U3");
 
        return 0;
 }
 
-static void iommu_table_u3_setup(void)
+static void iommu_table_dart_setup(void)
 {
-       iommu_table_u3.it_busno = 0;
-       iommu_table_u3.it_offset = 0;
+       iommu_table_dart.it_busno = 0;
+       iommu_table_dart.it_offset = 0;
        /* it_size is in number of entries */
-       iommu_table_u3.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
+       iommu_table_dart.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
 
        /* Initialize the common IOMMU code */
-       iommu_table_u3.it_base = (unsigned long)dart_vbase;
-       iommu_table_u3.it_index = 0;
-       iommu_table_u3.it_blocksize = 1;
-       iommu_init_table(&iommu_table_u3);
+       iommu_table_dart.it_base = (unsigned long)dart_vbase;
+       iommu_table_dart.it_index = 0;
+       iommu_table_dart.it_blocksize = 1;
+       iommu_init_table(&iommu_table_dart);
 
        /* Reserve the last page of the DART to avoid possible prefetch
         * past the DART mapped area
         */
-       set_bit(iommu_table_u3.it_size - 1, iommu_table_u3.it_map);
+       set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
 }
 
-static void iommu_dev_setup_u3(struct pci_dev *dev)
+static void iommu_dev_setup_dart(struct pci_dev *dev)
 {
        struct device_node *dn;
 
@@ -254,35 +270,39 @@ static void iommu_dev_setup_u3(struct pci_dev *dev)
        dn = pci_device_to_OF_node(dev);
 
        if (dn)
-               PCI_DN(dn)->iommu_table = &iommu_table_u3;
+               PCI_DN(dn)->iommu_table = &iommu_table_dart;
 }
 
-static void iommu_bus_setup_u3(struct pci_bus *bus)
+static void iommu_bus_setup_dart(struct pci_bus *bus)
 {
        struct device_node *dn;
 
-       if (!iommu_table_u3_inited) {
-               iommu_table_u3_inited = 1;
-               iommu_table_u3_setup();
+       if (!iommu_table_dart_inited) {
+               iommu_table_dart_inited = 1;
+               iommu_table_dart_setup();
        }
 
        dn = pci_bus_to_OF_node(bus);
 
        if (dn)
-               PCI_DN(dn)->iommu_table = &iommu_table_u3;
+               PCI_DN(dn)->iommu_table = &iommu_table_dart;
 }
 
 static void iommu_dev_setup_null(struct pci_dev *dev) { }
 static void iommu_bus_setup_null(struct pci_bus *bus) { }
 
-void iommu_init_early_u3(void)
+void iommu_init_early_dart(void)
 {
        struct device_node *dn;
 
        /* Find the DART in the device-tree */
        dn = of_find_compatible_node(NULL, "dart", "u3-dart");
-       if (dn == NULL)
-               return;
+       if (dn == NULL) {
+               dn = of_find_compatible_node(NULL, "dart", "u4-dart");
+               if (dn == NULL)
+                       goto bail;
+               dart_is_u4 = 1;
+       }
 
        /* Setup low level TCE operations for the core IOMMU code */
        ppc_md.tce_build = dart_build;
@@ -290,24 +310,27 @@ void iommu_init_early_u3(void)
        ppc_md.tce_flush = dart_flush;
 
        /* Initialize the DART HW */
-       if (dart_init(dn)) {
-               /* If init failed, use direct iommu and null setup functions */
-               ppc_md.iommu_dev_setup = iommu_dev_setup_null;
-               ppc_md.iommu_bus_setup = iommu_bus_setup_null;
-
-               /* Setup pci_dma ops */
-               pci_direct_iommu_init();
-       } else {
-               ppc_md.iommu_dev_setup = iommu_dev_setup_u3;
-               ppc_md.iommu_bus_setup = iommu_bus_setup_u3;
+       if (dart_init(dn) == 0) {
+               ppc_md.iommu_dev_setup = iommu_dev_setup_dart;
+               ppc_md.iommu_bus_setup = iommu_bus_setup_dart;
 
                /* Setup pci_dma ops */
                pci_iommu_init();
+
+               return;
        }
+
+ bail:
+       /* If init failed, use direct iommu and null setup functions */
+       ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+       ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+
+       /* Setup pci_dma ops */
+       pci_direct_iommu_init();
 }
 
 
-void __init alloc_u3_dart_table(void)
+void __init alloc_dart_table(void)
 {
        /* Only reserve DART space if machine has more than 2GB of RAM
         * or if requested with iommu=on on cmdline.
@@ -323,5 +346,5 @@ void __init alloc_u3_dart_table(void)
        dart_tablebase = (unsigned long)
                abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
 
-       printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase);
+       printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase);
 }
index 58d1cc2023c843df763db2b4b3d11aa753172b05..4f26304d0263b90ea1bdd51c0a59ebed9117bbd9 100644 (file)
@@ -13,6 +13,9 @@
  */
 
 #undef DEBUG
+#undef DEBUG_IPI
+#undef DEBUG_IRQ
+#undef DEBUG_LOW
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -45,7 +48,11 @@ static struct mpic *mpic_primary;
 static DEFINE_SPINLOCK(mpic_lock);
 
 #ifdef CONFIG_PPC32    /* XXX for now */
-#define distribute_irqs        CONFIG_IRQ_ALL_CPUS
+#ifdef CONFIG_IRQ_ALL_CPUS
+#define distribute_irqs        (1)
+#else
+#define distribute_irqs        (0)
+#endif
 #endif
 
 /*
@@ -164,70 +171,129 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic)
 /* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
  * to force the edge setting on the MPIC and do the ack workaround.
  */
-static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no)
+static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
 {
-       if (source_no >= 128 || !mpic->fixups)
+       if (source >= 128 || !mpic->fixups)
                return 0;
-       return mpic->fixups[source_no].base != NULL;
+       return mpic->fixups[source].base != NULL;
 }
 
-static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no)
+
+static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source)
 {
-       struct mpic_irq_fixup *fixup = &mpic->fixups[source_no];
-       u32 tmp;
+       struct mpic_irq_fixup *fixup = &mpic->fixups[source];
 
-       spin_lock(&mpic->fixup_lock);
-       writeb(0x11 + 2 * fixup->irq, fixup->base);
-       tmp = readl(fixup->base + 2);
-       writel(tmp | 0x80000000ul, fixup->base + 2);
-       /* config writes shouldn't be posted but let's be safe ... */
-       (void)readl(fixup->base + 2);
-       spin_unlock(&mpic->fixup_lock);
+       if (fixup->applebase) {
+               unsigned int soff = (fixup->index >> 3) & ~3;
+               unsigned int mask = 1U << (fixup->index & 0x1f);
+               writel(mask, fixup->applebase + soff);
+       } else {
+               spin_lock(&mpic->fixup_lock);
+               writeb(0x11 + 2 * fixup->index, fixup->base + 2);
+               writel(fixup->data, fixup->base + 4);
+               spin_unlock(&mpic->fixup_lock);
+       }
 }
 
+static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
+                                     unsigned int irqflags)
+{
+       struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+       unsigned long flags;
+       u32 tmp;
 
-static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase)
+       if (fixup->base == NULL)
+               return;
+
+       DBG("startup_ht_interrupt(%u, %u) index: %d\n",
+           source, irqflags, fixup->index);
+       spin_lock_irqsave(&mpic->fixup_lock, flags);
+       /* Enable and configure */
+       writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+       tmp = readl(fixup->base + 4);
+       tmp &= ~(0x23U);
+       if (irqflags & IRQ_LEVEL)
+               tmp |= 0x22;
+       writel(tmp, fixup->base + 4);
+       spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+}
+
+static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
+                                      unsigned int irqflags)
 {
-       int i, irq;
+       struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+       unsigned long flags;
        u32 tmp;
 
-       printk(KERN_INFO "mpic:    - Workarounds on AMD 8111 @ %p\n", devbase);
+       if (fixup->base == NULL)
+               return;
 
-       for (i=0; i < 24; i++) {
-               writeb(0x10 + 2*i, devbase + 0xf2);
-               tmp = readl(devbase + 0xf4);
-               if ((tmp & 0x1) || !(tmp & 0x20))
-                       continue;
-               irq = (tmp >> 16) & 0xff;
-               mpic->fixups[irq].irq = i;
-               mpic->fixups[irq].base = devbase + 0xf2;
-       }
+       DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags);
+
+       /* Disable */
+       spin_lock_irqsave(&mpic->fixup_lock, flags);
+       writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+       tmp = readl(fixup->base + 4);
+       tmp &= ~1U;
+       writel(tmp, fixup->base + 4);
+       spin_unlock_irqrestore(&mpic->fixup_lock, flags);
 }
-static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase)
+
+static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
+                                   unsigned int devfn, u32 vdid)
 {
-       int i, irq;
+       int i, irq, n;
+       u8 __iomem *base;
        u32 tmp;
+       u8 pos;
+
+       for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
+            pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
+               u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
+               if (id == PCI_CAP_ID_HT_IRQCONF) {
+                       id = readb(devbase + pos + 3);
+                       if (id == 0x80)
+                               break;
+               }
+       }
+       if (pos == 0)
+               return;
 
-       printk(KERN_INFO "mpic:    - Workarounds on AMD 8131 @ %p\n", devbase);
+       base = devbase + pos;
+       writeb(0x01, base + 2);
+       n = (readl(base + 4) >> 16) & 0xff;
 
-       for (i=0; i < 4; i++) {
-               writeb(0x10 + 2*i, devbase + 0xba);
-               tmp = readl(devbase + 0xbc);
-               if ((tmp & 0x1) || !(tmp & 0x20))
-                       continue;
+       printk(KERN_INFO "mpic:   - HT:%02x.%x [0x%02x] vendor %04x device %04x"
+              " has %d irqs\n",
+              devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1);
+
+       for (i = 0; i <= n; i++) {
+               writeb(0x10 + 2 * i, base + 2);
+               tmp = readl(base + 4);
                irq = (tmp >> 16) & 0xff;
-               mpic->fixups[irq].irq = i;
-               mpic->fixups[irq].base = devbase + 0xba;
+               DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp);
+               /* mask it , will be unmasked later */
+               tmp |= 0x1;
+               writel(tmp, base + 4);
+               mpic->fixups[irq].index = i;
+               mpic->fixups[irq].base = base;
+               /* Apple HT PIC has a non-standard way of doing EOIs */
+               if ((vdid & 0xffff) == 0x106b)
+                       mpic->fixups[irq].applebase = devbase + 0x60;
+               else
+                       mpic->fixups[irq].applebase = NULL;
+               writeb(0x11 + 2 * i, base + 2);
+               mpic->fixups[irq].data = readl(base + 4) | 0x80000000;
        }
 }
  
-static void __init mpic_scan_ioapics(struct mpic *mpic)
+
+static void __init mpic_scan_ht_pics(struct mpic *mpic)
 {
        unsigned int devfn;
        u8 __iomem *cfgspace;
 
-       printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n");
+       printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n");
 
        /* Allocate fixups array */
        mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
@@ -237,21 +303,20 @@ static void __init mpic_scan_ioapics(struct mpic *mpic)
        /* Init spinlock */
        spin_lock_init(&mpic->fixup_lock);
 
-       /* Map u3 config space. We assume all IO-APICs are on the primary bus
-        * and slot will never be above "0xf" so we only need to map 32k
+       /* Map U3 config space. We assume all IO-APICs are on the primary bus
+        * so we only need to map 64kB.
         */
-       cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000);
+       cfgspace = ioremap(0xf2000000, 0x10000);
        BUG_ON(cfgspace == NULL);
 
-       /* Now we scan all slots. We do a very quick scan, we read the header type,
-        * vendor ID and device ID only, that's plenty enough
+       /* Now we scan all slots. We do a very quick scan, we read the header
+        * type, vendor ID and device ID only, that's plenty enough
         */
-       for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) {
+       for (devfn = 0; devfn < 0x100; devfn++) {
                u8 __iomem *devbase = cfgspace + (devfn << 8);
                u8 hdr_type = readb(devbase + PCI_HEADER_TYPE);
                u32 l = readl(devbase + PCI_VENDOR_ID);
-               u16 vendor_id, device_id;
-               int multifunc = 0;
+               u16 s;
 
                DBG("devfn %x, l: %x\n", devfn, l);
 
@@ -259,22 +324,16 @@ static void __init mpic_scan_ioapics(struct mpic *mpic)
                if (l == 0xffffffff || l == 0x00000000 ||
                    l == 0x0000ffff || l == 0xffff0000)
                        goto next;
+               /* Check if is supports capability lists */
+               s = readw(devbase + PCI_STATUS);
+               if (!(s & PCI_STATUS_CAP_LIST))
+                       goto next;
+
+               mpic_scan_ht_pic(mpic, devbase, devfn, l);
 
-               /* Check if it's a multifunction device (only really used
-                * to function 0 though
-                */
-               multifunc = !!(hdr_type & 0x80);
-               vendor_id = l & 0xffff;
-               device_id = (l >> 16) & 0xffff;
-
-               /* If a known device, go to fixup setup code */
-               if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460)
-                       mpic_amd8111_read_irq(mpic, devbase);
-               if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450)
-                       mpic_amd8131_read_irq(mpic, devbase);
        next:
                /* next device, if function 0 */
-               if ((PCI_FUNC(devfn) == 0) && !multifunc)
+               if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0)
                        devfn += 7;
        }
 }
@@ -371,6 +430,31 @@ static void mpic_enable_irq(unsigned int irq)
                        break;
                }
        } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);    
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+       if (mpic->flags & MPIC_BROKEN_U3) {
+               unsigned int src = irq - mpic->irq_offset;
+               if (mpic_is_ht_interrupt(mpic, src) &&
+                   (irq_desc[irq].status & IRQ_LEVEL))
+                       mpic_ht_end_irq(mpic, src);
+       }
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+}
+
+static unsigned int mpic_startup_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+       struct mpic *mpic = mpic_from_irq(irq);
+       unsigned int src = irq - mpic->irq_offset;
+
+       if (mpic_is_ht_interrupt(mpic, src))
+               mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+       mpic_enable_irq(irq);
+
+       return 0;
 }
 
 static void mpic_disable_irq(unsigned int irq)
@@ -394,12 +478,27 @@ static void mpic_disable_irq(unsigned int irq)
        } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
 }
 
+static void mpic_shutdown_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+       struct mpic *mpic = mpic_from_irq(irq);
+       unsigned int src = irq - mpic->irq_offset;
+
+       if (mpic_is_ht_interrupt(mpic, src))
+               mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+       mpic_disable_irq(irq);
+}
+
 static void mpic_end_irq(unsigned int irq)
 {
        struct mpic *mpic = mpic_from_irq(irq);
 
+#ifdef DEBUG_IRQ
        DBG("%s: end_irq: %d\n", mpic->name, irq);
-
+#endif
        /* We always EOI on end_irq() even for edge interrupts since that
         * should only lower the priority, the MPIC should have properly
         * latched another edge interrupt coming in anyway
@@ -408,8 +507,9 @@ static void mpic_end_irq(unsigned int irq)
 #ifdef CONFIG_MPIC_BROKEN_U3
        if (mpic->flags & MPIC_BROKEN_U3) {
                unsigned int src = irq - mpic->irq_offset;
-               if (mpic_is_ht_interrupt(mpic, src))
-                       mpic_apic_end_irq(mpic, src);
+               if (mpic_is_ht_interrupt(mpic, src) &&
+                   (irq_desc[irq].status & IRQ_LEVEL))
+                       mpic_ht_end_irq(mpic, src);
        }
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
@@ -490,6 +590,8 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr,
        mpic->name = name;
 
        mpic->hc_irq.typename = name;
+       mpic->hc_irq.startup = mpic_startup_irq;
+       mpic->hc_irq.shutdown = mpic_shutdown_irq;
        mpic->hc_irq.enable = mpic_enable_irq;
        mpic->hc_irq.disable = mpic_disable_irq;
        mpic->hc_irq.end = mpic_end_irq;
@@ -658,10 +760,10 @@ void __init mpic_init(struct mpic *mpic)
                mpic->irq_count = mpic->num_sources;
 
 #ifdef CONFIG_MPIC_BROKEN_U3
-       /* Do the ioapic fixups on U3 broken mpic */
+       /* Do the HT PIC fixups on U3 broken mpic */
        DBG("MPIC flags: %x\n", mpic->flags);
        if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
-               mpic_scan_ioapics(mpic);
+               mpic_scan_ht_pics(mpic);
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
        for (i = 0; i < mpic->num_sources; i++) {
@@ -848,7 +950,9 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
 
        BUG_ON(mpic == NULL);
 
+#ifdef DEBUG_IPI
        DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
+#endif
 
        mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
                       mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
@@ -859,19 +963,28 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
        u32 irq;
 
        irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
+#ifdef DEBUG_LOW
        DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
-
+#endif
        if (mpic->cascade && irq == mpic->cascade_vec) {
+#ifdef DEBUG_LOW
                DBG("%s: cascading ...\n", mpic->name);
+#endif
                irq = mpic->cascade(regs, mpic->cascade_data);
                mpic_eoi(mpic);
                return irq;
        }
        if (unlikely(irq == MPIC_VEC_SPURRIOUS))
                return -1;
-       if (irq < MPIC_VEC_IPI_0) 
+       if (irq < MPIC_VEC_IPI_0) {
+#ifdef DEBUG_IRQ
+               DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset);
+#endif
                return irq + mpic->irq_offset;
+       }
+#ifdef DEBUG_IPI
                DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0);
+#endif
        return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset;
 }
 
index b20312e5ed271784bbeb79495ca122541d68707a..109d874ecfbeaa7980381aba99081a8d9d56481a 100644 (file)
@@ -3,9 +3,5 @@
 ifdef CONFIG_PPC64
 EXTRA_CFLAGS += -mno-minimal-toc
 endif
-
-obj-$(CONFIG_8xx)      += start_8xx.o
-obj-$(CONFIG_6xx)      += start_32.o
-obj-$(CONFIG_4xx)      += start_32.o
-obj-$(CONFIG_PPC64)    += start_64.o
-obj-y                  += xmon.o ppc-dis.o ppc-opc.o setjmp.o nonstdio.o
+obj-y                  += xmon.o ppc-dis.o ppc-opc.o setjmp.o start.o \
+                          nonstdio.o
diff --git a/arch/powerpc/xmon/start_32.c b/arch/powerpc/xmon/start_32.c
deleted file mode 100644 (file)
index c2464df..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- */
-#include <linux/config.h>
-#include <linux/string.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/cuda.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <asm/xmon.h>
-#include <asm/prom.h>
-#include <asm/bootx.h>
-#include <asm/machdep.h>
-#include <asm/errno.h>
-#include <asm/pmac_feature.h>
-#include <asm/processor.h>
-#include <asm/delay.h>
-#include <asm/btext.h>
-#include <asm/time.h>
-#include "nonstdio.h"
-
-static volatile unsigned char __iomem *sccc, *sccd;
-unsigned int TXRDY, RXRDY, DLAB;
-
-static int use_serial;
-static int use_screen;
-static int via_modem;
-static int xmon_use_sccb;
-static struct device_node *channel_node;
-
-void buf_access(void)
-{
-       if (DLAB)
-               sccd[3] &= ~DLAB;       /* reset DLAB */
-}
-
-extern int adb_init(void);
-
-#ifdef CONFIG_PPC_CHRP
-/*
- * This looks in the "ranges" property for the primary PCI host bridge
- * to find the physical address of the start of PCI/ISA I/O space.
- * It is basically a cut-down version of pci_process_bridge_OF_ranges.
- */
-static unsigned long chrp_find_phys_io_base(void)
-{
-       struct device_node *node;
-       unsigned int *ranges;
-       unsigned long base = CHRP_ISA_IO_BASE;
-       int rlen = 0;
-       int np;
-
-       node = find_devices("isa");
-       if (node != NULL) {
-               node = node->parent;
-               if (node == NULL || node->type == NULL
-                   || strcmp(node->type, "pci") != 0)
-                       node = NULL;
-       }
-       if (node == NULL)
-               node = find_devices("pci");
-       if (node == NULL)
-               return base;
-
-       ranges = (unsigned int *) get_property(node, "ranges", &rlen);
-       np = prom_n_addr_cells(node) + 5;
-       while ((rlen -= np * sizeof(unsigned int)) >= 0) {
-               if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
-                       /* I/O space starting at 0, grab the phys base */
-                       base = ranges[np - 3];
-                       break;
-               }
-               ranges += np;
-       }
-       return base;
-}
-#endif /* CONFIG_PPC_CHRP */
-
-void xmon_map_scc(void)
-{
-#ifdef CONFIG_PPC_MULTIPLATFORM
-       volatile unsigned char __iomem *base;
-
-       if (_machine == _MACH_Pmac) {
-               struct device_node *np;
-               unsigned long addr;
-#ifdef CONFIG_BOOTX_TEXT
-               if (!use_screen && !use_serial
-                   && !machine_is_compatible("iMac")) {
-                       /* see if there is a keyboard in the device tree
-                          with a parent of type "adb" */
-                       for (np = find_devices("keyboard"); np; np = np->next)
-                               if (np->parent && np->parent->type
-                                   && strcmp(np->parent->type, "adb") == 0)
-                                       break;
-
-                       /* needs to be hacked if xmon_printk is to be used
-                          from within find_via_pmu() */
-#ifdef CONFIG_ADB_PMU
-                       if (np != NULL && boot_text_mapped && find_via_pmu())
-                               use_screen = 1;
-#endif
-#ifdef CONFIG_ADB_CUDA
-                       if (np != NULL && boot_text_mapped && find_via_cuda())
-                               use_screen = 1;
-#endif
-               }
-               if (!use_screen && (np = find_devices("escc")) != NULL) {
-                       /*
-                        * look for the device node for the serial port
-                        * we're using and see if it says it has a modem
-                        */
-                       char *name = xmon_use_sccb? "ch-b": "ch-a";
-                       char *slots;
-                       int l;
-
-                       np = np->child;
-                       while (np != NULL && strcmp(np->name, name) != 0)
-                               np = np->sibling;
-                       if (np != NULL) {
-                               /* XXX should parse this properly */
-                               channel_node = np;
-                               slots = get_property(np, "slot-names", &l);
-                               if (slots != NULL && l >= 10
-                                   && strcmp(slots+4, "Modem") == 0)
-                                       via_modem = 1;
-                       }
-               }
-               btext_drawstring("xmon uses ");
-               if (use_screen)
-                       btext_drawstring("screen and keyboard\n");
-               else {
-                       if (via_modem)
-                               btext_drawstring("modem on ");
-                       btext_drawstring(xmon_use_sccb? "printer": "modem");
-                       btext_drawstring(" port\n");
-               }
-
-#endif /* CONFIG_BOOTX_TEXT */
-
-#ifdef CHRP_ESCC
-               addr = 0xc1013020;
-#else
-               addr = 0xf3013020;
-#endif
-               TXRDY = 4;
-               RXRDY = 1;
-       
-               np = find_devices("mac-io");
-               if (np && np->n_addrs)
-                       addr = np->addrs[0].address + 0x13020;
-               base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
-               sccc = base + (addr & ~PAGE_MASK);
-               sccd = sccc + 0x10;
-
-       } else {
-               base = (volatile unsigned char *) isa_io_base;
-
-#ifdef CONFIG_PPC_CHRP
-               if (_machine == _MACH_chrp)
-                       base = (volatile unsigned char __iomem *)
-                               ioremap(chrp_find_phys_io_base(), 0x1000);
-#endif
-
-               sccc = base + 0x3fd;
-               sccd = base + 0x3f8;
-               if (xmon_use_sccb) {
-                       sccc -= 0x100;
-                       sccd -= 0x100;
-               }
-               TXRDY = 0x20;
-               RXRDY = 1;
-               DLAB = 0x80;
-       }
-#elif defined(CONFIG_GEMINI)
-       /* should already be mapped by the kernel boot */
-       sccc = (volatile unsigned char __iomem *) 0xffeffb0d;
-       sccd = (volatile unsigned char __iomem *) 0xffeffb08;
-       TXRDY = 0x20;
-       RXRDY = 1;
-       DLAB = 0x80;
-#elif defined(CONFIG_405GP)
-       sccc = (volatile unsigned char __iomem *)0xef600305;
-       sccd = (volatile unsigned char __iomem *)0xef600300;
-       TXRDY = 0x20;
-       RXRDY = 1;
-       DLAB = 0x80;
-#endif /* platform */
-}
-
-static int scc_initialized = 0;
-
-void xmon_init_scc(void);
-extern void cuda_poll(void);
-
-static inline void do_poll_adb(void)
-{
-#ifdef CONFIG_ADB_PMU
-       if (sys_ctrler == SYS_CTRLER_PMU)
-               pmu_poll_adb();
-#endif /* CONFIG_ADB_PMU */
-#ifdef CONFIG_ADB_CUDA
-       if (sys_ctrler == SYS_CTRLER_CUDA)
-               cuda_poll();
-#endif /* CONFIG_ADB_CUDA */
-}
-
-int xmon_write(void *ptr, int nb)
-{
-       char *p = ptr;
-       int i, c, ct;
-
-#ifdef CONFIG_SMP
-       static unsigned long xmon_write_lock;
-       int lock_wait = 1000000;
-       int locked;
-
-       while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
-               if (--lock_wait == 0)
-                       break;
-#endif
-
-#ifdef CONFIG_BOOTX_TEXT
-       if (use_screen) {
-               /* write it on the screen */
-               for (i = 0; i < nb; ++i)
-                       btext_drawchar(*p++);
-               goto out;
-       }
-#endif
-       if (!scc_initialized)
-               xmon_init_scc();
-       ct = 0;
-       for (i = 0; i < nb; ++i) {
-               while ((*sccc & TXRDY) == 0)
-                       do_poll_adb();
-               c = p[i];
-               if (c == '\n' && !ct) {
-                       c = '\r';
-                       ct = 1;
-                       --i;
-               } else {
-                       ct = 0;
-               }
-               buf_access();
-               *sccd = c;
-               eieio();
-       }
-
- out:
-#ifdef CONFIG_SMP
-       if (!locked)
-               clear_bit(0, &xmon_write_lock);
-#endif
-       return nb;
-}
-
-int xmon_wants_key;
-int xmon_adb_keycode;
-
-#ifdef CONFIG_BOOTX_TEXT
-static int xmon_adb_shiftstate;
-
-static unsigned char xmon_keytab[128] =
-       "asdfhgzxcv\000bqwer"                           /* 0x00 - 0x0f */
-       "yt123465=97-80]o"                              /* 0x10 - 0x1f */
-       "u[ip\rlj'k;\\,/nm."                            /* 0x20 - 0x2f */
-       "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
-       "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
-       "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
-
-static unsigned char xmon_shift_keytab[128] =
-       "ASDFHGZXCV\000BQWER"                           /* 0x00 - 0x0f */
-       "YT!@#$^%+(&_*)}O"                              /* 0x10 - 0x1f */
-       "U{IP\rLJ\"K:|<?NM>"                            /* 0x20 - 0x2f */
-       "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
-       "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
-       "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
-
-static int xmon_get_adb_key(void)
-{
-       int k, t, on;
-
-       xmon_wants_key = 1;
-       for (;;) {
-               xmon_adb_keycode = -1;
-               t = 0;
-               on = 0;
-               do {
-                       if (--t < 0) {
-                               on = 1 - on;
-                               btext_drawchar(on? 0xdb: 0x20);
-                               btext_drawchar('\b');
-                               t = 200000;
-                       }
-                       do_poll_adb();
-               } while (xmon_adb_keycode == -1);
-               k = xmon_adb_keycode;
-               if (on)
-                       btext_drawstring(" \b");
-
-               /* test for shift keys */
-               if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
-                       xmon_adb_shiftstate = (k & 0x80) == 0;
-                       continue;
-               }
-               if (k >= 0x80)
-                       continue;       /* ignore up transitions */
-               k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
-               if (k != 0)
-                       break;
-       }
-       xmon_wants_key = 0;
-       return k;
-}
-#endif /* CONFIG_BOOTX_TEXT */
-
-int xmon_readchar(void)
-{
-#ifdef CONFIG_BOOTX_TEXT
-       if (use_screen)
-               return xmon_get_adb_key();
-#endif
-       if (!scc_initialized)
-               xmon_init_scc();
-       while ((*sccc & RXRDY) == 0)
-               do_poll_adb();
-       buf_access();
-       return *sccd;
-}
-
-int xmon_read_poll(void)
-{
-       if ((*sccc & RXRDY) == 0) {
-               do_poll_adb();
-               return -1;
-       }
-       buf_access();
-       return *sccd;
-}
-
-static unsigned char scc_inittab[] = {
-    13, 0,             /* set baud rate divisor */
-    12, 1,
-    14, 1,             /* baud rate gen enable, src=rtxc */
-    11, 0x50,          /* clocks = br gen */
-    5,  0xea,          /* tx 8 bits, assert DTR & RTS */
-    4,  0x46,          /* x16 clock, 1 stop */
-    3,  0xc1,          /* rx enable, 8 bits */
-};
-
-void xmon_init_scc(void)
-{
-       if ( _machine == _MACH_chrp )
-       {
-               sccd[3] = 0x83; eieio();        /* LCR = 8N1 + DLAB */
-               sccd[0] = 12; eieio();          /* DLL = 9600 baud */
-               sccd[1] = 0; eieio();
-               sccd[2] = 0; eieio();           /* FCR = 0 */
-               sccd[3] = 3; eieio();           /* LCR = 8N1 */
-               sccd[1] = 0; eieio();           /* IER = 0 */
-       }
-       else if ( _machine == _MACH_Pmac )
-       {
-               int i, x;
-               unsigned long timeout;
-
-               if (channel_node != 0)
-                       pmac_call_feature(
-                               PMAC_FTR_SCC_ENABLE,
-                               channel_node,
-                               PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
-                       printk(KERN_INFO "Serial port locked ON by debugger !\n");
-               if (via_modem && channel_node != 0) {
-                       unsigned int t0;
-
-                       pmac_call_feature(
-                               PMAC_FTR_MODEM_ENABLE,
-                               channel_node, 0, 1);
-                       printk(KERN_INFO "Modem powered up by debugger !\n");
-                       t0 = get_tbl();
-                       timeout = 3 * tb_ticks_per_sec;
-                       if (timeout == 0)
-                               /* assume 25MHz if tb_ticks_per_sec not set */
-                               timeout = 75000000;
-                       while (get_tbl() - t0 < timeout)
-                               eieio();
-               }
-               /* use the B channel if requested */
-               if (xmon_use_sccb) {
-                       sccc = (volatile unsigned char *)
-                               ((unsigned long)sccc & ~0x20);
-                       sccd = sccc + 0x10;
-               }
-               for (i = 20000; i != 0; --i) {
-                       x = *sccc; eieio();
-               }
-               *sccc = 9; eieio();             /* reset A or B side */
-               *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
-               for (i = 0; i < sizeof(scc_inittab); ++i) {
-                       *sccc = scc_inittab[i];
-                       eieio();
-               }
-       }
-       scc_initialized = 1;
-       if (via_modem) {
-               for (;;) {
-                       xmon_write("ATE1V1\r", 7);
-                       if (xmon_expect("OK", 5)) {
-                               xmon_write("ATA\r", 4);
-                               if (xmon_expect("CONNECT", 40))
-                                       break;
-                       }
-                       xmon_write("+++", 3);
-                       xmon_expect("OK", 3);
-               }
-       }
-}
-
-void xmon_enter(void)
-{
-#ifdef CONFIG_ADB_PMU
-       if (_machine == _MACH_Pmac) {
-               pmu_suspend();
-       }
-#endif
-}
-
-void xmon_leave(void)
-{
-#ifdef CONFIG_ADB_PMU
-       if (_machine == _MACH_Pmac) {
-               pmu_resume();
-       }
-#endif
-}
diff --git a/arch/powerpc/xmon/start_8xx.c b/arch/powerpc/xmon/start_8xx.c
deleted file mode 100644 (file)
index 4c17b04..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- * Copyright (C) 2000 Dan Malek.
- * Quick hack of Paul's code to make XMON work on 8xx processors.  Lots
- * of assumptions, like the SMC1 is used, it has been initialized by the
- * loader at some point, and we can just stuff and suck bytes.
- * We rely upon the 8xx uart driver to support us, as the interface
- * changes between boot up and operational phases of the kernel.
- */
-#include <linux/string.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <linux/kernel.h>
-#include <asm/8xx_immap.h>
-#include <asm/mpc8xx.h>
-#include <asm/commproc.h>
-#include "nonstdio.h"
-
-extern int xmon_8xx_write(char *str, int nb);
-extern int xmon_8xx_read_poll(void);
-extern int xmon_8xx_read_char(void);
-
-void xmon_map_scc(void)
-{
-       cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-}
-
-void xmon_init_scc(void);
-
-int xmon_write(void *ptr, int nb)
-{
-       return(xmon_8xx_write(ptr, nb));
-}
-
-int xmon_readchar(void)
-{
-       return xmon_8xx_read_char();
-}
-
-int xmon_read_poll(void)
-{
-       return(xmon_8xx_read_poll());
-}
index c45a6ad5f3b75d55dfe0d44a78b5dd255bb7ffde..22612ed5379c46d0c0482759f873261298522d91 100644 (file)
@@ -450,7 +450,6 @@ int xmon_core(struct pt_regs *regs, int fromipi)
  leave:
        cpu_clear(cpu, cpus_in_xmon);
        xmon_fault_jmp[cpu] = NULL;
-
 #else
        /* UP is simple... */
        if (in_xmon) {
@@ -805,7 +804,10 @@ cmds(struct pt_regs *excp)
                        break;
                case 'x':
                case 'X':
+                       return cmd;
                case EOF:
+                       printf(" <no input ...>\n");
+                       mdelay(2000);
                        return cmd;
                case '?':
                        printf(help_string);
@@ -1011,7 +1013,7 @@ static long check_bp_loc(unsigned long addr)
        unsigned int instr;
 
        addr &= ~3;
-       if (addr < KERNELBASE) {
+       if (!is_kernel_addr(addr)) {
                printf("Breakpoints may only be placed at kernel addresses\n");
                return 0;
        }
@@ -1062,7 +1064,7 @@ bpt_cmds(void)
                dabr.address = 0;
                dabr.enabled = 0;
                if (scanhex(&dabr.address)) {
-                       if (dabr.address < KERNELBASE) {
+                       if (!is_kernel_addr(dabr.address)) {
                                printf(badaddr);
                                break;
                        }
index cc3f64c084c5e886b29eadd081c77edc5bcace91..e396f4591d59a3083c1c42f8fdd3ca771b5498a4 100644 (file)
@@ -8,9 +8,6 @@ config MMU
        bool
        default y
 
-config UID16
-       bool
-
 config GENERIC_HARDIRQS
        bool
        default y
index c96c9f80521ec13dd974d0d96c7629a886d181db..368ec035e6cd988986c0c590ede9dd2090cdf276 100644 (file)
@@ -234,7 +234,8 @@ udelay:
  * First, flush the data cache in case it was enabled and may be
  * holding instructions for copy back.
  */
-_GLOBAL(flush_instruction_cache)
+        .globl flush_instruction_cache
+flush_instruction_cache:        
        mflr    r6
        bl      flush_data_cache
 
@@ -279,7 +280,8 @@ _GLOBAL(flush_instruction_cache)
  * Flush data cache
  * Do this by just reading lots of stuff into the cache.
  */
-_GLOBAL(flush_data_cache)
+        .globl flush_data_cache
+flush_data_cache:       
        lis     r3,cache_flush_buffer@h
        ori     r3,r3,cache_flush_buffer@l
        li      r4,NUM_CACHE_LINES
index 532e7ef1edb6229405496e85dbd5cb3f12301f07..58415d5718e35eab594c118d81d98aa3f4d4c9b2 100644 (file)
@@ -26,7 +26,7 @@ quiet_cmd_uimage = UIMAGE  $@
 targets += uImage
 $(obj)/uImage: $(obj)/vmlinux.gz
        $(Q)rm -f $@
-       $(call if_changed,uimage)
+       $(call cmd,uimage)
        @echo -n '  Image: $@ '
        @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
 
diff --git a/arch/ppc/configs/TQM8540_defconfig b/arch/ppc/configs/TQM8540_defconfig
new file mode 100644 (file)
index 0000000..99bf3b7
--- /dev/null
@@ -0,0 +1,973 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Fri Nov 25 17:26:50 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD 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"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+CONFIG_TQM8540=y
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8540=y
+
+#
+# Platform options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT 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=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 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
+# 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_NET_DIVERT 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 is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+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=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# 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
+# 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_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 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
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM 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
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+
+#
+# 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_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI 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
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# 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_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# 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_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 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_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# 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_PC87360 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_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# 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_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_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY 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=y
+# 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 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_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/TQM8541_defconfig b/arch/ppc/configs/TQM8541_defconfig
new file mode 100644 (file)
index 0000000..0ff5669
--- /dev/null
@@ -0,0 +1,986 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Wed Nov 30 13:36:28 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD 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"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+CONFIG_TQM8541=y
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8555=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT 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=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 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
+# 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_NET_DIVERT 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 is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+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=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# 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
+# 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_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 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
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM 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
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+
+#
+# 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_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_FS_ENET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI 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
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_CPM is not set
+# CONFIG_SERIAL_JSM is not set
+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_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# 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_MPC=y
+# CONFIG_I2C_MPC8260 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_MAX6900 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8563 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 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_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# 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_PC87360 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_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# 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_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_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY 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=y
+# 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 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_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/TQM8555_defconfig b/arch/ppc/configs/TQM8555_defconfig
new file mode 100644 (file)
index 0000000..730b3db
--- /dev/null
@@ -0,0 +1,983 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Thu Nov 24 17:10:52 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD 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"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+CONFIG_TQM8555=y
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8555=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT 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=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 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
+# 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_NET_DIVERT 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 is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+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=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# 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
+# 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_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 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
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM 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
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+
+#
+# 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_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_FS_ENET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI 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
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_CPM is not set
+# CONFIG_SERIAL_JSM is not set
+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_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# 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_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# 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_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 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_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# 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_PC87360 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_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# 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_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_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY 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=y
+# 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 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_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/TQM8560_defconfig b/arch/ppc/configs/TQM8560_defconfig
new file mode 100644 (file)
index 0000000..1d90207
--- /dev/null
@@ -0,0 +1,992 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Wed Nov 30 16:47:53 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD 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"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8555 is not set
+CONFIG_TQM8560=y
+CONFIG_MPC8560=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT 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=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 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
+# 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_NET_DIVERT 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 is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+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=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# 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
+# 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_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 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
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM 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
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+
+#
+# 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_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_FS_ENET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI 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
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+CONFIG_SERIAL_CPM_SCC1=y
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+# CONFIG_SERIAL_CPM_SMC1 is not set
+# CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
+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_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# 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_MPC=y
+# CONFIG_I2C_MPC8260 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_MAX6900 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8563 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 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_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# 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_PC87360 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_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# 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_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_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY 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=y
+# 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 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_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
index 0bb23fce42935e6e51e826cdfd991449b3cdadfa..e6c1d615bb860879d684da4d40f41a6a66a9608f 100644 (file)
@@ -49,5 +49,4 @@ obj-$(CONFIG_TAU)             += temp.o
 ifndef CONFIG_E200
 obj-$(CONFIG_FSL_BOOKE)                += perfmon_fsl_booke.o
 endif
-obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
 endif
index fe0e767fb94ed51f916ce087be3f5efdbd70ea8f..7964bf660e9274b9abb460d548a5c368db591809 100644 (file)
@@ -131,7 +131,7 @@ main(void)
        DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
        DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
 
-       DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
+       DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame));
        DEFINE(TI_TASK, offsetof(struct thread_info, task));
        DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
        DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
index f044edbb454fe68abf869909a9a180829997e1aa..a48b950722a11385059b6606057b1d34f20ca3fc 100644 (file)
@@ -200,8 +200,6 @@ _GLOBAL(DoSyscall)
        bl      do_show_syscall
 #endif /* SHOW_SYSCALLS */
        rlwinm  r10,r1,0,0,18   /* current_thread_info() */
-       li      r11,0
-       stb     r11,TI_SC_NOERR(r10)
        lwz     r11,TI_FLAGS(r10)
        andi.   r11,r11,_TIF_SYSCALL_T_OR_A
        bne-    syscall_dotrace
@@ -222,25 +220,21 @@ ret_from_syscall:
        bl      do_show_syscall_exit
 #endif
        mr      r6,r3
-       li      r11,-_LAST_ERRNO
-       cmplw   0,r3,r11
        rlwinm  r12,r1,0,0,18   /* current_thread_info() */
-       blt+    30f
-       lbz     r11,TI_SC_NOERR(r12)
-       cmpwi   r11,0
-       bne     30f
-       neg     r3,r3
-       lwz     r10,_CCR(r1)    /* Set SO bit in CR */
-       oris    r10,r10,0x1000
-       stw     r10,_CCR(r1)
-
        /* disable interrupts so current_thread_info()->flags can't change */
-30:    LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
+       LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
        SYNC
        MTMSRD(r10)
        lwz     r9,TI_FLAGS(r12)
-       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+       li      r8,-_LAST_ERRNO
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
        bne-    syscall_exit_work
+       cmplw   0,r3,r8
+       blt+    syscall_exit_cont
+       lwz     r11,_CCR(r1)                    /* Load CR */
+       neg     r3,r3
+       oris    r11,r11,0x1000  /* Set SO bit in CR */
+       stw     r11,_CCR(r1)
 syscall_exit_cont:
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
        /* If the process has its own DBCR0 value, load it up.  The single
@@ -292,46 +286,113 @@ syscall_dotrace:
        b       syscall_dotrace_cont
 
 syscall_exit_work:
-       stw     r6,RESULT(r1)   /* Save result */
+       andi.   r0,r9,_TIF_RESTOREALL
+       bne-    2f
+       cmplw   0,r3,r8
+       blt+    1f
+       andi.   r0,r9,_TIF_NOERROR
+       bne-    1f
+       lwz     r11,_CCR(r1)                    /* Load CR */
+       neg     r3,r3
+       oris    r11,r11,0x1000  /* Set SO bit in CR */
+       stw     r11,_CCR(r1)
+
+1:     stw     r6,RESULT(r1)   /* Save result */
        stw     r3,GPR3(r1)     /* Update return value */
-       andi.   r0,r9,_TIF_SYSCALL_T_OR_A
-       beq     5f
-       ori     r10,r10,MSR_EE
-       SYNC
-       MTMSRD(r10)             /* re-enable interrupts */
+2:     andi.   r0,r9,(_TIF_PERSYSCALL_MASK)
+       beq     4f
+
+       /* Clear per-syscall TIF flags if any are set, but _leave_
+       _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+       yet.  */
+
+       li      r11,_TIF_PERSYSCALL_MASK
+       addi    r12,r12,TI_FLAGS
+3:     lwarx   r8,0,r12
+       andc    r8,r8,r11
+#ifdef CONFIG_IBM405_ERR77
+       dcbt    0,r12
+#endif
+       stwcx.  r8,0,r12
+       bne-    3b
+       subi    r12,r12,TI_FLAGS
+       
+4:     /* Anything which requires enabling interrupts? */
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+       beq     7f
+
+       /* Save NVGPRS if they're not saved already */
        lwz     r4,TRAP(r1)
        andi.   r4,r4,1
-       beq     4f
+       beq     5f
        SAVE_NVGPRS(r1)
        li      r4,0xc00
        stw     r4,TRAP(r1)
-4:
+
+       /* Re-enable interrupts */
+5:     ori     r10,r10,MSR_EE
+       SYNC
+       MTMSRD(r10)
+
+       andi.   r0,r9,_TIF_SAVE_NVGPRS
+       bne     save_user_nvgprs
+
+save_user_nvgprs_cont:
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+       beq     7f
+
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      do_syscall_trace_leave
        REST_NVGPRS(r1)
-2:
-       lwz     r3,GPR3(r1)
+
+6:     lwz     r3,GPR3(r1)
        LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
        SYNC
        MTMSRD(r10)             /* disable interrupts again */
        rlwinm  r12,r1,0,0,18   /* current_thread_info() */
        lwz     r9,TI_FLAGS(r12)
-5:
+7:
        andi.   r0,r9,_TIF_NEED_RESCHED
-       bne     1f
+       bne     8f
        lwz     r5,_MSR(r1)
        andi.   r5,r5,MSR_PR
-       beq     syscall_exit_cont
+       beq     ret_from_except
        andi.   r0,r9,_TIF_SIGPENDING
-       beq     syscall_exit_cont
+       beq     ret_from_except
        b       do_user_signal
-1:
+8:
        ori     r10,r10,MSR_EE
        SYNC
        MTMSRD(r10)             /* re-enable interrupts */
        bl      schedule
-       b       2b
+       b       6b
+
+save_user_nvgprs:
+       lwz     r8,TI_SIGFRAME(r12)
+
+.macro savewords start, end
+  1:   stw \start,4*(\start)(r8)
+       .section __ex_table,"a"
+       .align  2
+       .long   1b,save_user_nvgprs_fault
+       .previous
+       .if \end - \start
+       savewords "(\start+1)",\end
+       .endif
+.endm  
+       savewords 14,31
+       b       save_user_nvgprs_cont
+
+       
+save_user_nvgprs_fault:
+       li      r3,11           /* SIGSEGV */
+       lwz     r4,TI_TASK(r12)
+       bl      force_sigsegv
 
+       rlwinm  r12,r1,0,0,18   /* current_thread_info() */
+       lwz     r9,TI_FLAGS(r12)
+       b       save_user_nvgprs_cont
+       
 #ifdef SHOW_SYSCALLS
 do_show_syscall:
 #ifdef SHOW_SYSCALLS_TASK
@@ -401,28 +462,10 @@ show_syscalls_task:
 #endif /* SHOW_SYSCALLS */
 
 /*
- * The sigsuspend and rt_sigsuspend system calls can call do_signal
- * and thus put the process into the stopped state where we might
- * want to examine its user state with ptrace.  Therefore we need
- * to save all the nonvolatile registers (r13 - r31) before calling
- * the C code.
+ * The fork/clone functions need to copy the full register set into
+ * the child process. Therefore we need to save all the nonvolatile
+ * registers (r13 - r31) before calling the C code.
  */
-       .globl  ppc_sigsuspend
-ppc_sigsuspend:
-       SAVE_NVGPRS(r1)
-       lwz     r0,TRAP(r1)
-       rlwinm  r0,r0,0,0,30            /* clear LSB to indicate full */
-       stw     r0,TRAP(r1)             /* register set saved */
-       b       sys_sigsuspend
-
-       .globl  ppc_rt_sigsuspend
-ppc_rt_sigsuspend:
-       SAVE_NVGPRS(r1)
-       lwz     r0,TRAP(r1)
-       rlwinm  r0,r0,0,0,30
-       stw     r0,TRAP(r1)
-       b       sys_rt_sigsuspend
-
        .globl  ppc_fork
 ppc_fork:
        SAVE_NVGPRS(r1)
@@ -447,14 +490,6 @@ ppc_clone:
        stw     r0,TRAP(r1)             /* register set saved */
        b       sys_clone
 
-       .globl  ppc_swapcontext
-ppc_swapcontext:
-       SAVE_NVGPRS(r1)
-       lwz     r0,TRAP(r1)
-       rlwinm  r0,r0,0,0,30            /* clear LSB to indicate full */
-       stw     r0,TRAP(r1)             /* register set saved */
-       b       sys_swapcontext
-
 /*
  * Top-level page fault handling.
  * This is in assembler because if do_page_fault tells us that
@@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
        .long   ret_from_except
 #endif
 
-       .globl  sigreturn_exit
-sigreturn_exit:
-       subi    r1,r3,STACK_FRAME_OVERHEAD
-       rlwinm  r12,r1,0,0,18   /* current_thread_info() */
-       lwz     r9,TI_FLAGS(r12)
-       andi.   r0,r9,_TIF_SYSCALL_T_OR_A
-       beq+    ret_from_except_full
-       bl      do_syscall_trace_leave
-       /* fall through */
-
        .globl  ret_from_except_full
 ret_from_except_full:
        REST_NVGPRS(r1)
@@ -658,7 +683,7 @@ user_exc_return:            /* r10 contains MSR_KERNEL here */
        /* Check current_thread_info()->flags */
        rlwinm  r9,r1,0,0,18
        lwz     r9,TI_FLAGS(r9)
-       andi.   r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+       andi.   r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
        bne     do_work
 
 restore_user:
index 5e61124581d03fda7f374379eb76ae7176240fc8..fb5658bba28592e9b55ac75ba1ae373a9fb21ca9 100644 (file)
@@ -1197,7 +1197,7 @@ _GLOBAL(sys_call_table)
        .long sys_ssetmask
        .long sys_setreuid      /* 70 */
        .long sys_setregid
-       .long ppc_sigsuspend
+       .long sys_sigsuspend
        .long sys_sigpending
        .long sys_sethostname
        .long sys_setrlimit     /* 75 */
@@ -1303,7 +1303,7 @@ _GLOBAL(sys_call_table)
        .long sys_rt_sigpending /* 175 */
        .long sys_rt_sigtimedwait
        .long sys_rt_sigqueueinfo
-       .long ppc_rt_sigsuspend
+       .long sys_rt_sigsuspend
        .long sys_pread64
        .long sys_pwrite64      /* 180 */
        .long sys_chown
@@ -1374,7 +1374,7 @@ _GLOBAL(sys_call_table)
        .long sys_clock_gettime
        .long sys_clock_getres
        .long sys_clock_nanosleep
-       .long ppc_swapcontext
+       .long sys_swapcontext
        .long sys_tgkill        /* 250 */
        .long sys_utimes
        .long sys_statfs64
index f7fae5f153b2b55a7aff720947f76255bcc69179..50c75eec8874d6c10a6ca73b6acf3c75aab0ddc6 100644 (file)
@@ -815,8 +815,7 @@ EXPORT_SYMBOL(pci_device_to_OF_node);
  * to set pci_assign_all_buses to 1 and still use RTAS for PCI
  * config cycles.
  */
-struct pci_controller*
-pci_find_hose_for_OF_device(struct device_node* node)
+struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
 {
        if (!have_of)
                return NULL;
@@ -942,7 +941,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
        while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
                res = NULL;
                size = ranges[na+4];
-               switch (ranges[0] >> 24) {
+               switch ((ranges[0] >> 24) & 0x3) {
                case 1:         /* I/O space */
                        if (ranges[2] != 0)
                                break;
@@ -956,6 +955,8 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
                        res = &hose->io_resource;
                        res->flags = IORESOURCE_IO;
                        res->start = ranges[2];
+                       DBG("PCI: IO 0x%lx -> 0x%lx\n",
+                                   res->start, res->start + size - 1);
                        break;
                case 2:         /* memory space */
                        memno = 0;
@@ -973,7 +974,11 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
                        if (memno < 3) {
                                res = &hose->mem_resources[memno];
                                res->flags = IORESOURCE_MEM;
+                               if(ranges[0] & 0x40000000)
+                                       res->flags |= IORESOURCE_PREFETCH;
                                res->start = ranges[na+2];
+                               DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno,
+                                           res->start, res->start + size - 1);
                        }
                        break;
                }
@@ -1806,6 +1811,23 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
 
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       struct pci_controller* hose = hose_head;
+
+       for (; hose; hose = hose->next) {
+               unsigned int size = hose->io_resource.end -
+                       hose->io_resource.start + 1;
+               if (address >= hose->io_base_phys &&
+                   address < (hose->io_base_phys + size)) {
+                       unsigned long base =
+                               (unsigned long)hose->io_base_virt - _IO_BASE;
+                       return base + (address - hose->io_base_phys);
+               }
+       }
+       return (unsigned int)-1;
+}
+EXPORT_SYMBOL(pci_address_to_pio);
 
 /*
  * Null PCI config access functions, for the case when we can't
index bb6a5c6a64bee18e1a94ec0968aada425bbd7aa1..95075f99a6d4ea09abfb4c388a019a040d389e1c 100644 (file)
@@ -82,10 +82,6 @@ EXPORT_SYMBOL(ppc_n_lost_interrupts);
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
 EXPORT_SYMBOL(DMA_MODE_READ);
 EXPORT_SYMBOL(DMA_MODE_WRITE);
-#if defined(CONFIG_PPC_PREP)
-EXPORT_SYMBOL(_prep_type);
-EXPORT_SYMBOL(ucSystemType);
-#endif
 
 #if !defined(__INLINE_BITOPS)
 EXPORT_SYMBOL(set_bit);
@@ -311,7 +307,6 @@ EXPORT_SYMBOL(__res);
 
 EXPORT_SYMBOL(next_mmu_context);
 EXPORT_SYMBOL(set_context);
-EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */
 EXPORT_SYMBOL(disarm_decr);
 #ifdef CONFIG_PPC_STD_MMU
 extern long mol_trampoline;
index 0eb0b7085e6a86f9e9b18df12dac6f0ad03d89f0..e707c6f6e61bdd729d2309befc78fc082083f300 100644 (file)
@@ -744,6 +744,9 @@ void __init setup_arch(char **cmdline_p)
        /* so udelay does something sensible, assume <= 1000 bogomips */
        loops_per_jiffy = 500000000 / HZ;
 
+       if (ppc_md.init_early)
+               ppc_md.init_early();
+
 #ifdef CONFIG_PPC_MULTIPLATFORM
        /* This could be called "early setup arch", it must be done
         * now because xmon need it
index c5bc2821d99162c673aac9a2d1558d4e950a8502..7ddd331a7145e6d65331ece621c414a9777a7e7a 100644 (file)
@@ -39,7 +39,7 @@ config MPC8560_ADS
 config SBC8560
        bool "WindRiver PowerQUICC III SBC8560"
        help
-         This option enables support for the WindRiver PowerQUICC III 
+         This option enables support for the WindRiver PowerQUICC III
          SBC8560 board.
 
 config STX_GP3
@@ -48,6 +48,26 @@ config STX_GP3
          This option enables support for the Silicon Turnkey Express GP3
          board.
 
+config TQM8540
+       bool "TQ Components TQM8540"
+       help
+         This option enablese support for the TQ Components TQM8540 board.
+
+config TQM8541
+       bool "TQ Components TQM8541"
+       help
+         This option enablese support for the TQ Components TQM8541 board.
+
+config TQM8555
+       bool "TQ Components TQM8555"
+       help
+         This option enablese support for the TQ Components TQM8555 board.
+
+config TQM8560
+       bool "TQ Components TQM8560"
+       help
+         This option enablese support for the TQ Components TQM8560 board.
+
 endchoice
 
 # It's often necessary to know the specific 85xx processor type.
@@ -55,7 +75,7 @@ endchoice
 # don't need to ask more redundant questions.
 config MPC8540
        bool
-       depends on MPC8540_ADS
+       depends on MPC8540_ADS || TQM8540
        default y
 
 config MPC8548
@@ -65,12 +85,12 @@ config MPC8548
 
 config MPC8555
        bool
-       depends on MPC8555_CDS
+       depends on MPC8555_CDS || TQM8541 || TQM8555
        default y
 
 config MPC8560
        bool
-       depends on SBC8560 || MPC8560_ADS || STX_GP3
+       depends on SBC8560 || MPC8560_ADS || STX_GP3 || TQM8560
        default y
 
 config 85xx_PCI2
index efdf813108f2fb86c0e7bfff4f7b095db47ee8e2..6c4753c144d39755fcdd50b340fa7f8ae70532b7 100644 (file)
@@ -7,3 +7,7 @@ obj-$(CONFIG_MPC8555_CDS)       += mpc85xx_cds_common.o
 obj-$(CONFIG_MPC8560_ADS)      += mpc85xx_ads_common.o mpc8560_ads.o
 obj-$(CONFIG_SBC8560)          += sbc85xx.o sbc8560.o
 obj-$(CONFIG_STX_GP3)          += stx_gp3.o
+obj-$(CONFIG_TQM8540)          += tqm85xx.o
+obj-$(CONFIG_TQM8541)          += tqm85xx.o
+obj-$(CONFIG_TQM8555)          += tqm85xx.o
+obj-$(CONFIG_TQM8560)          += tqm85xx.o
diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
new file mode 100644 (file)
index 0000000..c6dfd8f
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * arch/ppc/platforms/85xx/tqm85xx.c
+ *
+ * TQM85xx (40/41/55/60) board specific routines
+ *
+ * Copyright (c) 2005 DENX Software Engineering
+ * Stefan Roese <sr@denx.de>
+ *
+ * Based on original work by
+ *     Kumar Gala <galak@kernel.crashing.org>
+ *      Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
+#include <asm/cpm2.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc85xx_setup.h>
+#include <syslib/cpm2_pic.h>
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_rio.h>
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+
+extern unsigned long total_memory;     /* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+static u_char tqm85xx_openpic_initsenses[] __initdata = {
+       MPC85XX_INTERNAL_IRQ_SENSES,
+       0x0,                                            /* External  0: */
+       0x0,                                            /* External  1: */
+#if defined(CONFIG_PCI)
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 2: PCI INTA */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 3: PCI INTB */
+#else
+       0x0,                            /* External  2: */
+       0x0,                            /* External  3: */
+#endif
+       0x0,                            /* External  4: */
+       0x0,                            /* External  5: */
+       0x0,                            /* External  6: */
+       0x0,                            /* External  7: */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 8: PHY */
+       0x0,                            /* External  9: */
+       0x0,                            /* External 10: */
+       0x0,                            /* External 11: */
+};
+
+static const char *GFAR_PHY_0 = "phy0:2";
+static const char *GFAR_PHY_1 = "phy0:1";
+#ifdef CONFIG_MPC8540
+static const char *GFAR_PHY_3 = "phy0:3";
+#endif
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+tqm85xx_setup_arch(void)
+{
+       bd_t *binfo = (bd_t *) __res;
+       unsigned int freq;
+       struct gianfar_platform_data *pdata;
+       struct gianfar_mdio_data *mdata;
+
+#ifdef CONFIG_MPC8560
+       cpm2_reset();
+#endif
+
+       /* get the core frequency */
+       freq = binfo->bi_intfreq;
+
+       if (ppc_md.progress)
+               ppc_md.progress("tqm85xx_setup_arch()", 0);
+
+       /* Set loops_per_jiffy to a half-way reasonable value,
+          for use until calibrate_delay gets called. */
+       loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+       /* setup PCI host bridges */
+       mpc85xx_setup_hose();
+#endif
+
+#ifndef CONFIG_MPC8560
+#if defined(CONFIG_SERIAL_8250)
+       mpc85xx_early_serial_map();
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       /* Invalidate the entry we stole earlier the serial ports
+        * should be properly mapped */
+       invalidate_tlbcam_entry(num_tlbcam_entries - 1);
+#endif
+#endif /* CONFIG_MPC8560 */
+
+       /* setup the board related info for the MDIO bus */
+       mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO);
+
+       mdata->irq[0] = MPC85xx_IRQ_EXT8;
+       mdata->irq[1] = MPC85xx_IRQ_EXT8;
+       mdata->irq[2] = -1;
+       mdata->irq[3] = MPC85xx_IRQ_EXT8;
+       mdata->irq[31] = -1;
+       mdata->paddr += binfo->bi_immr_base;
+
+       /* setup the board related information for the enet controllers */
+       pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->bus_id = GFAR_PHY_0;
+               memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+       }
+
+       pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
+       if (pdata) {
+               pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+               pdata->bus_id = GFAR_PHY_1;
+               memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+       }
+
+#ifdef CONFIG_MPC8540
+       pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
+       if (pdata) {
+               pdata->board_flags = 0;
+               pdata->bus_id = GFAR_PHY_3;
+               memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
+       }
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else
+#endif
+#ifdef  CONFIG_ROOT_NFS
+               ROOT_DEV = Root_NFS;
+#else
+       ROOT_DEV = Root_HDA1;
+#endif
+}
+
+#ifdef CONFIG_MPC8560
+static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+       while ((irq = cpm2_get_irq(regs)) >= 0)
+               __do_IRQ(irq, regs);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction cpm2_irqaction = {
+       .handler = cpm2_cascade,
+       .flags = SA_INTERRUPT,
+       .mask = CPU_MASK_NONE,
+       .name = "cpm2_cascade",
+};
+#endif /* CONFIG_MPC8560 */
+
+void __init
+tqm85xx_init_IRQ(void)
+{
+       bd_t *binfo = (bd_t *) __res;
+
+       /* Determine the Physical Address of the OpenPIC regs */
+       phys_addr_t OpenPIC_PAddr =
+               binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+       OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+       OpenPIC_InitSenses = tqm85xx_openpic_initsenses;
+       OpenPIC_NumInitSenses = sizeof (tqm85xx_openpic_initsenses);
+
+       /* Skip reserved space and internal sources */
+       openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+
+       /* Map PIC IRQs 0-11 */
+       openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000);
+
+       /* we let openpic interrupts starting from an offset, to
+        * leave space for cascading interrupts underneath.
+        */
+       openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+#ifdef CONFIG_MPC8560
+       /* Setup CPM2 PIC */
+        cpm2_init_IRQ();
+
+       setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
+#endif /* CONFIG_MPC8560 */
+
+       return;
+}
+
+int tqm85xx_show_cpuinfo(struct seq_file *m)
+{
+       uint pvid, svid, phid1;
+       uint memsize = total_memory;
+       bd_t *binfo = (bd_t *) __res;
+       unsigned int freq;
+
+       /* get the core frequency */
+       freq = binfo->bi_intfreq;
+
+       pvid = mfspr(SPRN_PVR);
+       svid = mfspr(SPRN_SVR);
+
+       seq_printf(m, "Vendor\t\t: TQ Components\n");
+       seq_printf(m, "Machine\t\t: TQM%s\n", cur_ppc_sys_spec->ppc_sys_name);
+       seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
+       seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+       seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+       /* Display cpu Pll setting */
+       phid1 = mfspr(SPRN_HID1);
+       seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+       /* Display the amount of memory */
+       seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+
+       return 0;
+}
+
+#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_DS1337)
+extern ulong ds1337_get_rtc_time(void);
+extern int ds1337_set_rtc_time(unsigned long nowtime);
+
+static int __init
+tqm85xx_rtc_hookup(void)
+{
+       struct timespec tv;
+
+        ppc_md.set_rtc_time = ds1337_set_rtc_time;
+        ppc_md.get_rtc_time = ds1337_get_rtc_time;
+
+       tv.tv_nsec = 0;
+       tv.tv_sec = (ppc_md.get_rtc_time)();
+       do_settimeofday(&tv);
+
+       return 0;
+}
+late_initcall(tqm85xx_rtc_hookup);
+#endif
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+       static char pci_irq_table[][4] =
+               /*
+                *      PCI IDSEL/INTPIN->INTLINE
+                *       A      B      C      D
+                */
+               {
+                       {PIRQA, PIRQB, 0, 0},
+               };
+
+       const long min_idsel = 0x1c, max_idsel = 0x1c, irqs_per_slot = 4;
+       return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+       if (bus == 0 && PCI_SLOT(devfn) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       else
+               return PCIBIOS_SUCCESSFUL;
+}
+
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_RAPIDIO
+void platform_rio_init(void)
+{
+       /* 512MB RIO LAW at 0xc0000000 */
+       mpc85xx_rio_setup(0xc0000000, 0x20000000);
+}
+#endif /* CONFIG_RAPIDIO */
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       /* parse_bootinfo must always be called first */
+       parse_bootinfo(find_bootinfo());
+
+       /*
+        * If we were passed in a board information, copy it into the
+        * residual data area.
+        */
+       if (r3) {
+               memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+                      sizeof (bd_t));
+       }
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && !defined(CONFIG_MPC8560)
+       {
+               bd_t *binfo = (bd_t *) __res;
+               struct uart_port p;
+
+               /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+               settlbcam(num_tlbcam_entries - 1, binfo->bi_immr_base,
+                         binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+
+               memset(&p, 0, sizeof (p));
+               p.iotype = SERIAL_IO_MEM;
+               p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART0_OFFSET;
+               p.uartclk = binfo->bi_busfreq;
+
+               gen550_init(0, &p);
+
+               memset(&p, 0, sizeof (p));
+               p.iotype = SERIAL_IO_MEM;
+               p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART1_OFFSET;
+               p.uartclk = binfo->bi_busfreq;
+
+               gen550_init(1, &p);
+       }
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+       /*
+        * If the init RAM disk has been configured in, and there's a valid
+        * starting address for it, set it up.
+        */
+       if (r4) {
+               initrd_start = r4 + KERNELBASE;
+               initrd_end = r5 + KERNELBASE;
+       }
+#endif                         /* CONFIG_BLK_DEV_INITRD */
+
+       /* Copy the kernel command line arguments to a safe place. */
+
+       if (r6) {
+               *(char *) (r7 + KERNELBASE) = 0;
+               strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+       }
+
+       identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+       /* setup the PowerPC module struct */
+       ppc_md.setup_arch = tqm85xx_setup_arch;
+       ppc_md.show_cpuinfo = tqm85xx_show_cpuinfo;
+
+       ppc_md.init_IRQ = tqm85xx_init_IRQ;
+       ppc_md.get_irq = openpic_get_irq;
+
+       ppc_md.restart = mpc85xx_restart;
+       ppc_md.power_off = mpc85xx_power_off;
+       ppc_md.halt = mpc85xx_halt;
+
+       ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+       ppc_md.time_init = NULL;
+       ppc_md.set_rtc_time = NULL;
+       ppc_md.get_rtc_time = NULL;
+       ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#ifndef CONFIG_MPC8560
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+       ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
+       ppc_md.early_serial_map = mpc85xx_early_serial_map;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */
+#endif /* CONFIG_MPC8560 */
+
+       if (ppc_md.progress)
+               ppc_md.progress("tqm85xx_init(): exit", 0);
+
+       return;
+}
diff --git a/arch/ppc/platforms/85xx/tqm85xx.h b/arch/ppc/platforms/85xx/tqm85xx.h
new file mode 100644 (file)
index 0000000..3775eb3
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * arch/ppc/platforms/85xx/tqm85xx.h
+ *
+ * TQM85xx (40/41/55/60) board definitions
+ *
+ * Copyright (c) 2005 DENX Software Engineering
+ * Stefan Roese <sr@denx.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.
+ *
+ */
+
+#ifndef __MACH_TQM85XX_H
+#define __MACH_TQM85XX_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/ppcboot.h>
+
+#define BOARD_CCSRBAR          ((uint)0xe0000000)
+#define CCSRBAR_SIZE           ((uint)1024*1024)
+
+#define CPM_MAP_ADDR           (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#define PCI_CFG_ADDR_OFFSET    (0x8000)
+#define PCI_CFG_DATA_OFFSET    (0x8004)
+
+/* PCI interrupt controller */
+#define PIRQA                  MPC85xx_IRQ_EXT2
+#define PIRQB                  MPC85xx_IRQ_EXT3
+
+#define MPC85XX_PCI1_LOWER_IO  0x00000000
+#define MPC85XX_PCI1_UPPER_IO  0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM 0x80000000
+#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE   0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET        0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE   0x01000000
+
+#define BASE_BAUD 115200
+
+extern void mpc85xx_setup_hose(void) __init;
+extern void mpc85xx_restart(char *cmd);
+extern void mpc85xx_power_off(void);
+extern void mpc85xx_halt(void);
+extern void mpc85xx_init_IRQ(void) __init;
+extern unsigned long mpc85xx_find_end_of_memory(void) __init;
+extern void mpc85xx_calibrate_decr(void) __init;
+
+#endif /* __MACH_TQM85XX_H */
index f1b70ab3c6fd892a34ef182427e32e63e0c52c2b..056ac2a7b5c15bc0bebc2dcd4fbf903284910363 100644 (file)
@@ -404,7 +404,6 @@ static struct irqaction xmon_irqaction = {
 void __init chrp_init_IRQ(void)
 {
        struct device_node *np;
-       int i;
        unsigned long chrp_int_ack = 0;
        unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
 #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
index 4415748071dc8836faaa6f4e6752f4cb12e865ca..d065358020030a1c506e1766e9b89c8c67b5ac93 100644 (file)
@@ -72,7 +72,6 @@
 
 TODC_ALLOC();
 
-unsigned char ucSystemType;
 unsigned char ucBoardRev;
 unsigned char ucBoardRevMaj, ucBoardRevMin;
 
@@ -954,7 +953,6 @@ prep_calibrate_decr(void)
 static void __init
 prep_init_IRQ(void)
 {
-       int i;
        unsigned int pci_viddid, pci_did;
 
        if (OpenPIC_Addr != NULL) {
index 5b7f2b80e56e575f37b7597e867f3addee27064e..84ef03018d0e680b3acc479b4cc9772c88a6adf5 100644 (file)
@@ -96,7 +96,7 @@ ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)              += pci_auto.o
 endif
 obj-$(CONFIG_RAPIDIO)          += ppc85xx_rio.o
-obj-$(CONFIG_83xx)             += ipic.o ppc83xx_setup.o ppc_sys.o \
+obj-$(CONFIG_83xx)             += ppc83xx_setup.o ppc_sys.o \
                                        mpc83xx_sys.o mpc83xx_devices.o
 ifeq ($(CONFIG_83xx),y)
 obj-$(CONFIG_PCI)              += pci_auto.o
index 1cc3abe6fa435657b7969024acd52278cedc482f..688616de3cde5ceebdc980a306b66faf60351614 100644 (file)
@@ -135,6 +135,16 @@ static struct irqaction tbint_irqaction = {
        .name = "tbint",
 };
 
+/* per-board overridable init_internal_rtc() function. */
+void __init __attribute__ ((weak))
+init_internal_rtc(void)
+{
+       /* Disable the RTC one second and alarm interrupts. */
+       out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
+       /* Enable the RTC */
+       out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
+}
+
 /* The decrementer counts at the system (internal) clock frequency divided by
  * sixteen, or external oscillator divided by four.  We force the processor
  * to use system clock divided by sixteen.
@@ -183,10 +193,7 @@ void __init m8xx_calibrate_decr(void)
        out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck, KAPWR_KEY);
        out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, KAPWR_KEY);
 
-       /* Disable the RTC one second and alarm interrupts. */
-       out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
-       /* Enable the RTC */
-       out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
+       init_internal_rtc();
 
        /* Enabling the decrementer also enables the timebase interrupts
         * (or from the other point of view, to get decrementer interrupts
index a21632d37e5ab7263f498664ef08ff448625086e..df6c9557b86a4f4889221ef2038d3100cd121898 100644 (file)
@@ -19,6 +19,7 @@
 #include <syslib/m8xx_wdt.h>
 
 static int wdt_timeout;
+int m8xx_has_internal_rtc = 0;
 
 static irqreturn_t m8xx_wdt_interrupt(int, void *, struct pt_regs *);
 static struct irqaction m8xx_wdt_irqaction = {
@@ -45,35 +46,15 @@ static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-void __init m8xx_wdt_handler_install(bd_t * binfo)
+#define SYPCR_SWP 0x1
+#define SYPCR_SWE 0x4
+
+
+void __init m8xx_wdt_install_irq(volatile immap_t *imap, bd_t *binfo)
 {
-       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
        u32 pitc;
-       u32 sypcr;
        u32 pitrtclk;
 
-       sypcr = in_be32(&imap->im_siu_conf.sc_sypcr);
-
-       if (!(sypcr & 0x04)) {
-               printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
-                      sypcr);
-               return;
-       }
-
-       m8xx_wdt_reset();
-
-       printk(KERN_NOTICE
-              "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
-              (sypcr >> 16), sypcr & 0x01);
-
-       wdt_timeout = (sypcr >> 16) & 0xFFFF;
-
-       if (!wdt_timeout)
-               wdt_timeout = 0xFFFF;
-
-       if (sypcr & 0x01)
-               wdt_timeout *= 2048;
-
        /*
         * Fire trigger if half of the wdt ticked down 
         */
@@ -98,6 +79,67 @@ void __init m8xx_wdt_handler_install(bd_t * binfo)
        printk(KERN_NOTICE
               "m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc);
 
+}
+
+static void m8xx_wdt_timer_func(unsigned long data);
+
+static struct timer_list m8xx_wdt_timer =
+       TIMER_INITIALIZER(m8xx_wdt_timer_func, 0, 0);
+
+void m8xx_wdt_stop_timer(void)
+{
+       del_timer(&m8xx_wdt_timer);
+}
+
+void m8xx_wdt_install_timer(void)
+{
+       m8xx_wdt_timer.expires = jiffies + (HZ/2);
+       add_timer(&m8xx_wdt_timer);
+}
+
+static void m8xx_wdt_timer_func(unsigned long data)
+{
+       m8xx_wdt_reset();
+       m8xx_wdt_install_timer();
+}
+
+void __init m8xx_wdt_handler_install(bd_t * binfo)
+{
+       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+       u32 sypcr;
+
+       sypcr = in_be32(&imap->im_siu_conf.sc_sypcr);
+
+       if (!(sypcr & SYPCR_SWE)) {
+               printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
+                      sypcr);
+               return;
+       }
+
+       m8xx_wdt_reset();
+
+       printk(KERN_NOTICE
+              "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
+              (sypcr >> 16), sypcr & SYPCR_SWP);
+
+       wdt_timeout = (sypcr >> 16) & 0xFFFF;
+
+       if (!wdt_timeout)
+               wdt_timeout = 0xFFFF;
+
+       if (sypcr & SYPCR_SWP)
+               wdt_timeout *= 2048;
+
+       m8xx_has_internal_rtc = in_be16(&imap->im_sit.sit_rtcsc) & RTCSC_RTE;
+
+       /* if the internal RTC is off use a kernel timer */
+       if (!m8xx_has_internal_rtc) {
+               if (wdt_timeout < (binfo->bi_intfreq/HZ))
+                       printk(KERN_ERR "m8xx_wdt: timeout too short for ktimer!\n");
+               m8xx_wdt_install_timer();
+       } else
+               m8xx_wdt_install_irq(imap, binfo);
+
        wdt_timeout /= binfo->bi_intfreq;
 }
 
index 0d81a9f8155f191ec5fef7fe4a4fc276f07bb35e..e75835f0012be0725f00a5fc509c69d9a1e4d784 100644 (file)
@@ -9,8 +9,12 @@
 #ifndef _PPC_SYSLIB_M8XX_WDT_H
 #define _PPC_SYSLIB_M8XX_WDT_H
 
+extern int m8xx_has_internal_rtc;
+
 extern void m8xx_wdt_handler_install(bd_t * binfo);
 extern int m8xx_wdt_get_timeout(void);
 extern void m8xx_wdt_reset(void);
+extern void m8xx_wdt_install_timer(void);
+extern void m8xx_wdt_stop_timer(void);
 
 #endif                         /* _PPC_SYSLIB_M8XX_WDT_H */
index 8ecda6d66de4c0b2e9a1a7b3b32c4dbc49dea891..cc02232aa96e93be846ceac801908fc08e070432 100644 (file)
@@ -712,35 +712,18 @@ sys_ptrace(long request, long pid, long addr, long data)
        int ret;
 
        lock_kernel();
-
        if (request == PTRACE_TRACEME) {
-               /* are we already being traced? */
-               ret = -EPERM;
-               if (current->ptrace & PT_PTRACED)
-                       goto out;
-               ret = security_ptrace(current->parent, current);
-               if (ret)
-                       goto out;
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
-               goto out;
+                ret = ptrace_traceme();
+                goto out;
        }
 
-       ret = -EPERM;
-       if (pid == 1)           /* you may not mess with init */
-               goto out;
-
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
                goto out;
+       }
 
        ret = do_ptrace(child, request, addr, data);
-
        put_task_struct(child);
 out:
        unlock_kernel();
index 64f5ae0ff96d1474c3f4052848ced900c78d5a1f..8cf6d437a630e704a86a1c1ad1de3892753af4ec 100644 (file)
@@ -14,10 +14,6 @@ config SUPERH
          gaming console.  The SuperH port has a home page at
          <http://www.linux-sh.org/>.
 
-config UID16
-       bool
-       default y
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index 870fe5327e09490b43c4d63c706b24de15402798..1195af37ee5aef321aaf7789971e158898169a53 100644 (file)
@@ -417,7 +417,7 @@ static __init unsigned int get_cpu_hz(void)
        /*
        ** Regardless the toolchain, force the compiler to use the
        ** arbitrary register r3 as a clock tick counter.
-       ** NOTE: r3 must be in accordance with rtc_interrupt()
+       ** NOTE: r3 must be in accordance with sh64_rtc_interrupt()
        */
        register unsigned long long  __rtc_irq_flag __asm__ ("r3");
 
@@ -482,7 +482,8 @@ static __init unsigned int get_cpu_hz(void)
 #endif
 }
 
-static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id,
+                                     struct pt_regs *regs)
 {
        ctrl_outb(0, RCR1);     /* Disable Carry Interrupts */
        regs->regs[3] = 1;      /* Using r3 */
@@ -491,7 +492,7 @@ static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 }
 
 static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer", NULL, NULL};
-static struct irqaction irq1  = { rtc_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "rtc", NULL, NULL};
+static struct irqaction irq1  = { sh64_rtc_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "rtc", NULL, NULL};
 
 void __init time_init(void)
 {
index 56c34e7fd4ee8f6b0bd7481c438eaa19f66b6eb9..f944b58cdfe79fde99ab07fc2348f2af059875f6 100644 (file)
@@ -9,10 +9,6 @@ config MMU
        bool
        default y
 
-config UID16
-       bool
-       default y
-
 config HIGHMEM
        bool
        default y
index 475c4c13462c8c81b79e7594422817246f4a20d2..fc470c0e9dc6bd453ce6b14143610d70225622d5 100644 (file)
@@ -286,40 +286,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                               s, (int) request, (int) pid, addr, data, addr2);
        }
 #endif
-       if (request == PTRACE_TRACEME) {
-               int my_ret;
-
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED) {
-                       pt_error_return(regs, EPERM);
-                       goto out;
-               }
-               my_ret = security_ptrace(current->parent, current);
-               if (my_ret) {
-                       pt_error_return(regs, -my_ret);
-                       goto out;
-               }
 
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
+       if (request == PTRACE_TRACEME) {
+               ret = ptrace_traceme();
                pt_succ_return(regs, 0);
                goto out;
        }
-#ifndef ALLOW_INIT_TRACING
-       if (pid == 1) {
-               /* Can't dork with init. */
-               pt_error_return(regs, EPERM);
-               goto out;
-       }
-#endif
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
 
-       if (!child) {
-               pt_error_return(regs, ESRCH);
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
+               pt_error_return(regs, -ret);
                goto out;
        }
 
index c4b7ad70cd7c5d1b756d46987ae90c5e536324ac..b775ceb4cf989e38ad2f186cc05566e331c4752b 100644 (file)
@@ -309,11 +309,6 @@ config COMPAT
        depends on SPARC32_COMPAT
        default y
 
-config UID16
-       bool
-       depends on SPARC32_COMPAT
-       default y
-
 config BINFMT_ELF32
        tristate "Kernel support for 32-bit ELF binaries"
        depends on SPARC32_COMPAT
index 774ecbb8a0319061c909c9ad72b39d32b11a2737..84d3df2264cb7148e4a5390f05a0ce0baf618844 100644 (file)
@@ -198,39 +198,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
        }
 #endif
        if (request == PTRACE_TRACEME) {
-               int ret;
-
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED) {
-                       pt_error_return(regs, EPERM);
-                       goto out;
-               }
-               ret = security_ptrace(current->parent, current);
-               if (ret) {
-                       pt_error_return(regs, -ret);
-                       goto out;
-               }
-
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
+               ret = ptrace_traceme();
                pt_succ_return(regs, 0);
                goto out;
        }
-#ifndef ALLOW_INIT_TRACING
-       if (pid == 1) {
-               /* Can't dork with init. */
-               pt_error_return(regs, EPERM);
-               goto out;
-       }
-#endif
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
 
-       if (!child) {
-               pt_error_return(regs, ESRCH);
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
+               pt_error_return(regs, -ret);
                goto out;
        }
 
index 1eb21de9d1b5c8809f02dd7f86fc51208c7b440f..b4ff2e5760215460fcaa79fa859c826d479d26e3 100644 (file)
@@ -22,10 +22,6 @@ config SBUS
 config PCI
        bool
 
-config UID16
-       bool
-       default y
-
 config GENERIC_CALIBRATE_DELAY
        bool
        default y
@@ -83,7 +79,7 @@ config KERNEL_HALF_GIGS
         of physical memory.
 
 config MODE_SKAS
-       bool "Separate Kernel Address Space support"
+       bool "Separate Kernel Address Space support" if MODE_TT
        default y
        help
        This option controls whether skas (separate kernel address space)
index 73f9652b2ee9000aab4243c50db4650d7974ea67..3a93c6f772fa3aa0bac0de3d6f3ec977dc545a3b 100644 (file)
@@ -117,6 +117,7 @@ static int ubd_open(struct inode * inode, struct file * filp);
 static int ubd_release(struct inode * inode, struct file * file);
 static int ubd_ioctl(struct inode * inode, struct file * file,
                     unsigned int cmd, unsigned long arg);
+static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 #define MAX_DEV (8)
 
@@ -125,6 +126,7 @@ static struct block_device_operations ubd_blops = {
         .open          = ubd_open,
         .release       = ubd_release,
         .ioctl         = ubd_ioctl,
+       .getgeo         = ubd_getgeo,
 };
 
 /* Protected by the queue_lock */
@@ -1058,6 +1060,16 @@ static void do_ubd_request(request_queue_t *q)
        }
 }
 
+static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       struct ubd *dev = bdev->bd_disk->private_data;
+
+       geo->heads = 128;
+       geo->sectors = 32;
+       geo->cylinders = dev->size / (128 * 32 * 512);
+       return 0;
+}
+
 static int ubd_ioctl(struct inode * inode, struct file * file,
                     unsigned int cmd, unsigned long arg)
 {
@@ -1070,16 +1082,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
        };
 
        switch (cmd) {
-               struct hd_geometry g;
                struct cdrom_volctrl volume;
-       case HDIO_GETGEO:
-               if(!loc) return(-EINVAL);
-               g.heads = 128;
-               g.sectors = 32;
-               g.cylinders = dev->size / (128 * 32 * 512);
-               g.start = get_start_sect(inode->i_bdev);
-               return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
-
        case HDIO_GET_IDENTITY:
                ubd_id.cyls = dev->size / (128 * 32 * 512);
                if(copy_to_user((char __user *) arg, (char *) &ubd_id,
index e5fec5570199851967a4d501aa683932c4164900..8f4e46d677ab08cb4305b85cc384a9e173d36bc0 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
 #include "sysdep/ptrace.h"
 #include "sysdep/faultinfo.h"
 
+typedef void (*kern_hndl)(int, union uml_pt_regs *);
+
+struct kern_handlers {
+       kern_hndl relay_signal;
+       kern_hndl winch;
+       kern_hndl bus_handler;
+       kern_hndl page_fault;
+       kern_hndl sigio_handler;
+       kern_hndl timer_handler;
+};
+
+extern struct kern_handlers handlinfo_kern;
+
 extern int ncpus;
 extern char *linux_prog;
 extern char *gdb_init;
@@ -51,8 +64,6 @@ extern void timer_handler(int sig, union uml_pt_regs *regs);
 extern int set_signals(int enable);
 extern void force_sigbus(void);
 extern int pid_to_processor_id(int pid);
-extern void block_signals(void);
-extern void unblock_signals(void);
 extern void deliver_signals(void *t);
 extern int next_syscall_index(int max);
 extern int next_trap_index(int max);
@@ -111,6 +122,8 @@ extern void arch_switch(void);
 extern void free_irq(unsigned int, void *);
 extern int um_in_interrupt(void);
 extern int cpu(void);
+extern void segv_handler(int sig, union uml_pt_regs *regs);
+extern void sigio_handler(int sig, union uml_pt_regs *regs);
 
 #endif
 
index c279ee6d89e44d33a4207b13e52b0096dfd674b1..dd72d66cf0ed18457361f0b004d02c2d1136f5c4 100644 (file)
@@ -9,6 +9,8 @@
 #include "uml-config.h"
 #include "asm/types.h"
 #include "../os/include/file.h"
+#include "sysdep/ptrace.h"
+#include "kern_util.h"
 
 #define OS_TYPE_FILE 1 
 #define OS_TYPE_DIR 2 
@@ -219,4 +221,18 @@ extern int umid_file_name(char *name, char *buf, int len);
 extern int set_umid(char *name);
 extern char *get_umid(void);
 
+/* signal.c */
+extern void set_sigstack(void *sig_stack, int size);
+extern void remove_sigstack(void);
+extern void set_handler(int sig, void (*handler)(int), int flags, ...);
+extern int change_sig(int signal, int on);
+extern void block_signals(void);
+extern void unblock_signals(void);
+extern int get_signals(void);
+extern int set_signals(int enable);
+
+/* trap.c */
+extern void os_fill_handlinfo(struct kern_handlers h);
+extern void do_longjmp(void *p, int val);
+
 #endif
diff --git a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h
deleted file mode 100644 (file)
index b075e54..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* 
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SIGNAL_USER_H__
-#define __SIGNAL_USER_H__
-
-extern int signal_stack_size;
-
-extern int change_sig(int signal, int on);
-extern void set_sigstack(void *stack, int size);
-extern void set_handler(int sig, void (*handler)(int), int flags, ...);
-extern int set_signals(int enable);
-extern int get_signals(void);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index b9984003e6035407c393c7466bcfac8f77c67831..c1dbd77b073f322ef3ee6369deeefb4235b04a73 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -23,12 +23,7 @@ struct cpu_task {
 
 extern struct cpu_task cpu_tasks[];
 
-struct signal_info {
-       void (*handler)(int, union uml_pt_regs *);
-       int is_irq;
-};
-
-extern struct signal_info sig_info[];
+extern void (*sig_info[])(int, union uml_pt_regs *);
 
 extern unsigned long low_physmem;
 extern unsigned long high_physmem;
@@ -64,7 +59,6 @@ extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(void);
 extern void do_exec(int old_pid, int new_pid);
 extern void tracer_panic(char *msg, ...);
-extern void do_longjmp(void *p, int val);
 extern int detach(int pid, int sig);
 extern int attach(int pid);
 extern void kill_child_dead(int pid);
index 6f7700593a6fe362448bbab3122f60723f9f0352..193cc2b7448d7e6c08b47f1828870a61a96d414b 100644 (file)
@@ -9,8 +9,8 @@ clean-files :=
 obj-y = config.o exec_kern.o exitcode.o \
        init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \
        process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \
-       signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o time.o \
-       time_kern.o tlb.o trap_kern.o trap_user.o uaccess.o um_arch.o umid.o \
+       signal_kern.o smp.o syscall_kern.o sysrq.o time.o \
+       time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o \
        user_util.o
 
 obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
index 50a2aa35cda96b762b5ea315566da7e2671f6adb..0e32f5f4a887ba99cdc316899afd92859a81cd34 100644 (file)
@@ -15,7 +15,6 @@
 #include "kern_util.h"
 #include "user.h"
 #include "process.h"
-#include "signal_user.h"
 #include "sigio.h"
 #include "irq_user.h"
 #include "os.h"
index 651abf255bc592b2163977269fdadd9bd4524fad..d2d3f256778cb4371ab8f5a3b060a6885f757271 100644 (file)
@@ -36,7 +36,6 @@
 #include "kern_util.h"
 #include "kern.h"
 #include "signal_kern.h"
-#include "signal_user.h"
 #include "init.h"
 #include "irq_user.h"
 #include "mem_user.h"
index a637e885c5835cb7c78e31c6d40099f8473c448c..6f1a3a288117985e1b4bc9d73bda578284c26d09 100644 (file)
@@ -12,6 +12,8 @@
 #include "mode.h"
 #include "choose-mode.h"
 
+void (*pm_power_off)(void);
+
 #ifdef CONFIG_SMP
 static void kill_idlers(int me)
 {
index 03618bd13d55f1521fb59a9b29224dd7fd0fd9f3..7b0e0e81c16196d7244819316a2b0cf725f1e62e 100644 (file)
@@ -22,7 +22,6 @@
 #include "asm/ucontext.h"
 #include "kern_util.h"
 #include "signal_kern.h"
-#include "signal_user.h"
 #include "kern.h"
 #include "frame_kern.h"
 #include "sigcontext.h"
diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c
deleted file mode 100644 (file)
index 62f4578..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/mman.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "signal_user.h"
-#include "signal_kern.h"
-#include "sysdep/sigcontext.h"
-#include "sigcontext.h"
-
-void set_sigstack(void *sig_stack, int size)
-{
-       stack_t stack = ((stack_t) { .ss_flags  = 0,
-                                    .ss_sp     = (__ptr_t) sig_stack,
-                                    .ss_size   = size - sizeof(void *) });
-
-       if(sigaltstack(&stack, NULL) != 0)
-               panic("enabling signal stack failed, errno = %d\n", errno);
-}
-
-void set_handler(int sig, void (*handler)(int), int flags, ...)
-{
-       struct sigaction action;
-       va_list ap;
-       int mask;
-
-       va_start(ap, flags);
-       action.sa_handler = handler;
-       sigemptyset(&action.sa_mask);
-       while((mask = va_arg(ap, int)) != -1){
-               sigaddset(&action.sa_mask, mask);
-       }
-       va_end(ap);
-       action.sa_flags = flags;
-       action.sa_restorer = NULL;
-       if(sigaction(sig, &action, NULL) < 0)
-               panic("sigaction failed");
-}
-
-int change_sig(int signal, int on)
-{
-       sigset_t sigset, old;
-
-       sigemptyset(&sigset);
-       sigaddset(&sigset, signal);
-       sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
-       return(!sigismember(&old, signal));
-}
-
-/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
- * disable profiling; it's safe because the profiling code does not interact
- * with the kernel code at all.*/
-
-static void change_signals(int type)
-{
-       sigset_t mask;
-
-       sigemptyset(&mask);
-       sigaddset(&mask, SIGVTALRM);
-       sigaddset(&mask, SIGALRM);
-       sigaddset(&mask, SIGIO);
-       if(sigprocmask(type, &mask, NULL) < 0)
-               panic("Failed to change signal mask - errno = %d", errno);
-}
-
-void block_signals(void)
-{
-       change_signals(SIG_BLOCK);
-}
-
-void unblock_signals(void)
-{
-       change_signals(SIG_UNBLOCK);
-}
-
-/* These are the asynchronous signals.  SIGVTALRM and SIGARLM are handled
- * together under SIGVTALRM_BIT.  SIGPROF is excluded because we want to
- * be able to profile all of UML, not just the non-critical sections.  If
- * profiling is not thread-safe, then that is not my problem.  We can disable
- * profiling when SMP is enabled in that case.
- */
-#define SIGIO_BIT 0
-#define SIGVTALRM_BIT 1
-
-static int enable_mask(sigset_t *mask)
-{
-       int sigs;
-
-       sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
-       sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
-       sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
-       return(sigs);
-}
-
-int get_signals(void)
-{
-       sigset_t mask;
-       
-       if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
-               panic("Failed to get signal mask");
-       return(enable_mask(&mask));
-}
-
-int set_signals(int enable)
-{
-       sigset_t mask;
-       int ret;
-
-       sigemptyset(&mask);
-       if(enable & (1 << SIGIO_BIT)) 
-               sigaddset(&mask, SIGIO);
-       if(enable & (1 << SIGVTALRM_BIT)){
-               sigaddset(&mask, SIGVTALRM);
-               sigaddset(&mask, SIGALRM);
-       }
-
-       /* This is safe - sigprocmask is guaranteed to copy locally the
-        * value of new_set, do his work and then, at the end, write to
-        * old_set.
-        */
-       if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
-               panic("Failed to enable signals");
-       ret = enable_mask(&mask);
-       sigemptyset(&mask);
-       if((enable & (1 << SIGIO_BIT)) == 0) 
-               sigaddset(&mask, SIGIO);
-       if((enable & (1 << SIGVTALRM_BIT)) == 0){
-               sigaddset(&mask, SIGVTALRM);
-               sigaddset(&mask, SIGALRM);
-       }
-       if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
-               panic("Failed to block signals");
-
-       return(ret);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 8de471b59c1c8188c35887cd18280594c9dc33dc..7a9fc16d71d4805df78eb6505516e3e88537aa78 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
-       syscall.o tlb.o trap_user.o uaccess.o
+       syscall.o tlb.o uaccess.o
 
 USER_OBJS := process.o clone.o
 
index daa2f85b684c7dd14845b6d1a63560abad1de67c..01d489de3986d76b4bea09f3fdd9986112a9a53a 100644 (file)
@@ -22,7 +22,6 @@ extern int start_idle_thread(void *stack, void *switch_buf_ptr,
 extern int user_thread(unsigned long stack, int flags);
 extern void userspace(union uml_pt_regs *regs);
 extern void new_thread_proc(void *stack, void (*handler)(int sig));
-extern void remove_sigstack(void);
 extern void new_thread_handler(int sig);
 extern void handle_syscall(union uml_pt_regs *regs);
 extern int map(struct mm_id * mm_idp, unsigned long virt,
index 599d679bd4fcb3bfdebff8355d69e8d5b7a13274..9264d4021dfe23f73c0adb02d65fdf3eeea25914 100644 (file)
@@ -31,7 +31,6 @@
 #include "proc_mm.h"
 #include "skas_ptrace.h"
 #include "chan_user.h"
-#include "signal_user.h"
 #include "registers.h"
 #include "mem.h"
 #include "uml-config.h"
@@ -514,16 +513,6 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
        siglongjmp(**switch_buf, 1);
 }
 
-void remove_sigstack(void)
-{
-       stack_t stack = ((stack_t) { .ss_flags  = SS_DISABLE,
-                                    .ss_sp     = NULL,
-                                    .ss_size   = 0 });
-
-       if(sigaltstack(&stack, NULL) != 0)
-               panic("disabling signal stack failed, errno = %d\n", errno);
-}
-
 void initial_thread_cb_skas(void (*proc)(void *), void *arg)
 {
        sigjmp_buf here;
index 9c990253966c596af858b1dbd176084012cd48d2..09790ccb161ca7ddae9c91136ed805a2dc62a8dc 100644 (file)
@@ -14,7 +14,6 @@
 #include "asm/atomic.h"
 #include "kern_util.h"
 #include "time_user.h"
-#include "signal_user.h"
 #include "skas.h"
 #include "os.h"
 #include "user_util.h"
index c40b611e3d936dbcd120f65961e18a65ec8a4c87..11f518a7e1562538e1cf75e5b87af1c609d50009 100644 (file)
@@ -14,9 +14,9 @@
 #include "kern_util.h"
 #include "user.h"
 #include "process.h"
-#include "signal_user.h"
 #include "time_user.h"
 #include "kern_constants.h"
+#include "os.h"
 
 /* XXX This really needs to be declared and initialized in a kernel file since
  * it's in <linux/time.h>
index 0d4c10a736077702556fea90e281b82b109ada06..d56046c2aba2fec7799ae39df1ef8b53fdcba9f9 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
 #include "mconsole_kern.h"
 #include "mem.h"
 #include "mem_kern.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/ptrace.h"
+#include "os.h"
 #ifdef CONFIG_MODE_SKAS
 #include "skas.h"
 #endif
+#include "os.h"
 
 /* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */
 int handle_page_fault(unsigned long address, unsigned long ip, 
@@ -125,6 +129,25 @@ out_of_memory:
        goto out;
 }
 
+void segv_handler(int sig, union uml_pt_regs *regs)
+{
+       struct faultinfo * fi = UPT_FAULTINFO(regs);
+
+       if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
+               bad_segv(*fi, UPT_IP(regs));
+               return;
+       }
+       segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
+}
+
+struct kern_handlers handlinfo_kern = {
+       .relay_signal = relay_signal,
+       .winch = winch,
+       .bus_handler = relay_signal,
+       .page_fault = segv_handler,
+       .sigio_handler = sigio_handler,
+       .timer_handler = timer_handler
+};
 /*
  * We give a *copy* of the faultinfo in the regs to segv.
  * This must be done, since nesting SEGVs could overwrite
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
deleted file mode 100644 (file)
index e9ccd6b..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* 
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <errno.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <asm/page.h>
-#include <asm/unistd.h>
-#include <asm/ptrace.h>
-#include "init.h"
-#include "sysdep/ptrace.h"
-#include "sigcontext.h"
-#include "sysdep/sigcontext.h"
-#include "irq_user.h"
-#include "signal_user.h"
-#include "time_user.h"
-#include "task.h"
-#include "mode.h"
-#include "choose-mode.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "os.h"
-
-void kill_child_dead(int pid)
-{
-       kill(pid, SIGKILL);
-       kill(pid, SIGCONT);
-       do {
-               int n;
-               CATCH_EINTR(n = waitpid(pid, NULL, 0));
-               if (n > 0)
-                       kill(pid, SIGCONT);
-               else
-                       break;
-       } while(1);
-}
-
-void segv_handler(int sig, union uml_pt_regs *regs)
-{
-        struct faultinfo * fi = UPT_FAULTINFO(regs);
-
-        if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
-                bad_segv(*fi, UPT_IP(regs));
-               return;
-       }
-        segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
-}
-
-void usr2_handler(int sig, union uml_pt_regs *regs)
-{
-       CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
-}
-
-struct signal_info sig_info[] = {
-       [ SIGTRAP ] { .handler          = relay_signal,
-                     .is_irq           = 0 },
-       [ SIGFPE ] { .handler           = relay_signal,
-                    .is_irq            = 0 },
-       [ SIGILL ] { .handler           = relay_signal,
-                    .is_irq            = 0 },
-       [ SIGWINCH ] { .handler         = winch,
-                      .is_irq          = 1 },
-       [ SIGBUS ] { .handler           = bus_handler,
-                    .is_irq            = 0 },
-       [ SIGSEGV] { .handler           = segv_handler,
-                    .is_irq            = 0 },
-       [ SIGIO ] { .handler            = sigio_handler,
-                   .is_irq             = 1 },
-       [ SIGVTALRM ] { .handler        = timer_handler,
-                       .is_irq         = 1 },
-        [ SIGALRM ] { .handler          = timer_handler,
-                      .is_irq           = 1 },
-       [ SIGUSR2 ] { .handler          = usr2_handler,
-                     .is_irq           = 0 },
-};
-
-void do_longjmp(void *b, int val)
-{
-       sigjmp_buf *buf = b;
-
-       siglongjmp(*buf, val);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 065b504a653b1d9cbe87998e92cf7f85486427fe..136e54c47d37fd1052304d5f11164fe53b2c15a8 100644 (file)
@@ -14,7 +14,6 @@
 #include "kern_util.h"
 #include "irq_user.h"
 #include "time_user.h"
-#include "signal_user.h"
 #include "mem_user.h"
 #include "os.h"
 #include "tlb.h"
index cfaa373a6e77df4190a2721b467a29fd94c5f4c3..14d4622a5fb86ffbd9750f9d8ce6adf34dbf03b6 100644 (file)
@@ -13,7 +13,6 @@
 #include "asm/ptrace.h"
 #include "asm/tlbflush.h"
 #include "irq_user.h"
-#include "signal_user.h"
 #include "kern_util.h"
 #include "user_util.h"
 #include "os.h"
index d11e7399d7a1a894097ec0b0a45360803eae10b5..71daae24e48a8b8125b203fafc74ee40ea39c81d 100644 (file)
@@ -19,7 +19,6 @@
 #include "sigcontext.h"
 #include "sysdep/sigcontext.h"
 #include "os.h"
-#include "signal_user.h"
 #include "user_util.h"
 #include "mem_user.h"
 #include "process.h"
index fc108615beafbaf894f0fe3e4c2eb55338084030..a414c529fbcd78b91350db486527a1bf37742c2a 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -8,18 +8,18 @@
 #include <signal.h>
 #include "sysdep/ptrace.h"
 #include "sysdep/sigcontext.h"
-#include "signal_user.h"
 #include "user_util.h"
 #include "kern_util.h"
 #include "task.h"
 #include "tt.h"
+#include "os.h"
 
 void sig_handler_common_tt(int sig, void *sc_ptr)
 {
        struct sigcontext *sc = sc_ptr;
        struct tt_regs save_regs, *r;
-       struct signal_info *info;
        int save_errno = errno, is_user;
+       void (*handler)(int, union uml_pt_regs *);
 
        /* This is done because to allow SIGSEGV to be delivered inside a SEGV
         * handler.  This can happen in copy_user, and if SEGV is disabled,
@@ -40,10 +40,14 @@ void sig_handler_common_tt(int sig, void *sc_ptr)
        if(sig != SIGUSR2) 
                r->syscall = -1;
 
-       info = &sig_info[sig];
-       if(!info->is_irq) unblock_signals();
+       handler = sig_info[sig];
+
+       /* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */
+       if (sig != SIGIO && sig != SIGWINCH &&
+           sig != SIGVTALRM && sig != SIGALRM)
+               unblock_signals();
 
-       (*info->handler)(sig, (union uml_pt_regs *) r);
+       handler(sig, (union uml_pt_regs *) r);
 
        if(is_user){
                interrupt_end();
index 26626b2b9172cfbd9a230cad4e95684682105825..73747ac197748d6deb1649f0b59b4b1aad1d7051 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -363,6 +363,11 @@ int linux_main(int argc, char **argv)
        uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
                                     &host_task_size, &task_size);
 
+       /*
+        * Setting up handlers to 'sig_info' struct
+        */
+       os_fill_handlinfo(handlinfo_kern);
+
        brk_start = (unsigned long) sbrk(0);
        CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
        /* Increase physical memory size for exec-shield users
index 11e30b13e318ffe756e873bc79737954c146311e..40c7d6b1df6804e01ae6576d19a59e73e52e9cc1 100644 (file)
@@ -4,11 +4,13 @@
 #
 
 obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
-       start_up.o time.o tt.o tty.o uaccess.o umid.o user_syms.o drivers/ \
-       sys-$(SUBARCH)/
+       start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \
+       drivers/ sys-$(SUBARCH)/
+
+obj-$(CONFIG_MODE_SKAS) += skas/
 
 USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
-       start_up.o time.o tt.o tty.o uaccess.o umid.o
+       start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o
 
 elf_aux.o: $(ARCH_DIR)/kernel-offsets.h
 CFLAGS_elf_aux.o += -I$(objtree)/arch/um
index 23da27d22569da2308b373f0edd42a2b5757c710..172c8474453c9c4baa229d66c0d619ba243d40f3 100644 (file)
@@ -16,7 +16,6 @@
 #include "user_util.h"
 #include "kern_util.h"
 #include "mem_user.h"
-#include "signal_user.h"
 #include "time_user.h"
 #include "irq_user.h"
 #include "user.h"
index d9c52387c4a16c4dea868f0de58201092d0c967f..39815c6b5e4510ecd0fdaef22c73fc87a82c06ef 100644 (file)
@@ -15,7 +15,6 @@
 #include "os.h"
 #include "user.h"
 #include "user_util.h"
-#include "signal_user.h"
 #include "process.h"
 #include "irq_user.h"
 #include "kern_util.h"
index c7bfd5ee392573b5a79c9eb8dc676b00306c7046..c1f46a0fef13d14c8740d80091fb18a2cf0690d7 100644 (file)
@@ -4,9 +4,22 @@
  */
 
 #include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/mman.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "signal_kern.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/signal.h"
+#include "sigcontext.h"
 #include "time_user.h"
 #include "mode.h"
-#include "sysdep/signal.h"
 
 void sig_handler(ARCH_SIGHDLR_PARAM)
 {
@@ -36,13 +49,138 @@ void alarm_handler(ARCH_SIGHDLR_PARAM)
                switch_timers(1);
 }
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
+void set_sigstack(void *sig_stack, int size)
+{
+       stack_t stack = ((stack_t) { .ss_flags  = 0,
+                                    .ss_sp     = (__ptr_t) sig_stack,
+                                    .ss_size   = size - sizeof(void *) });
+
+       if(sigaltstack(&stack, NULL) != 0)
+               panic("enabling signal stack failed, errno = %d\n", errno);
+}
+
+void remove_sigstack(void)
+{
+       stack_t stack = ((stack_t) { .ss_flags  = SS_DISABLE,
+                                    .ss_sp     = NULL,
+                                    .ss_size   = 0 });
+
+       if(sigaltstack(&stack, NULL) != 0)
+               panic("disabling signal stack failed, errno = %d\n", errno);
+}
+
+void set_handler(int sig, void (*handler)(int), int flags, ...)
+{
+       struct sigaction action;
+       va_list ap;
+       int mask;
+
+       va_start(ap, flags);
+       action.sa_handler = handler;
+       sigemptyset(&action.sa_mask);
+       while((mask = va_arg(ap, int)) != -1){
+               sigaddset(&action.sa_mask, mask);
+       }
+       va_end(ap);
+       action.sa_flags = flags;
+       action.sa_restorer = NULL;
+       if(sigaction(sig, &action, NULL) < 0)
+               panic("sigaction failed");
+}
+
+int change_sig(int signal, int on)
+{
+       sigset_t sigset, old;
+
+       sigemptyset(&sigset);
+       sigaddset(&sigset, signal);
+       sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
+       return(!sigismember(&old, signal));
+}
+
+/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
+ * disable profiling; it's safe because the profiling code does not interact
+ * with the kernel code at all.*/
+
+static void change_signals(int type)
+{
+       sigset_t mask;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGVTALRM);
+       sigaddset(&mask, SIGALRM);
+       sigaddset(&mask, SIGIO);
+       if(sigprocmask(type, &mask, NULL) < 0)
+               panic("Failed to change signal mask - errno = %d", errno);
+}
+
+void block_signals(void)
+{
+       change_signals(SIG_BLOCK);
+}
+
+void unblock_signals(void)
+{
+       change_signals(SIG_UNBLOCK);
+}
+
+/* These are the asynchronous signals.  SIGVTALRM and SIGARLM are handled
+ * together under SIGVTALRM_BIT.  SIGPROF is excluded because we want to
+ * be able to profile all of UML, not just the non-critical sections.  If
+ * profiling is not thread-safe, then that is not my problem.  We can disable
+ * profiling when SMP is enabled in that case.
  */
+#define SIGIO_BIT 0
+#define SIGVTALRM_BIT 1
+
+static int enable_mask(sigset_t *mask)
+{
+       int sigs;
+
+       sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
+       sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
+       sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
+       return(sigs);
+}
+
+int get_signals(void)
+{
+       sigset_t mask;
+
+       if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
+               panic("Failed to get signal mask");
+       return(enable_mask(&mask));
+}
+
+int set_signals(int enable)
+{
+       sigset_t mask;
+       int ret;
+
+       sigemptyset(&mask);
+       if(enable & (1 << SIGIO_BIT))
+               sigaddset(&mask, SIGIO);
+       if(enable & (1 << SIGVTALRM_BIT)){
+               sigaddset(&mask, SIGVTALRM);
+               sigaddset(&mask, SIGALRM);
+       }
+
+       /* This is safe - sigprocmask is guaranteed to copy locally the
+        * value of new_set, do his work and then, at the end, write to
+        * old_set.
+        */
+       if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
+               panic("Failed to enable signals");
+       ret = enable_mask(&mask);
+       sigemptyset(&mask);
+       if((enable & (1 << SIGIO_BIT)) == 0)
+               sigaddset(&mask, SIGIO);
+       if((enable & (1 << SIGVTALRM_BIT)) == 0){
+               sigaddset(&mask, SIGVTALRM);
+               sigaddset(&mask, SIGALRM);
+       }
+       if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
+               panic("Failed to block signals");
+
+       return(ret);
+}
diff --git a/arch/um/os-Linux/skas/Makefile b/arch/um/os-Linux/skas/Makefile
new file mode 100644 (file)
index 0000000..eab5386
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
+# Licensed under the GPL
+#
+
+obj-y := trap.o
+
+USER_OBJS := trap.o
+
+include arch/um/scripts/Makefile.rules
similarity index 53%
rename from arch/um/kernel/skas/trap_user.c
rename to arch/um/os-Linux/skas/trap.c
index 9950a6716fe5b015dd51365adfa312c5c2226d60..9ad5fbec459347c26efb0db216b104ff276a50d1 100644 (file)
@@ -1,11 +1,10 @@
-/* 
+/*
  * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
 
 #include <signal.h>
 #include <errno.h>
-#include "signal_user.h"
 #include "user_util.h"
 #include "kern_util.h"
 #include "task.h"
 #include "ptrace_user.h"
 #include "sysdep/ptrace.h"
 #include "sysdep/ptrace_user.h"
+#include "os.h"
 
 void sig_handler_common_skas(int sig, void *sc_ptr)
 {
        struct sigcontext *sc = sc_ptr;
        struct skas_regs *r;
-       struct signal_info *info;
+       void (*handler)(int, union uml_pt_regs *);
        int save_errno = errno;
        int save_user;
 
@@ -34,17 +34,22 @@ void sig_handler_common_skas(int sig, void *sc_ptr)
        r = &TASK_REGS(get_current())->skas;
        save_user = r->is_user;
        r->is_user = 0;
-        if ( sig == SIGFPE || sig == SIGSEGV ||
-             sig == SIGBUS || sig == SIGILL ||
-             sig == SIGTRAP ) {
-                GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
-        }
+       if ( sig == SIGFPE || sig == SIGSEGV ||
+            sig == SIGBUS || sig == SIGILL ||
+            sig == SIGTRAP ) {
+               GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
+       }
 
        change_sig(SIGUSR1, 1);
-       info = &sig_info[sig];
-       if(!info->is_irq) unblock_signals();
 
-       (*info->handler)(sig, (union uml_pt_regs *) r);
+       handler = sig_info[sig];
+
+       /* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */
+       if (sig != SIGIO && sig != SIGWINCH &&
+           sig != SIGVTALRM && sig != SIGALRM)
+               unblock_signals();
+
+       handler(sig, (union uml_pt_regs *) r);
 
        errno = save_errno;
        r->is_user = save_user;
@@ -54,25 +59,15 @@ extern int ptrace_faultinfo;
 
 void user_signal(int sig, union uml_pt_regs *regs, int pid)
 {
-       struct signal_info *info;
-        int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
-                    (sig == SIGILL) || (sig == SIGTRAP));
+       void (*handler)(int, union uml_pt_regs *);
+       int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
+                   (sig == SIGILL) || (sig == SIGTRAP));
 
        if (segv)
                get_skas_faultinfo(pid, &regs->skas.faultinfo);
-       info = &sig_info[sig];
-       (*info->handler)(sig, regs);
+
+       handler = sig_info[sig];
+       handler(sig, (union uml_pt_regs *) regs);
 
        unblock_signals();
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 29a9e3f4376368caa56610e423d9e189eec79e4d..b47e5e71d1a5d14d0ebefef0589ceef269a20851 100644 (file)
@@ -24,7 +24,6 @@
 #include "kern_util.h"
 #include "user.h"
 #include "signal_kern.h"
-#include "signal_user.h"
 #include "sysdep/ptrace.h"
 #include "sysdep/sigcontext.h"
 #include "irq_user.h"
diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c
new file mode 100644 (file)
index 0000000..321e1c8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "mode.h"
+
+void usr2_handler(int sig, union uml_pt_regs *regs)
+{
+       CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
+}
+
+void (*sig_info[NSIG])(int, union uml_pt_regs *);
+
+void os_fill_handlinfo(struct kern_handlers h)
+{
+       sig_info[SIGTRAP] = h.relay_signal;
+       sig_info[SIGFPE] = h.relay_signal;
+       sig_info[SIGILL] = h.relay_signal;
+       sig_info[SIGWINCH] = h.winch;
+       sig_info[SIGBUS] = h.bus_handler;
+       sig_info[SIGSEGV] = h.page_fault;
+       sig_info[SIGIO] = h.sigio_handler;
+       sig_info[SIGVTALRM] = h.timer_handler;
+       sig_info[SIGALRM] = h.timer_handler;
+       sig_info[SIGUSR2] = usr2_handler;
+}
+
+void do_longjmp(void *b, int val)
+{
+       sigjmp_buf *buf = b;
+
+       siglongjmp(*buf, val);
+}
index a6db8877931a8cbc06a39911e35d61059c58c61f..cb2648b79d0fd15090205da1f7595c7a2e639edf 100644 (file)
@@ -23,7 +23,6 @@
 #include "kern_util.h"
 #include "user.h"
 #include "signal_kern.h"
-#include "signal_user.h"
 #include "sysdep/ptrace.h"
 #include "sysdep/sigcontext.h"
 #include "irq_user.h"
@@ -50,6 +49,20 @@ int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
        return(0);
 }
 
+void kill_child_dead(int pid)
+{
+       kill(pid, SIGKILL);
+       kill(pid, SIGCONT);
+       do {
+               int n;
+               CATCH_EINTR(n = waitpid(pid, NULL, 0));
+               if (n > 0)
+                       kill(pid, SIGCONT);
+               else
+                       break;
+       } while(1);
+}
+
 /*
  *-------------------------
  * only for tt mode (will be deleted in future...)
index 16bc19928b3c53c49d93ca825798d42d256fdc06..7cd1a82dc8c24fd086cd8c3e3a82ef6433640673 100644 (file)
@@ -10,7 +10,6 @@
 #include "asm/uaccess.h"
 #include "asm/unistd.h"
 #include "frame_kern.h"
-#include "signal_user.h"
 #include "sigcontext.h"
 #include "registers.h"
 #include "mode.h"
index 310865903234750fc4599d7782f5ac0b3e6000a2..04494638b96387203fefc91aebab3be1045bf681 100644 (file)
@@ -10,9 +10,6 @@ mainmenu "uClinux/v850 (w/o MMU) Kernel Configuration"
 config MMU
                bool
        default n
-config UID16
-       bool
-       default n
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index 6ece645e4dbea691191ccdaa8d49ec42025ab25f..4f3e925962c36576f9d2c7ee04fedbcdaf591d21 100644 (file)
@@ -542,11 +542,6 @@ config SYSVIPC_COMPAT
        depends on COMPAT && SYSVIPC
        default y
 
-config UID16
-       bool
-       depends on IA32_EMULATION
-       default y
-
 endmenu
 
 source "net/Kconfig"
index 0e10fd84c7cc79e2ee31832e6104c915f3c50597..cf4b88c416dc749bd30ff87f61e053703e6210da 100644 (file)
@@ -9,7 +9,7 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 
-#include "miscsetup.h"
+#include <linux/screen_info.h>
 #include <asm/io.h>
 #include <asm/page.h>
 
diff --git a/arch/x86_64/boot/compressed/miscsetup.h b/arch/x86_64/boot/compressed/miscsetup.h
deleted file mode 100644 (file)
index bb16205..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#define NULL 0
-//typedef unsigned int size_t; 
-
-
-struct screen_info {
-       unsigned char  orig_x;                  /* 0x00 */
-       unsigned char  orig_y;                  /* 0x01 */
-       unsigned short dontuse1;                /* 0x02 -- EXT_MEM_K sits here */
-       unsigned short orig_video_page;         /* 0x04 */
-       unsigned char  orig_video_mode;         /* 0x06 */
-       unsigned char  orig_video_cols;         /* 0x07 */
-       unsigned short unused2;                 /* 0x08 */
-       unsigned short orig_video_ega_bx;       /* 0x0a */
-       unsigned short unused3;                 /* 0x0c */
-       unsigned char  orig_video_lines;        /* 0x0e */
-       unsigned char  orig_video_isVGA;        /* 0x0f */
-       unsigned short orig_video_points;       /* 0x10 */
-
-       /* VESA graphic mode -- linear frame buffer */
-       unsigned short lfb_width;               /* 0x12 */
-       unsigned short lfb_height;              /* 0x14 */
-       unsigned short lfb_depth;               /* 0x16 */
-       unsigned long  lfb_base;                /* 0x18 */
-       unsigned long  lfb_size;                /* 0x1c */
-       unsigned short dontuse2, dontuse3;      /* 0x20 -- CL_MAGIC and CL_OFFSET here */
-       unsigned short lfb_linelength;          /* 0x24 */
-       unsigned char  red_size;                /* 0x26 */
-       unsigned char  red_pos;                 /* 0x27 */
-       unsigned char  green_size;              /* 0x28 */
-       unsigned char  green_pos;               /* 0x29 */
-       unsigned char  blue_size;               /* 0x2a */
-       unsigned char  blue_pos;                /* 0x2b */
-       unsigned char  rsvd_size;               /* 0x2c */
-       unsigned char  rsvd_pos;                /* 0x2d */
-       unsigned short vesapm_seg;              /* 0x2e */
-       unsigned short vesapm_off;              /* 0x30 */
-       unsigned short pages;                   /* 0x32 */
-                                               /* 0x34 -- 0x3f reserved for future expansion */
-};
index df0773c9bdbe70337e236bd6c267e91bedcaf465..1f0ff5adc80e1b0babda930850aa29eb16e4bab0 100644 (file)
@@ -643,6 +643,7 @@ ia32_sys_call_table:
        .quad sys_inotify_init
        .quad sys_inotify_add_watch
        .quad sys_inotify_rm_watch
+       .quad sys_migrate_pages
 ia32_syscall_end:              
        .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
                .quad ni_syscall
index 2a925e2af390bddc1ac34ba37882f8138703de1a..5f4cdfa56901ef4528c4850a8a225f246a672a13 100644 (file)
@@ -196,36 +196,6 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
 
 #undef R32
 
-static struct task_struct *find_target(int request, int pid, int *err)
-{ 
-       struct task_struct *child;
-
-       *err = -EPERM; 
-       if (pid == 1)
-               return NULL; 
-
-       *err = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (child) { 
-               *err = -EPERM;
-               if (child->pid == 1) 
-                       goto out;
-               *err = ptrace_check_attach(child, request == PTRACE_KILL); 
-               if (*err < 0) 
-                       goto out;
-               return child; 
-       } 
- out:
-       if (child)
-       put_task_struct(child);
-       return NULL; 
-       
-} 
-
 asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
 {
        struct task_struct *child;
@@ -254,9 +224,16 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
                break;
        } 
 
-       child = find_target(request, pid, &ret);
-       if (!child)
-               return ret;
+       if (request == PTRACE_TRACEME)
+               return ptrace_traceme();
+
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child))
+               return PTR_ERR(child);
+
+       ret = ptrace_check_attach(child, request == PTRACE_KILL);
+       if (ret < 0)
+               goto out;
 
        childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
 
@@ -373,6 +350,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
                break;
        }
 
+ out:
        put_task_struct(child);
        return ret;
 }
index e0ba5c1043fd23f71e48e236aebcb18b41d3934a..ce31d904d601c6700814cd580f99ec37f80a34fc 100644 (file)
@@ -44,6 +44,6 @@ 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_maxaligned_in_smp = INIT_TSS;
+DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
 
 #define ALIGN_TO_4K __attribute__((section(".data.init_task")))
index 74102796e5c06d4fdd749c5e50e0726262d1c975..43c9fa0f8d5fe4411bc5aa7dd07eaa4eb3bd472e 100644 (file)
@@ -1075,8 +1075,6 @@ device_initcall(time_init_device);
  */
 #include <linux/rtc.h>
 
-extern irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
 #define DEFAULT_RTC_INT_FREQ   64
 #define RTC_NUM_INTS           1
 
index 39dcccc82ada5b71e3105a8b7e9d8389fc9000b6..99a4d7b2f8ad335079ae1eebeab71136f20acc35 100644 (file)
@@ -64,7 +64,7 @@ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
 }
 EXPORT_SYMBOL(elv_rq_merge_ok);
 
-inline int elv_try_merge(struct request *__rq, struct bio *bio)
+static inline int elv_try_merge(struct request *__rq, struct bio *bio)
 {
        int ret = ELEVATOR_NO_MERGE;
 
@@ -80,7 +80,6 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio)
 
        return ret;
 }
-EXPORT_SYMBOL(elv_try_merge);
 
 static struct elevator_type *elevator_find(const char *name)
 {
index 6e278474f9a8c1f0dcb70a560031fac870eb3220..82030e1dfd631b1495f87ebe632f30ed6f1086fa 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/sched.h>               /* for capable() */
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
+#include <linux/hdreg.h>
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
 #include <linux/smp_lock.h>
@@ -245,6 +246,27 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
                set_device_ro(bdev, n);
                unlock_kernel();
                return 0;
+       case HDIO_GETGEO: {
+               struct hd_geometry geo;
+
+               if (!arg)
+                       return -EINVAL;
+               if (!disk->fops->getgeo)
+                       return -ENOTTY;
+
+               /*
+                * We need to set the startsect first, the driver may
+                * want to override it.
+                */
+               geo.start = get_start_sect(bdev);
+               ret = disk->fops->getgeo(bdev, &geo);
+               if (ret)
+                       return ret;
+               if (copy_to_user((struct hd_geometry __user *)arg, &geo,
+                                       sizeof(geo)))
+                       return -EFAULT;
+               return 0;
+       }
        }
 
        lock_kernel();
index 91d3b4828c4916290ded65ab1f016cf2cdfc50ae..8e27d0ab0d7ccefef5a53d42c52978200040ca18 100644 (file)
@@ -26,7 +26,8 @@
 #include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
-#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
 
 /*
  * for max sense size
@@ -62,13 +63,15 @@ static wait_queue_head_t congestion_wqh[2] = {
 /*
  * Controlling structure to kblockd
  */
-static struct workqueue_struct *kblockd_workqueue; 
+static struct workqueue_struct *kblockd_workqueue;
 
 unsigned long blk_max_low_pfn, blk_max_pfn;
 
 EXPORT_SYMBOL(blk_max_low_pfn);
 EXPORT_SYMBOL(blk_max_pfn);
 
+static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
+
 /* Amount of time in which a process may batch requests */
 #define BLK_BATCH_TIME (HZ/50UL)
 
@@ -207,6 +210,13 @@ void blk_queue_merge_bvec(request_queue_t *q, merge_bvec_fn *mbfn)
 
 EXPORT_SYMBOL(blk_queue_merge_bvec);
 
+void blk_queue_softirq_done(request_queue_t *q, softirq_done_fn *fn)
+{
+       q->softirq_done_fn = fn;
+}
+
+EXPORT_SYMBOL(blk_queue_softirq_done);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -270,6 +280,7 @@ EXPORT_SYMBOL(blk_queue_make_request);
 static inline void rq_init(request_queue_t *q, struct request *rq)
 {
        INIT_LIST_HEAD(&rq->queuelist);
+       INIT_LIST_HEAD(&rq->donelist);
 
        rq->errors = 0;
        rq->rq_status = RQ_ACTIVE;
@@ -286,6 +297,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
        rq->sense = NULL;
        rq->end_io = NULL;
        rq->end_io_data = NULL;
+       rq->completion_data = NULL;
 }
 
 /**
@@ -2735,30 +2747,6 @@ static inline int attempt_front_merge(request_queue_t *q, struct request *rq)
        return 0;
 }
 
-/**
- * blk_attempt_remerge  - attempt to remerge active head with next request
- * @q:    The &request_queue_t belonging to the device
- * @rq:   The head request (usually)
- *
- * Description:
- *    For head-active devices, the queue can easily be unplugged so quickly
- *    that proper merging is not done on the front request. This may hurt
- *    performance greatly for some devices. The block layer cannot safely
- *    do merging on that first request for these queues, but the driver can
- *    call this function and make it happen any way. Only the driver knows
- *    when it is safe to do so.
- **/
-void blk_attempt_remerge(request_queue_t *q, struct request *rq)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(q->queue_lock, flags);
-       attempt_back_merge(q, rq);
-       spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
-EXPORT_SYMBOL(blk_attempt_remerge);
-
 static void init_request_from_bio(struct request *req, struct bio *bio)
 {
        req->flags |= REQ_CMD;
@@ -3286,6 +3274,87 @@ int end_that_request_chunk(struct request *req, int uptodate, int nr_bytes)
 
 EXPORT_SYMBOL(end_that_request_chunk);
 
+/*
+ * splice the completion data to a local structure and hand off to
+ * process_completion_queue() to complete the requests
+ */
+static void blk_done_softirq(struct softirq_action *h)
+{
+       struct list_head *cpu_list;
+       LIST_HEAD(local_list);
+
+       local_irq_disable();
+       cpu_list = &__get_cpu_var(blk_cpu_done);
+       list_splice_init(cpu_list, &local_list);
+       local_irq_enable();
+
+       while (!list_empty(&local_list)) {
+               struct request *rq = list_entry(local_list.next, struct request, donelist);
+
+               list_del_init(&rq->donelist);
+               rq->q->softirq_done_fn(rq);
+       }
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
+                         void *hcpu)
+{
+       /*
+        * If a CPU goes away, splice its entries to the current CPU
+        * and trigger a run of the softirq
+        */
+       if (action == CPU_DEAD) {
+               int cpu = (unsigned long) hcpu;
+
+               local_irq_disable();
+               list_splice_init(&per_cpu(blk_cpu_done, cpu),
+                                &__get_cpu_var(blk_cpu_done));
+               raise_softirq_irqoff(BLOCK_SOFTIRQ);
+               local_irq_enable();
+       }
+
+       return NOTIFY_OK;
+}
+
+
+static struct notifier_block __devinitdata blk_cpu_notifier = {
+       .notifier_call  = blk_cpu_notify,
+};
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/**
+ * blk_complete_request - end I/O on a request
+ * @req:      the request being processed
+ *
+ * Description:
+ *     Ends all I/O on a request. It does not handle partial completions,
+ *     unless the driver actually implements this in its completionc callback
+ *     through requeueing. Theh actual completion happens out-of-order,
+ *     through a softirq handler. The user must have registered a completion
+ *     callback through blk_queue_softirq_done().
+ **/
+
+void blk_complete_request(struct request *req)
+{
+       struct list_head *cpu_list;
+       unsigned long flags;
+
+       BUG_ON(!req->q->softirq_done_fn);
+               
+       local_irq_save(flags);
+
+       cpu_list = &__get_cpu_var(blk_cpu_done);
+       list_add_tail(&req->donelist, cpu_list);
+       raise_softirq_irqoff(BLOCK_SOFTIRQ);
+
+       local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(blk_complete_request);
+       
 /*
  * queue lock must be held
  */
@@ -3364,6 +3433,8 @@ EXPORT_SYMBOL(kblockd_flush);
 
 int __init blk_dev_init(void)
 {
+       int i;
+
        kblockd_workqueue = create_workqueue("kblockd");
        if (!kblockd_workqueue)
                panic("Failed to create kblockd\n");
@@ -3377,6 +3448,14 @@ int __init blk_dev_init(void)
        iocontext_cachep = kmem_cache_create("blkdev_ioc",
                        sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL);
 
+       for (i = 0; i < NR_CPUS; i++)
+               INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
+
+       open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL);
+#ifdef CONFIG_HOTPLUG_CPU
+       register_cpu_notifier(&blk_cpu_notifier);
+#endif
+
        blk_max_low_pfn = max_low_pfn;
        blk_max_pfn = max_pfn;
 
index c2ac36dfe4f3a8253bba24933ab9f5b66634eb83..18de84c8ccd8bca5d1fafe8d0326cda0998cf87d 100644 (file)
@@ -190,16 +190,21 @@ static int verify_command(struct file *file, unsigned char *cmd)
                safe_for_write(GPCMD_SET_STREAMING),
        };
        unsigned char type = cmd_type[cmd[0]];
+       int has_write_perm = 0;
 
        /* Anybody who can open the device can do a read-safe command */
        if (type & CMD_READ_SAFE)
                return 0;
 
+       /*
+        * file can be NULL from ioctl_by_bdev()...
+        */
+       if (file)
+               has_write_perm = file->f_mode & FMODE_WRITE;
+
        /* Write-safe commands just require a writable open.. */
-       if (type & CMD_WRITE_SAFE) {
-               if (file->f_mode & FMODE_WRITE)
-                       return 0;
-       }
+       if ((type & CMD_WRITE_SAFE) && has_write_perm)
+               return 0;
 
        /* And root can do any command.. */
        if (capable(CAP_SYS_RAWIO))
index 4b65f74d66b1a2465798618a347424260833c4cd..ce074f6f3369c338e16828fde64f0864cc8a00d2 100644 (file)
@@ -129,19 +129,6 @@ static DEFINE_SPINLOCK(mfm_lock);
 #define MAJOR_NR       MFM_ACORN_MAJOR
 #define QUEUE (mfm_queue)
 #define CURRENT elv_next_request(mfm_queue)
-/*
- * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
- */
-#ifndef HDIO_GETGEO
-#define HDIO_GETGEO 0x301
-struct hd_geometry {
-       unsigned char heads;
-       unsigned char sectors;
-       unsigned short cylinders;
-       unsigned long start;
-};
-#endif
-
 
 /*
  * Configuration section
@@ -1153,22 +1140,13 @@ static int mfm_initdrives(void)
  * The 'front' end of the mfm driver follows...
  */
 
-static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
+static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct mfm_info *p = inode->i_bdev->bd_disk->private_data;
-       struct hd_geometry *geo = (struct hd_geometry *) arg;
-       if (cmd != HDIO_GETGEO)
-               return -EINVAL;
-       if (!arg)
-               return -EINVAL;
-       if (put_user (p->heads, &geo->heads))
-               return -EFAULT;
-       if (put_user (p->sectors, &geo->sectors))
-               return -EFAULT;
-       if (put_user (p->cylinders, &geo->cylinders))
-               return -EFAULT;
-       if (put_user (get_start_sect(inode->i_bdev), &geo->start))
-               return -EFAULT;
+       struct mfm_info *p = bdev->bd_disk->private_data;
+
+       geo->heads = p->heads;
+       geo->sectors = p->sectors;
+       geo->cylinders = p->cylinders;
        return 0;
 }
 
@@ -1219,7 +1197,7 @@ void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
 static struct block_device_operations mfm_fops =
 {
        .owner          = THIS_MODULE,
-       .ioctl          = mfm_ioctl,
+       .getgeo         = mfm_getgeo,
 };
 
 /*
index e3cd0b16031ad32c70ee1b47516c23b02856cbcb..20c9a37643c73110f0e18fd5efef989906d2bf14 100644 (file)
@@ -204,11 +204,13 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
 
        return AE_OK;
 }
+EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
 void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
 {
        iounmap(virt);
 }
+EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
 #ifdef ACPI_FUTURE_USAGE
 acpi_status
index c57e20dcb0f839004267dc3ffbdc16e95a351403..074abc81ec3d099cc7353c1a2568bec68f005aaa 100644 (file)
@@ -2126,8 +2126,7 @@ static void process_rsq(ns_dev *card)
 
    if (!ns_rsqe_valid(card->rsq.next))
       return;
-   while (ns_rsqe_valid(card->rsq.next))
-   {
+   do {
       dequeue_rx(card, card->rsq.next);
       ns_rsqe_init(card->rsq.next);
       previous = card->rsq.next;
@@ -2135,7 +2134,7 @@ static void process_rsq(ns_dev *card)
          card->rsq.next = card->rsq.base;
       else
          card->rsq.next++;
-   }
+   } while (ns_rsqe_valid(card->rsq.next));
    writel((((u32) previous) - ((u32) card->rsq.base)),
           card->membase + RSQH);
 }
index 21097a39a057e83e6d495f031cdf4ab23881ed48..4a7bb7dfce851305b4083b17ceba732729933aca 100644 (file)
@@ -92,34 +92,28 @@ static int DAC960_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int DAC960_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
+static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct gendisk *disk = bdev->bd_disk;
        DAC960_Controller_T *p = disk->queue->queuedata;
        int drive_nr = (long)disk->private_data;
-       struct hd_geometry g;
-       struct hd_geometry __user *loc = (struct hd_geometry __user *)arg;
-
-       if (cmd != HDIO_GETGEO || !loc)
-               return -EINVAL;
 
        if (p->FirmwareType == DAC960_V1_Controller) {
-               g.heads = p->V1.GeometryTranslationHeads;
-               g.sectors = p->V1.GeometryTranslationSectors;
-               g.cylinders = p->V1.LogicalDriveInformation[drive_nr].
-                       LogicalDriveSize / (g.heads * g.sectors);
+               geo->heads = p->V1.GeometryTranslationHeads;
+               geo->sectors = p->V1.GeometryTranslationSectors;
+               geo->cylinders = p->V1.LogicalDriveInformation[drive_nr].
+                       LogicalDriveSize / (geo->heads * geo->sectors);
        } else {
                DAC960_V2_LogicalDeviceInfo_T *i =
                        p->V2.LogicalDeviceInformation[drive_nr];
                switch (i->DriveGeometry) {
                case DAC960_V2_Geometry_128_32:
-                       g.heads = 128;
-                       g.sectors = 32;
+                       geo->heads = 128;
+                       geo->sectors = 32;
                        break;
                case DAC960_V2_Geometry_255_63:
-                       g.heads = 255;
-                       g.sectors = 63;
+                       geo->heads = 255;
+                       geo->sectors = 63;
                        break;
                default:
                        DAC960_Error("Illegal Logical Device Geometry %d\n",
@@ -127,12 +121,11 @@ static int DAC960_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                }
 
-               g.cylinders = i->ConfigurableDeviceSize / (g.heads * g.sectors);
+               geo->cylinders = i->ConfigurableDeviceSize /
+                       (geo->heads * geo->sectors);
        }
        
-       g.start = get_start_sect(inode->i_bdev);
-
-       return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+       return 0;
 }
 
 static int DAC960_media_changed(struct gendisk *disk)
@@ -157,7 +150,7 @@ static int DAC960_revalidate_disk(struct gendisk *disk)
 static struct block_device_operations DAC960_BlockDeviceOperations = {
        .owner                  = THIS_MODULE,
        .open                   = DAC960_open,
-       .ioctl                  = DAC960_ioctl,
+       .getgeo                 = DAC960_getgeo,
        .media_changed          = DAC960_media_changed,
        .revalidate_disk        = DAC960_revalidate_disk,
 };
@@ -3767,7 +3760,7 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
              if (SenseKey == DAC960_SenseKey_VendorSpecific &&
                  AdditionalSenseCode == 0x80 &&
                  AdditionalSenseCodeQualifier <
-                 sizeof(DAC960_EventMessages) / sizeof(char *))
+                 ARRAY_SIZE(DAC960_EventMessages))
                DAC960_Critical("Physical Device %d:%d %s\n", Controller,
                                EventLogEntry->Channel,
                                EventLogEntry->TargetID,
index 5d2d649f7e8d517f950ce01a99a2395ef4533f30..196c0ec9cd5421da1c1f278d15fc66e5d474b8f4 100644 (file)
@@ -1079,6 +1079,19 @@ static void redo_acsi_request( void )
  *
  ***********************************************************************/
 
+static int acsi_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       struct acsi_info_struct *aip = bdev->bd_disk->private_data;
+
+       /*
+        * Just fake some geometry here, it's nonsense anyway
+        * To make it easy, use Adaptec's usual 64/32 mapping
+        */
+       geo->heads = 64;
+       geo->sectors = 32;
+       geo->cylinders = aip->size >> 11;
+       return 0;
+}
 
 static int acsi_ioctl( struct inode *inode, struct file *file,
                                           unsigned int cmd, unsigned long arg )
@@ -1086,18 +1099,6 @@ static int acsi_ioctl( struct inode *inode, struct file *file,
        struct gendisk *disk = inode->i_bdev->bd_disk;
        struct acsi_info_struct *aip = disk->private_data;
        switch (cmd) {
-         case HDIO_GETGEO:
-               /* HDIO_GETGEO is supported more for getting the partition's
-                * start sector... */
-         { struct hd_geometry *geo = (struct hd_geometry *)arg;
-           /* just fake some geometry here, it's nonsense anyway; to make it
-                * easy, use Adaptec's usual 64/32 mapping */
-           put_user( 64, &geo->heads );
-           put_user( 32, &geo->sectors );
-           put_user( aip->size >> 11, &geo->cylinders );
-               put_user(get_start_sect(inode->i_bdev), &geo->start);
-               return 0;
-         }
          case SCSI_IOCTL_GET_IDLUN:
                /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */
                put_user( aip->target | (aip->lun << 8),
@@ -1592,6 +1593,7 @@ static struct block_device_operations acsi_fops = {
        .open           = acsi_open,
        .release        = acsi_release,
        .ioctl          = acsi_ioctl,
+       .getgeo         = acsi_getgeo,
        .media_changed  = acsi_media_change,
        .revalidate_disk= acsi_revalidate,
 };
index 0acbfff8ad284ecb0d7adb7c57f32787f6e071c2..3c679d30b69849f46e1cc0489de8a0b91891225a 100644 (file)
@@ -131,7 +131,7 @@ static struct fd_drive_type drive_types[] = {
 { FD_DD_5,     "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2},
 { FD_NODRIVE, "No Drive", 0, 0,     0,     0, 0,  0,  0,  0,  0, 0}
 };
-static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
+static int num_dr_types = ARRAY_SIZE(drive_types);
 
 static int amiga_read(int), dos_read(int);
 static void amiga_write(int), dos_write(int);
@@ -1424,6 +1424,16 @@ static void do_fd_request(request_queue_t * q)
        redo_fd_request();
 }
 
+static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       int drive = MINOR(bdev->bd_dev) & 3;
+
+       geo->heads = unit[drive].type->heads;
+       geo->sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult;
+       geo->cylinders = unit[drive].type->tracks;
+       return 0;
+}
+
 static int fd_ioctl(struct inode *inode, struct file *filp,
                    unsigned int cmd, unsigned long param)
 {
@@ -1431,18 +1441,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
        static struct floppy_struct getprm;
 
        switch(cmd){
-       case HDIO_GETGEO:
-       {
-               struct hd_geometry loc;
-               loc.heads = unit[drive].type->heads;
-               loc.sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult;
-               loc.cylinders = unit[drive].type->tracks;
-               loc.start = 0;
-               if (copy_to_user((void *)param, (void *)&loc,
-                                sizeof(struct hd_geometry)))
-                       return -EFAULT;
-               break;
-       }
        case FDFMTBEG:
                get_fdc(drive);
                if (fd_ref[drive] > 1) {
@@ -1652,6 +1650,7 @@ static struct block_device_operations floppy_fops = {
        .open           = floppy_open,
        .release        = floppy_release,
        .ioctl          = fd_ioctl,
+       .getgeo         = fd_getgeo,
        .media_changed  = amiga_floppy_change,
 };
 
index 0e97fcb9f3a15b3bbe5b4a0bb8bd085c20e05b2b..c05ee8bffd97921dcd44438a9ade85e6b4a1f789 100644 (file)
@@ -169,38 +169,26 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio)
        return 0;
 }
 
-/* This ioctl implementation expects userland to have the device node
- * permissions set so that only priviledged users can open an aoe
- * block device directly.
- */
 static int
-aoeblk_ioctl(struct inode *inode, struct file *filp, uint cmd, ulong arg)
+aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct aoedev *d;
-
-       if (!arg)
-               return -EINVAL;
+       struct aoedev *d = bdev->bd_disk->private_data;
 
-       d = inode->i_bdev->bd_disk->private_data;
        if ((d->flags & DEVFL_UP) == 0) {
                printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n");
                return -ENODEV;
        }
 
-       if (cmd == HDIO_GETGEO) {
-               d->geo.start = get_start_sect(inode->i_bdev);
-               if (!copy_to_user((void __user *) arg, &d->geo, sizeof d->geo))
-                       return 0;
-               return -EFAULT;
-       }
-       printk(KERN_INFO "aoe: aoeblk_ioctl: unknown ioctl %d\n", cmd);
-       return -EINVAL;
+       geo->cylinders = d->geo.cylinders;
+       geo->heads = d->geo.heads;
+       geo->sectors = d->geo.sectors;
+       return 0;
 }
 
 static struct block_device_operations aoe_bdops = {
        .open = aoeblk_open,
        .release = aoeblk_release,
-       .ioctl = aoeblk_ioctl,
+       .getgeo = aoeblk_getgeo,
        .owner = THIS_MODULE,
 };
 
index 22bda05fc693f454e801ce902ec248a2416572bd..3aa68a5447d69a65b405b7796706c89db506a648 100644 (file)
@@ -181,7 +181,7 @@ static struct {
        {  6, TYPE_HD },        /* 31: H1640    <- was H1600 == h1600 for PC */
 };
 
-#define NUM_DISK_MINORS (sizeof(minor2disktype)/sizeof(*minor2disktype))
+#define NUM_DISK_MINORS ARRAY_SIZE(minor2disktype)
 
 /*
  * Maximum disk size (in kilobytes). This default is used whenever the
index d2815b7a9150dbf9d0fb417b8dc3acadd8315b40..e4e9f255bd1f709a01a58dc5d09c2e8b10684820 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
- *    Copyright 2000, 2005 Hewlett-Packard Development Company, L.P.
+ *    Copyright 2000, 2006 Hewlett-Packard Development Company, L.P.
  *
  *    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
 #include <linux/completion.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.6.8)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8)
+#define DRIVER_NAME "HP CISS Driver (v 2.6.10)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,10)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8");
+MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.10");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
                        " SA6i P600 P800 P400 P400i E200 E200i");
 MODULE_LICENSE("GPL");
@@ -103,7 +103,7 @@ static const struct pci_device_id cciss_pci_device_id[] = {
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 
-#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type))
+#define NR_PRODUCTS ARRAY_SIZE(products)
 
 /*  board_id = Subsystem Device ID & Vendor ID
  *  product = Marketing Name for the board
@@ -153,6 +153,7 @@ static int cciss_open(struct inode *inode, struct file *filep);
 static int cciss_release(struct inode *inode, struct file *filep);
 static int cciss_ioctl(struct inode *inode, struct file *filep, 
                unsigned int cmd, unsigned long arg);
+static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static int revalidate_allvol(ctlr_info_t *host);
 static int cciss_revalidate(struct gendisk *disk);
@@ -166,7 +167,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
                        unsigned int block_size, InquiryData_struct *inq_buff,
                        drive_info_struct *drv);
 static void cciss_getgeometry(int cntl_num);
-
+static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32);
 static void start_io( ctlr_info_t *h);
 static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
        unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
@@ -194,6 +195,7 @@ static struct block_device_operations cciss_fops  = {
        .open           = cciss_open, 
        .release        = cciss_release,
         .ioctl         = cciss_ioctl,
+        .getgeo                = cciss_getgeo,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = cciss_compat_ioctl,
 #endif
@@ -282,7 +284,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
                 h->product_name,
                 (unsigned long)h->board_id,
                h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
-                (unsigned int)h->intr,
+                (unsigned int)h->intr[SIMPLE_MODE_INT],
                 h->num_luns, 
                h->Qdepth, h->commands_outstanding,
                h->maxQsinceinit, h->max_outstanding, h->maxSG);
@@ -633,6 +635,20 @@ static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned
        return err;
 }
 #endif
+
+static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       drive_info_struct *drv = get_drv(bdev->bd_disk);
+
+       if (!drv->cylinders)
+               return -ENXIO;
+
+       geo->heads = drv->heads;
+       geo->sectors = drv->sectors;
+       geo->cylinders = drv->cylinders;
+       return 0;
+}
+
 /*
  * ioctl 
  */
@@ -651,21 +667,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 #endif /* CCISS_DEBUG */ 
        
        switch(cmd) {
-       case HDIO_GETGEO:
-       {
-                struct hd_geometry driver_geo;
-                if (drv->cylinders) {
-                        driver_geo.heads = drv->heads;
-                        driver_geo.sectors = drv->sectors;
-                        driver_geo.cylinders = drv->cylinders;
-                } else
-                       return -ENXIO;
-                driver_geo.start= get_start_sect(inode->i_bdev);
-                if (copy_to_user(argp, &driver_geo, sizeof(struct hd_geometry)))
-                        return  -EFAULT;
-                return(0);
-       }
-
        case CCISS_GETPCIINFO:
        {
                cciss_pci_info_struct pciinfo;
@@ -2177,16 +2178,48 @@ static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
 
        start_io(h);
 }
+
+static void cciss_softirq_done(struct request *rq)
+{
+       CommandList_struct *cmd = rq->completion_data;
+       ctlr_info_t *h = hba[cmd->ctlr];
+       u64bit temp64;
+       int i, ddir;
+
+       if (cmd->Request.Type.Direction == XFER_READ)
+               ddir = PCI_DMA_FROMDEVICE;
+       else
+               ddir = PCI_DMA_TODEVICE;
+
+       /* command did not need to be retried */
+       /* unmap the DMA mapping for all the scatter gather elements */
+       for(i=0; i<cmd->Header.SGList; i++) {
+               temp64.val32.lower = cmd->SG[i].Addr.lower;
+               temp64.val32.upper = cmd->SG[i].Addr.upper;
+               pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
+       }
+
+       complete_buffers(rq->bio, rq->errors);
+
+#ifdef CCISS_DEBUG
+       printk("Done with %p\n", rq);
+#endif /* CCISS_DEBUG */ 
+
+       spin_lock_irq(&h->lock);
+       end_that_request_last(rq, rq->errors);
+       cmd_free(h, cmd,1);
+       spin_unlock_irq(&h->lock);
+}
+
 /* checks the status of the job and calls complete buffers to mark all 
- * buffers for the completed job. 
+ * buffers for the completed job. Note that this function does not need
+ * to hold the hba/queue lock.
  */ 
 static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
                int timeout)
 {
        int status = 1;
-       int i;
        int retry_cmd = 0;
-       u64bit temp64;
                
        if (timeout)
                status = 0; 
@@ -2294,24 +2327,10 @@ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
                resend_cciss_cmd(h,cmd);
                return;
        }       
-       /* command did not need to be retried */
-       /* unmap the DMA mapping for all the scatter gather elements */
-       for(i=0; i<cmd->Header.SGList; i++) {
-               temp64.val32.lower = cmd->SG[i].Addr.lower;
-               temp64.val32.upper = cmd->SG[i].Addr.upper;
-               pci_unmap_page(hba[cmd->ctlr]->pdev,
-                       temp64.val, cmd->SG[i].Len,
-                       (cmd->Request.Type.Direction == XFER_READ) ?
-                               PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-       }
-       complete_buffers(cmd->rq->bio, status);
 
-#ifdef CCISS_DEBUG
-       printk("Done with %p\n", cmd->rq);
-#endif /* CCISS_DEBUG */ 
-
-       end_that_request_last(cmd->rq, status ? 1 : -EIO);
-       cmd_free(h,cmd,1);
+       cmd->rq->completion_data = cmd;
+       cmd->rq->errors = status;
+       blk_complete_request(cmd->rq);
 }
 
 /* 
@@ -2661,6 +2680,60 @@ static int find_PCI_BAR_index(struct pci_dev *pdev,
        return -1;
 }
 
+/* If MSI/MSI-X is supported by the kernel we will try to enable it on
+ * controllers that are capable. If not, we use IO-APIC mode.
+ */
+
+static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id)
+{
+#ifdef CONFIG_PCI_MSI
+        int err;
+        struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1},
+                                                  {0,2}, {0,3}};
+
+       /* Some boards advertise MSI but don't really support it */
+       if ((board_id == 0x40700E11) ||
+               (board_id == 0x40800E11) ||
+               (board_id == 0x40820E11) ||
+               (board_id == 0x40830E11))
+               goto default_int_mode;
+
+        if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+                err = pci_enable_msix(pdev, cciss_msix_entries, 4);
+                if (!err) {
+                        c->intr[0] = cciss_msix_entries[0].vector;
+                        c->intr[1] = cciss_msix_entries[1].vector;
+                        c->intr[2] = cciss_msix_entries[2].vector;
+                        c->intr[3] = cciss_msix_entries[3].vector;
+                        c->msix_vector = 1;
+                        return;
+                }
+                if (err > 0) {
+                        printk(KERN_WARNING "cciss: only %d MSI-X vectors "
+                                        "available\n", err);
+                } else {
+                        printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
+                                               err);
+                }
+        }
+        if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+                if (!pci_enable_msi(pdev)) {
+                        c->intr[SIMPLE_MODE_INT] = pdev->irq;
+                        c->msi_vector = 1;
+                        return;
+                } else {
+                        printk(KERN_WARNING "cciss: MSI init failed\n");
+                       c->intr[SIMPLE_MODE_INT] = pdev->irq;
+                        return;
+                }
+        }
+#endif /* CONFIG_PCI_MSI */
+       /* if we get here we're going to use the default interrupt mode */
+default_int_mode:
+        c->intr[SIMPLE_MODE_INT] = pdev->irq;
+       return;
+}
+
 static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 {
        ushort subsystem_vendor_id, subsystem_device_id, command;
@@ -2721,7 +2794,10 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
        printk("board_id = %x\n", board_id);
 #endif /* CCISS_DEBUG */ 
 
-       c->intr = pdev->irq;
+/* If the kernel supports MSI/MSI-X we will try to enable that functionality,
+ * else we use the IO-APIC interrupt assigned to us by system ROM.
+ */
+       cciss_interrupt_mode(c, pdev, board_id);
 
        /*
         * Memory base addr is first addr , the second points to the config
@@ -2775,7 +2851,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
        c->board_id = board_id;
 
 #ifdef CCISS_DEBUG
-       print_cfg_table(c->cfgtable); 
+       print_cfg_table(c->cfgtable);
 #endif /* CCISS_DEBUG */
 
        for(i=0; i<NR_PRODUCTS; i++) {
@@ -3060,7 +3136,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
         * 8 controller support.
         */
        if (i < MAX_CTLR_ORIG)
-               hba[i]->major = MAJOR_NR + i;
+               hba[i]->major = COMPAQ_CISS_MAJOR + i;
        rc = register_blkdev(hba[i]->major, hba[i]->devname);
        if(rc == -EBUSY || rc == -EINVAL) {
                printk(KERN_ERR
@@ -3075,11 +3151,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
        /* make sure the board interrupts are off */
        hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
-       if( request_irq(hba[i]->intr, do_cciss_intr, 
+       if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
                SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
                        hba[i]->devname, hba[i])) {
                printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
-                       hba[i]->intr, hba[i]->devname);
+                       hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
                goto clean2;
        }
        hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
@@ -3141,15 +3217,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                drv->queue = q;
 
                q->backing_dev_info.ra_pages = READ_AHEAD;
-       blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+               blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
 
-       /* This is a hardware imposed limit. */
-       blk_queue_max_hw_segments(q, MAXSGENTRIES);
+               /* This is a hardware imposed limit. */
+               blk_queue_max_hw_segments(q, MAXSGENTRIES);
 
-       /* This is a limit in the driver and could be eliminated. */
-       blk_queue_max_phys_segments(q, MAXSGENTRIES);
+               /* This is a limit in the driver and could be eliminated. */
+               blk_queue_max_phys_segments(q, MAXSGENTRIES);
 
-       blk_queue_max_sectors(q, 512);
+               blk_queue_max_sectors(q, 512);
+
+               blk_queue_softirq_done(q, cciss_softirq_done);
 
                q->queuedata = hba[i];
                sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
@@ -3185,7 +3263,7 @@ clean4:
                        NR_CMDS * sizeof( ErrorInfo_struct),
                        hba[i]->errinfo_pool,
                        hba[i]->errinfo_pool_dhandle);
-       free_irq(hba[i]->intr, hba[i]);
+       free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]);
 clean2:
        unregister_blkdev(hba[i]->major, hba[i]->devname);
 clean1:
@@ -3226,7 +3304,15 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
                printk(KERN_WARNING "Error Flushing cache on controller %d\n", 
                        i);
        }
-       free_irq(hba[i]->intr, hba[i]);
+       free_irq(hba[i]->intr[2], hba[i]);
+
+#ifdef CONFIG_PCI_MSI
+        if (hba[i]->msix_vector)
+                pci_disable_msix(hba[i]->pdev);
+        else if (hba[i]->msi_vector)
+                pci_disable_msi(hba[i]->pdev);
+#endif /* CONFIG_PCI_MSI */
+
        pci_set_drvdata(pdev, NULL);
        iounmap(hba[i]->vaddr);
        cciss_unregister_scsi(i);  /* unhook from SCSI subsystem */
index 3b0858c83897f4fc5c4d25cc0450b6864c33cffc..b24fc0553ccf958c95538d22f79ad4f2682b068c 100644 (file)
@@ -13,8 +13,6 @@
 #define IO_OK          0
 #define IO_ERROR       1
 
-#define MAJOR_NR COMPAQ_CISS_MAJOR
-
 struct ctlr_info;
 typedef struct ctlr_info ctlr_info_t;
 
@@ -65,7 +63,6 @@ struct ctlr_info
        unsigned long io_mem_addr;
        unsigned long io_mem_length;
        CfgTable_struct __iomem *cfgtable;
-       unsigned int intr;
        int     interrupts_enabled;
        int     major;
        int     max_commands;
@@ -74,6 +71,13 @@ struct ctlr_info
        int     num_luns;
        int     highest_lun;
        int     usage_count;  /* number of opens all all minor devices */
+#      define DOORBELL_INT     0
+#      define PERF_MODE_INT    1
+#      define SIMPLE_MODE_INT  2
+#      define MEMQ_MODE_INT    3
+       unsigned int intr[4];
+       unsigned int msix_vector;
+       unsigned int msi_vector;
 
        // information about each logical volume
        drive_info_struct drv[CISS_MAX_LUN];
index 2942d32280a5e93a2628a8dce0f99cebc8928f6f..9e35de05d5c551b91aee24f908804a7da40a80f2 100644 (file)
@@ -714,7 +714,7 @@ cciss_scsi_detect(int ctlr)
        ((struct cciss_scsi_adapter_data_t *) 
                hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh;
        sh->hostdata[0] = (unsigned long) hba[ctlr];
-       sh->irq = hba[ctlr]->intr;
+       sh->irq = hba[ctlr]->intr[SIMPLE_MODE_INT];
        sh->unique_id = sh->irq;
        error = scsi_add_host(sh, &hba[ctlr]->pdev->dev);
        if (error)
index 9bddb687487375f3e0428813afa5509816b5b693..862b9abac0aea0943298aa61bc581ba14fa8edc5 100644 (file)
@@ -72,11 +72,11 @@ static ctlr_info_t *hba[MAX_CTLR];
 
 static int eisa[8];
 
-#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type))
+#define NR_PRODUCTS ARRAY_SIZE(products)
 
 /*  board_id = Subsystem Device ID & Vendor ID
  *  product = Marketing Name for the board
- *  access = Address of the struct of function pointers 
+ *  access = Address of the struct of function pointers
  */
 static struct board_type products[] = {
        { 0x0040110E, "IDA",                    &smart1_access },
@@ -160,6 +160,7 @@ static int sendcmd(
 static int ida_open(struct inode *inode, struct file *filep);
 static int ida_release(struct inode *inode, struct file *filep);
 static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
+static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io);
 
 static void do_ida_request(request_queue_t *q);
@@ -199,6 +200,7 @@ static struct block_device_operations ida_fops  = {
        .open           = ida_open,
        .release        = ida_release,
        .ioctl          = ida_ioctl,
+       .getgeo         = ida_getgeo,
        .revalidate_disk= ida_revalidate,
 };
 
@@ -1124,6 +1126,23 @@ static void ida_timer(unsigned long tdata)
        h->misc_tflags = 0;
 }
 
+static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       drv_info_t *drv = get_drv(bdev->bd_disk);
+
+       if (drv->cylinders) {
+               geo->heads = drv->heads;
+               geo->sectors = drv->sectors;
+               geo->cylinders = drv->cylinders;
+       } else {
+               geo->heads = 0xff;
+               geo->sectors = 0x3f;
+               geo->cylinders = drv->nr_blks / (0xff*0x3f);
+       }
+
+       return 0;
+}
+
 /*
  *  ida_ioctl does some miscellaneous stuff like reporting drive geometry,
  *  setting readahead and submitting commands from userspace to the controller.
@@ -1133,27 +1152,10 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
        drv_info_t *drv = get_drv(inode->i_bdev->bd_disk);
        ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
        int error;
-       int diskinfo[4];
-       struct hd_geometry __user *geo = (struct hd_geometry __user *)arg;
        ida_ioctl_t __user *io = (ida_ioctl_t __user *)arg;
        ida_ioctl_t *my_io;
 
        switch(cmd) {
-       case HDIO_GETGEO:
-               if (drv->cylinders) {
-                       diskinfo[0] = drv->heads;
-                       diskinfo[1] = drv->sectors;
-                       diskinfo[2] = drv->cylinders;
-               } else {
-                       diskinfo[0] = 0xff;
-                       diskinfo[1] = 0x3f;
-                       diskinfo[2] = drv->nr_blks / (0xff*0x3f);
-               }
-               put_user(diskinfo[0], &geo->heads);
-               put_user(diskinfo[1], &geo->sectors);
-               put_user(diskinfo[2], &geo->cylinders);
-               put_user(get_start_sect(inode->i_bdev), &geo->start);
-               return 0;
        case IDAGETDRVINFO:
                if (copy_to_user(&io->c.drv, drv, sizeof(drv_info_t)))
                        return -EFAULT;
index a5b857c5c4b8c18c3cbd897912e854bd919a6e57..374621a512e09b319f7a28bc306a70b5722562c4 100644 (file)
@@ -479,7 +479,6 @@ static struct floppy_struct floppy_type[32] = {
        { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5"    */
 };
 
-#define        NUMBER(x)       (sizeof(x) / sizeof(*(x)))
 #define SECTSIZE (_FD_SECTSIZE(*floppy))
 
 /* Auto-detection: Disk type used until the next media change occurs. */
@@ -3445,6 +3444,23 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
        return 0;
 }
 
+static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       int drive = (long)bdev->bd_disk->private_data;
+       int type = ITYPE(drive_state[drive].fd_device);
+       struct floppy_struct *g;
+       int ret;
+
+       ret = get_floppy_geometry(drive, type, &g);
+       if (ret)
+               return ret;
+
+       geo->heads = g->head;
+       geo->sectors = g->sect;
+       geo->cylinders = g->track;
+       return 0;
+}
+
 static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                    unsigned long param)
 {
@@ -3474,23 +3490,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                cmd = FDEJECT;
        }
 
-       /* generic block device ioctls */
-       switch (cmd) {
-               /* the following have been inspired by the corresponding
-                * code for other block devices. */
-               struct floppy_struct *g;
-       case HDIO_GETGEO:
-               {
-                       struct hd_geometry loc;
-                       ECALL(get_floppy_geometry(drive, type, &g));
-                       loc.heads = g->head;
-                       loc.sectors = g->sect;
-                       loc.cylinders = g->track;
-                       loc.start = 0;
-                       return _COPYOUT(loc);
-               }
-       }
-
        /* convert the old style command into a new style command */
        if ((cmd & 0xff00) == 0x0200) {
                ECALL(normalize_ioctl(&cmd, &size));
@@ -3645,7 +3644,7 @@ static void __init config_types(void)
                const char *name = NULL;
                static char temparea[32];
 
-               if (type < NUMBER(default_drive_params)) {
+               if (type < ARRAY_SIZE(default_drive_params)) {
                        params = &default_drive_params[type].params;
                        if (type) {
                                name = default_drive_params[type].name;
@@ -3938,6 +3937,7 @@ static struct block_device_operations floppy_fops = {
        .open           = floppy_open,
        .release        = floppy_release,
        .ioctl          = fd_ioctl,
+       .getgeo         = fd_getgeo,
        .media_changed  = check_floppy_change,
        .revalidate_disk = floppy_revalidate,
 };
@@ -3960,7 +3960,7 @@ static void __init register_devfs_entries(int drive)
 {
        int base_minor = (drive < 4) ? drive : (124 + drive);
 
-       if (UDP->cmos < NUMBER(default_drive_params)) {
+       if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
                int i = 0;
                do {
                        int minor = base_minor + (table_sup[UDP->cmos][i] << 2);
@@ -4218,7 +4218,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
            !(allowed_drive_mask & (1 << drive)) ||
            fdc_state[FDC(drive)].version == FDC_NONE)
                return NULL;
-       if (((*part >> 2) & 0x1f) >= NUMBER(floppy_type))
+       if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
                return NULL;
        *part = 0;
        return get_disk(disks[drive]);
@@ -4570,7 +4570,7 @@ static void unregister_devfs_entries(int drive)
 {
        int i;
 
-       if (UDP->cmos < NUMBER(default_drive_params)) {
+       if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
                i = 0;
                do {
                        devfs_remove("floppy/%d%s", drive,
index 33d6f237b2edc8fb4134413d55e58a7d5bb4d7ea..6997d8e6bfb5d70e9dfcc25d391be36ae2799a87 100644 (file)
@@ -174,7 +174,6 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size,
                msg.msg_namelen = 0;
                msg.msg_control = NULL;
                msg.msg_controllen = 0;
-               msg.msg_namelen = 0;
                msg.msg_flags = msg_flags | MSG_NOSIGNAL;
 
                if (send)
index fa49d62626ba12d1e8647993f48a4fa6e655d660..62d2464c12f2001017077dadb883e0a18264be84 100644 (file)
@@ -747,32 +747,33 @@ static int pd_open(struct inode *inode, struct file *file)
        return 0;
 }
 
+static int pd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       struct pd_unit *disk = bdev->bd_disk->private_data;
+
+       if (disk->alt_geom) {
+               geo->heads = PD_LOG_HEADS;
+               geo->sectors = PD_LOG_SECTS;
+               geo->cylinders = disk->capacity / (geo->heads * geo->sectors);
+       } else {
+               geo->heads = disk->heads;
+               geo->sectors = disk->sectors;
+               geo->cylinders = disk->cylinders;
+       }
+
+       return 0;
+}
+
 static int pd_ioctl(struct inode *inode, struct file *file,
         unsigned int cmd, unsigned long arg)
 {
        struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
-       struct hd_geometry __user *geo = (struct hd_geometry __user *) arg;
-       struct hd_geometry g;
 
        switch (cmd) {
        case CDROMEJECT:
                if (disk->access == 1)
                        pd_special_command(disk, pd_eject);
                return 0;
-       case HDIO_GETGEO:
-               if (disk->alt_geom) {
-                       g.heads = PD_LOG_HEADS;
-                       g.sectors = PD_LOG_SECTS;
-                       g.cylinders = disk->capacity / (g.heads * g.sectors);
-               } else {
-                       g.heads = disk->heads;
-                       g.sectors = disk->sectors;
-                       g.cylinders = disk->cylinders;
-               }
-               g.start = get_start_sect(inode->i_bdev);
-               if (copy_to_user(geo, &g, sizeof(struct hd_geometry)))
-                       return -EFAULT;
-               return 0;
        default:
                return -EINVAL;
        }
@@ -815,6 +816,7 @@ static struct block_device_operations pd_fops = {
        .open           = pd_open,
        .release        = pd_release,
        .ioctl          = pd_ioctl,
+       .getgeo         = pd_getgeo,
        .media_changed  = pd_check_media,
        .revalidate_disk= pd_revalidate
 };
index e9746af29b9f0299f03261667e43fb86f8f7063d..852b564e903a69566a1f3b82d3a339d884db9b98 100644 (file)
@@ -205,6 +205,7 @@ static int pf_open(struct inode *inode, struct file *file);
 static void do_pf_request(request_queue_t * q);
 static int pf_ioctl(struct inode *inode, struct file *file,
                    unsigned int cmd, unsigned long arg);
+static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static int pf_release(struct inode *inode, struct file *file);
 
@@ -266,6 +267,7 @@ static struct block_device_operations pf_fops = {
        .open           = pf_open,
        .release        = pf_release,
        .ioctl          = pf_ioctl,
+       .getgeo         = pf_getgeo,
        .media_changed  = pf_check_media,
 };
 
@@ -313,34 +315,34 @@ static int pf_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct pf_unit *pf = inode->i_bdev->bd_disk->private_data;
-       struct hd_geometry __user *geo = (struct hd_geometry __user *) arg;
-       struct hd_geometry g;
-       sector_t capacity;
-
-       if (cmd == CDROMEJECT) {
-               if (pf->access == 1) {
-                       pf_eject(pf);
-                       return 0;
-               }
-               return -EBUSY;
-       }
-       if (cmd != HDIO_GETGEO)
-               return -EINVAL;
-       capacity = get_capacity(pf->disk);
+       struct pf_unit *pf = bdev->bd_disk->private_data;
+       sector_t capacity = get_capacity(pf->disk);
+
        if (capacity < PF_FD_MAX) {
-               g.cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT);
-               g.heads = PF_FD_HDS;
-               g.sectors = PF_FD_SPT;
+               geo->cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT);
+               geo->heads = PF_FD_HDS;
+               geo->sectors = PF_FD_SPT;
        } else {
-               g.cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT);
-               g.heads = PF_HD_HDS;
-               g.sectors = PF_HD_SPT;
+               geo->cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT);
+               geo->heads = PF_HD_HDS;
+               geo->sectors = PF_HD_SPT;
        }
-       if (copy_to_user(geo, &g, sizeof(g)))
-               return -EFAULT;
+
+       return 0;
+}
+
+static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct pf_unit *pf = inode->i_bdev->bd_disk->private_data;
+
+       if (cmd != CDROMEJECT)
+               return -EINVAL;
+
+       if (pf->access != 1)
+               return -EBUSY;
+       pf_eject(pf);
        return 0;
 }
 
index c0233efabebae2216eabeabda378bba0aafce661..51b7a5c5b77ab2bd5e5584cc96f72af11d016d96 100644 (file)
@@ -1955,9 +1955,12 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
        if ((ret = blkdev_get(pd->bdev, FMODE_READ, O_RDONLY)))
                goto out;
 
+       if ((ret = bd_claim(pd->bdev, pd)))
+               goto out_putdev;
+
        if ((ret = pkt_get_last_written(pd, &lba))) {
                printk("pktcdvd: pkt_get_last_written failed\n");
-               goto out_putdev;
+               goto out_unclaim;
        }
 
        set_capacity(pd->disk, lba << 2);
@@ -1967,7 +1970,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
        q = bdev_get_queue(pd->bdev);
        if (write) {
                if ((ret = pkt_open_write(pd)))
-                       goto out_putdev;
+                       goto out_unclaim;
                /*
                 * Some CDRW drives can not handle writes larger than one packet,
                 * even if the size is a multiple of the packet size.
@@ -1982,13 +1985,15 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
        }
 
        if ((ret = pkt_set_segment_merging(pd, q)))
-               goto out_putdev;
+               goto out_unclaim;
 
        if (write)
                printk("pktcdvd: %lukB available on disc\n", lba << 1);
 
        return 0;
 
+out_unclaim:
+       bd_release(pd->bdev);
 out_putdev:
        blkdev_put(pd->bdev);
 out:
@@ -2007,6 +2012,7 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
        pkt_lock_door(pd, 0);
 
        pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
+       bd_release(pd->bdev);
        blkdev_put(pd->bdev);
 }
 
index 29d1518be72a16ba980e71eb829a671208e1fbdf..43415f69839f7d0946354d0c824390955e996cbb 100644 (file)
@@ -81,8 +81,7 @@ static void (*current_int_handler) (u_int) = NULL;
 static void ps2esdi_normal_interrupt_handler(u_int);
 static void ps2esdi_initial_reset_int_handler(u_int);
 static void ps2esdi_geometry_int_handler(u_int);
-static int ps2esdi_ioctl(struct inode *inode, struct file *file,
-                        u_int cmd, u_long arg);
+static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer);
 
@@ -132,7 +131,7 @@ static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
 static struct block_device_operations ps2esdi_fops =
 {
        .owner          = THIS_MODULE,
-       .ioctl          = ps2esdi_ioctl,
+       .getgeo         = ps2esdi_getgeo,
 };
 
 static struct gendisk *ps2esdi_gendisk[2];
@@ -1058,21 +1057,13 @@ static void dump_cmd_complete_status(u_int int_ret_code)
 
 }
 
-static int ps2esdi_ioctl(struct inode *inode,
-                        struct file *file, u_int cmd, u_long arg)
+static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct ps2esdi_i_struct *p = inode->i_bdev->bd_disk->private_data;
-       struct ps2esdi_geometry geom;
-
-       if (cmd != HDIO_GETGEO)
-               return -EINVAL;
-       memset(&geom, 0, sizeof(geom));
-       geom.heads = p->head;
-       geom.sectors = p->sect;
-       geom.cylinders = p->cyl;
-       geom.start = get_start_sect(inode->i_bdev);
-       if (copy_to_user((void __user *)arg, &geom, sizeof(geom)))
-               return -EFAULT;
+       struct ps2esdi_i_struct *p = bdev->bd_disk->private_data;
+
+       geo->heads = p->head;
+       geo->sectors = p->sect;
+       geo->cylinders = p->cyl;
        return 0;
 }
 
index af7cb2bfd67051d02b568fed8b24e3aea3e8e44b..01f042f6f1c42874e9090ce60f0e925d7b73726c 100644 (file)
@@ -1083,23 +1083,33 @@ static int swim3_add_device(struct device_node *swim)
 {
        struct device_node *mediabay;
        struct floppy_state *fs = &floppy_states[floppy_count];
+       struct resource res_reg, res_dma;
 
-       if (swim->n_addrs < 2)
-       {
-               printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
-                      swim->n_addrs, swim->n_intrs);
+       if (of_address_to_resource(swim, 0, &res_reg) ||
+           of_address_to_resource(swim, 1, &res_dma)) {
+               printk(KERN_ERR "swim3: Can't get addresses\n");
                return -EINVAL;
        }
-
-       if (swim->n_intrs < 2)
-       {
-               printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n",
-                      swim->n_addrs, swim->n_intrs);
+       if (request_mem_region(res_reg.start, res_reg.end - res_reg.start + 1,
+                              " (reg)") == NULL) {
+               printk(KERN_ERR "swim3: Can't request register space\n");
+               return -EINVAL;
+       }
+       if (request_mem_region(res_dma.start, res_dma.end - res_dma.start + 1,
+                              " (dma)") == NULL) {
+               release_mem_region(res_reg.start,
+                                  res_reg.end - res_reg.start + 1);
+               printk(KERN_ERR "swim3: Can't request DMA space\n");
                return -EINVAL;
        }
 
-       if (!request_OF_resource(swim, 0, NULL)) {
-               printk(KERN_INFO "swim3: can't request IO resource !\n");
+       if (swim->n_intrs < 2) {
+               printk(KERN_INFO "swim3: expecting 2 intrs (n_intrs:%d)\n",
+                      swim->n_intrs);
+               release_mem_region(res_reg.start,
+                                  res_reg.end - res_reg.start + 1);
+               release_mem_region(res_dma.start,
+                                  res_dma.end - res_dma.start + 1);
                return -EINVAL;
        }
 
@@ -1110,10 +1120,8 @@ static int swim3_add_device(struct device_node *swim)
        memset(fs, 0, sizeof(*fs));
        spin_lock_init(&fs->lock);
        fs->state = idle;
-       fs->swim3 = (struct swim3 __iomem *)
-               ioremap(swim->addrs[0].address, 0x200);
-       fs->dma = (struct dbdma_regs __iomem *)
-               ioremap(swim->addrs[1].address, 0x200);
+       fs->swim3 = (struct swim3 __iomem *)ioremap(res_reg.start, 0x200);
+       fs->dma = (struct dbdma_regs __iomem *)ioremap(res_dma.start, 0x200);
        fs->swim3_intr = swim->intrs[0].line;
        fs->dma_intr = swim->intrs[1].line;
        fs->cur_cyl = -1;
index 9251f4131b5307e548fe98863ae8eb9ca5c9cf04..c0cdc182a8b0b4fcd619ee97100d53ff4f4538db 100644 (file)
@@ -407,8 +407,7 @@ struct carm_array_info {
 
 static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static void carm_remove_one (struct pci_dev *pdev);
-static int carm_bdev_ioctl(struct inode *ino, struct file *fil,
-                          unsigned int cmd, unsigned long arg);
+static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static struct pci_device_id carm_pci_tbl[] = {
        { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
@@ -426,7 +425,7 @@ static struct pci_driver carm_driver = {
 
 static struct block_device_operations carm_bd_ops = {
        .owner          = THIS_MODULE,
-       .ioctl          = carm_bdev_ioctl,
+       .getgeo         = carm_bdev_getgeo,
 };
 
 static unsigned int carm_host_id;
@@ -434,32 +433,14 @@ static unsigned long carm_major_alloc;
 
 
 
-static int carm_bdev_ioctl(struct inode *ino, struct file *fil,
-                          unsigned int cmd, unsigned long arg)
+static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       void __user *usermem = (void __user *) arg;
-       struct carm_port *port = ino->i_bdev->bd_disk->private_data;
-       struct hd_geometry geom;
+       struct carm_port *port = bdev->bd_disk->private_data;
 
-       switch (cmd) {
-       case HDIO_GETGEO:
-               if (!usermem)
-                       return -EINVAL;
-
-               geom.heads = (u8) port->dev_geom_head;
-               geom.sectors = (u8) port->dev_geom_sect;
-               geom.cylinders = port->dev_geom_cyl;
-               geom.start = get_start_sect(ino->i_bdev);
-
-               if (copy_to_user(usermem, &geom, sizeof(geom)))
-                       return -EFAULT;
-               return 0;
-
-       default:
-               break;
-       }
-
-       return -EOPNOTSUPP;
+       geo->heads = (u8) port->dev_geom_head;
+       geo->sectors = (u8) port->dev_geom_sect;
+       geo->cylinders = port->dev_geom_cyl;
+       return 0;
 }
 
 static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE };
index 0f48301342da4e2e0a13a23bed85821e06efb79b..15299e7a1ade64a23bc6d7c11781bbc89c71f69a 100644 (file)
@@ -809,34 +809,23 @@ static int mm_revalidate(struct gendisk *disk)
        set_capacity(disk, card->mm_size << 1);
        return 0;
 }
-/*
------------------------------------------------------------------------------------
---                            mm_ioctl
------------------------------------------------------------------------------------
-*/
-static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
+
+static int mm_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       if (cmd == HDIO_GETGEO) {
-               struct cardinfo *card = i->i_bdev->bd_disk->private_data;
-               int size = card->mm_size * (1024 / MM_HARDSECT);
-               struct hd_geometry geo;
-               /*
-                * get geometry: we have to fake one...  trim the size to a
-                * multiple of 2048 (1M): tell we have 32 sectors, 64 heads,
-                * whatever cylinders.
-                */
-               geo.heads     = 64;
-               geo.sectors   = 32;
-               geo.start     = get_start_sect(i->i_bdev);
-               geo.cylinders = size / (geo.heads * geo.sectors);
-
-               if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
-                       return -EFAULT;
-               return 0;
-       }
+       struct cardinfo *card = bdev->bd_disk->private_data;
+       int size = card->mm_size * (1024 / MM_HARDSECT);
 
-       return -EINVAL;
+       /*
+        * get geometry: we have to fake one...  trim the size to a
+        * multiple of 2048 (1M): tell we have 32 sectors, 64 heads,
+        * whatever cylinders.
+        */
+       geo->heads     = 64;
+       geo->sectors   = 32;
+       geo->cylinders = size / (geo->heads * geo->sectors);
+       return 0;
 }
+
 /*
 -----------------------------------------------------------------------------------
 --                                mm_check_change
@@ -855,7 +844,7 @@ static int mm_check_change(struct gendisk *disk)
 */
 static struct block_device_operations mm_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = mm_ioctl,
+       .getgeo         = mm_getgeo,
        .revalidate_disk= mm_revalidate,
        .media_changed  = mm_check_change,
 };
index 063f0304a1630e20af9fbf0866bbcfb8c6c731fd..d1aaf31bd97e85e762c33e2aa50b65748c45f0af 100644 (file)
@@ -247,43 +247,17 @@ static int viodasd_release(struct inode *ino, struct file *fil)
 
 /* External ioctl entry point.
  */
-static int viodasd_ioctl(struct inode *ino, struct file *fil,
-                        unsigned int cmd, unsigned long arg)
+static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       unsigned char sectors;
-       unsigned char heads;
-       unsigned short cylinders;
-       struct hd_geometry *geo;
-       struct gendisk *gendisk;
-       struct viodasd_device *d;
+       struct gendisk *disk = bdev->bd_disk;
+       struct viodasd_device *d = disk->private_data;
 
-       switch (cmd) {
-       case HDIO_GETGEO:
-               geo = (struct hd_geometry *)arg;
-               if (geo == NULL)
-                       return -EINVAL;
-               if (!access_ok(VERIFY_WRITE, geo, sizeof(*geo)))
-                       return -EFAULT;
-               gendisk = ino->i_bdev->bd_disk;
-               d = gendisk->private_data;
-               sectors = d->sectors;
-               if (sectors == 0)
-                       sectors = 32;
-               heads = d->tracks;
-               if (heads == 0)
-                       heads = 64;
-               cylinders = d->cylinders;
-               if (cylinders == 0)
-                       cylinders = get_capacity(gendisk) / (sectors * heads);
-               if (__put_user(sectors, &geo->sectors) ||
-                   __put_user(heads, &geo->heads) ||
-                   __put_user(cylinders, &geo->cylinders) ||
-                   __put_user(get_start_sect(ino->i_bdev), &geo->start))
-                       return -EFAULT;
-               return 0;
-       }
+       geo->sectors = d->sectors ? d->sectors : 0;
+       geo->heads = d->tracks ? d->tracks  : 64;
+       geo->cylinders = d->cylinders ? d->cylinders :
+               get_capacity(disk) / (geo->cylinders * geo->heads);
 
-       return -EINVAL;
+       return 0;
 }
 
 /*
@@ -293,7 +267,7 @@ static struct block_device_operations viodasd_fops = {
        .owner = THIS_MODULE,
        .open = viodasd_open,
        .release = viodasd_release,
-       .ioctl = viodasd_ioctl,
+       .getgeo = viodasd_getgeo,
 };
 
 /*
index 68b6d7b154cf88057b138d72a58b74d93409c23f..cbce7c5e9445638474640e59738db7b7cec3b74b 100644 (file)
@@ -128,9 +128,12 @@ static DEFINE_SPINLOCK(xd_lock);
 
 static struct gendisk *xd_gendisk[2];
 
+static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
+
 static struct block_device_operations xd_fops = {
        .owner  = THIS_MODULE,
        .ioctl  = xd_ioctl,
+       .getgeo = xd_getgeo,
 };
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
 static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
@@ -276,11 +279,11 @@ static u_char __init xd_detect (u_char *controller, unsigned int *address)
                return(1);
        }
 
-       for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])); i++) {
+       for (i = 0; i < ARRAY_SIZE(xd_bases); i++) {
                void __iomem *p = ioremap(xd_bases[i], 0x2000);
                if (!p)
                        continue;
-               for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])); j++) {
+               for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) {
                        const char *s = xd_sigs[j].string;
                        if (check_signature(p + xd_sigs[j].offset, s, strlen(s))) {
                                *controller = j;
@@ -330,22 +333,20 @@ static void do_xd_request (request_queue_t * q)
        }
 }
 
+static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       XD_INFO *p = bdev->bd_disk->private_data;
+
+       geo->heads = p->heads;
+       geo->sectors = p->sectors;
+       geo->cylinders = p->cylinders;
+       return 0;
+}
+
 /* xd_ioctl: handle device ioctl's */
 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
 {
-       XD_INFO *p = inode->i_bdev->bd_disk->private_data;
-
        switch (cmd) {
-               case HDIO_GETGEO:
-               {
-                       struct hd_geometry g;
-                       struct hd_geometry __user *geom= (void __user *)arg;
-                       g.heads = p->heads;
-                       g.sectors = p->sectors;
-                       g.cylinders = p->cylinders;
-                       g.start = get_start_sect(inode->i_bdev);
-                       return copy_to_user(geom, &g, sizeof(g)) ? -EFAULT : 0;
-               }
                case HDIO_SET_DMA:
                        if (!capable(CAP_SYS_ADMIN)) return -EACCES;
                        if (xdc_busy) return -EBUSY;
@@ -1017,7 +1018,7 @@ static void __init do_xd_setup (int *integers)
                case 2: if ((integers[2] > 0) && (integers[2] < 16))
                                xd_irq = integers[2];
                case 1: xd_override = 1;
-                       if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0]))))
+                       if ((integers[1] >= 0) && (integers[1] < ARRAY_SIZE(xd_sigs)))
                                xd_type = integers[1];
                case 0: break;
                default:printk("xd: too many parameters for xd\n");
index 5ebd06b1b4ca9463e789346ec939d6b7041aec2a..dd7e6901c575b8d0d36dc22b17a820371ed95ec8 100644 (file)
@@ -220,6 +220,14 @@ config SYNCLINKMP
          The module will be called synclinkmp.  If you want to do that, say M
          here.
 
+config SYNCLINK_GT
+       tristate "SyncLink GT/AC support"
+       depends on SERIAL_NONSTANDARD
+       help
+         Support for SyncLink GT and SyncLink AC families of
+         synchronous and asynchronous serial adapters
+         manufactured by Microgate Systems, Ltd. (www.microgate.com)
+
 config N_HDLC
        tristate "HDLC line discipline support"
        depends on SERIAL_NONSTANDARD
@@ -687,7 +695,7 @@ config NVRAM
 
 config RTC
        tristate "Enhanced Real Time Clock Support"
-       depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI)
+       depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV
        ---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
@@ -735,7 +743,7 @@ config SGI_IP27_RTC
 
 config GEN_RTC
        tristate "Generic /dev/rtc emulation"
-       depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC
+       depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV
        ---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 4aeae687e88a20e8911781ad5747a6ebb69d1948..d973d14d8f7fc998ab88fee69365289f5264502e 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_RISCOM8)         += riscom8.o
 obj-$(CONFIG_ISI)              += isicom.o
 obj-$(CONFIG_SYNCLINK)         += synclink.o
 obj-$(CONFIG_SYNCLINKMP)       += synclinkmp.o
+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
index 3f8f7fa6b0ff0177d626a9be477cfade0fe70552..268f78d926d33726b1fc4305b1d162e69cc54fb7 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/agp_backend.h>
 #include "agp.h"
 
index 49769f59ea1b2fb79528a5e054f90bf28ea9499d..b3bc2e37e6160957786d7ecd69cf9d6c92bed250 100644 (file)
@@ -169,6 +169,7 @@ static struct pci_device_id rng_pci_tbl[] = {
 
        { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
        { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+       { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
        { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
        { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
        { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
index 91dd669273e0018aeeb95b02e18b4549e074a661..5b2d18035073311e0bf7b150d3cca0a75f7b48b7 100644 (file)
@@ -101,6 +101,11 @@ static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
 
        return 1;
 }
+
+static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t *size)
+{
+       return 1;
+}
 #endif
 
 /*
@@ -228,26 +233,36 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
        return written;
 }
 
+#ifndef __HAVE_PHYS_MEM_ACCESS_PROT
+static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+                                    unsigned long size, pgprot_t vma_prot)
+{
+#ifdef pgprot_noncached
+       unsigned long offset = pfn << PAGE_SHIFT;
+
+       if (uncached_access(file, offset))
+               return pgprot_noncached(vma_prot);
+#endif
+       return vma_prot;
+}
+#endif
+
 static int mmap_mem(struct file * file, struct vm_area_struct * vma)
 {
-#if defined(__HAVE_PHYS_MEM_ACCESS_PROT)
+       size_t size = vma->vm_end - vma->vm_start;
+
+       if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, &size))
+               return -EINVAL;
+
        vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
-                                                vma->vm_end - vma->vm_start,
+                                                size,
                                                 vma->vm_page_prot);
-#elif defined(pgprot_noncached)
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       int uncached;
-
-       uncached = uncached_access(file, offset);
-       if (uncached)
-               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#endif
 
        /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
        if (remap_pfn_range(vma,
                            vma->vm_start,
                            vma->vm_pgoff,
-                           vma->vm_end-vma->vm_start,
+                           size,
                            vma->vm_page_prot))
                return -EAGAIN;
        return 0;
@@ -817,7 +832,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
                          size_t count, loff_t *ppos)
 {
        char *tmp;
-       int ret;
+       ssize_t ret;
 
        tmp = kmalloc(count + 1, GFP_KERNEL);
        if (tmp == NULL)
@@ -826,6 +841,9 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
        if (!copy_from_user(tmp, buf, count)) {
                tmp[count] = 0;
                ret = printk("%s", tmp);
+               if (ret > count)
+                       /* printk can add a prefix */
+                       ret = count;
        }
        kfree(tmp);
        return ret;
index 51a07370e636ec85edb0e9b375c5ebe72758fa83..f8dd8527c6aa9d8e30d17a26b64ed5b5dcccb2f7 100644 (file)
@@ -471,7 +471,6 @@ struct sonypi_keypress {
 
 static struct sonypi_device {
        struct pci_dev *dev;
-       struct platform_device *pdev;
        u16 irq;
        u16 bits;
        u16 ioport1;
@@ -511,6 +510,11 @@ static struct sonypi_device {
 #define SONYPI_ACPI_ACTIVE 0
 #endif                         /* CONFIG_ACPI */
 
+#ifdef CONFIG_ACPI
+static struct acpi_device *sonypi_acpi_device;
+static int acpi_enabled;
+#endif
+
 static int sonypi_ec_write(u8 addr, u8 value)
 {
 #ifdef CONFIG_ACPI_EC
@@ -864,6 +868,11 @@ found:
        if (useinput)
                sonypi_report_input_event(event);
 
+#ifdef CONFIG_ACPI
+       if (acpi_enabled)
+               acpi_bus_generate_event(sonypi_acpi_device, 1, event);
+#endif
+
        kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
        kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
        wake_up_interruptible(&sonypi_device.fifo_proc_list);
@@ -1165,45 +1174,38 @@ static int sonypi_disable(void)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int old_camera_power;
-
-static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_ACPI
+static int sonypi_acpi_add(struct acpi_device *device)
 {
-       old_camera_power = sonypi_device.camera_power;
-       sonypi_disable();
-
+       sonypi_acpi_device = device;
+       strcpy(acpi_device_name(device), "Sony laptop hotkeys");
+       strcpy(acpi_device_class(device), "sony/hotkey");
        return 0;
 }
 
-static int sonypi_resume(struct platform_device *dev)
+static int sonypi_acpi_remove(struct acpi_device *device, int type)
 {
-       sonypi_enable(old_camera_power);
+       sonypi_acpi_device = NULL;
        return 0;
 }
-#endif
-
-static void sonypi_shutdown(struct platform_device *dev)
-{
-       sonypi_disable();
-}
 
-static struct platform_driver sonypi_driver = {
-#ifdef CONFIG_PM
-       .suspend        = sonypi_suspend,
-       .resume         = sonypi_resume,
-#endif
-       .shutdown       = sonypi_shutdown,
-       .driver         = {
-               .name   = "sonypi",
+static struct acpi_driver sonypi_acpi_driver = {
+       .name           = "sonypi",
+       .class          = "hkey",
+       .ids            = "SNY6001",
+       .ops            = {
+                          .add = sonypi_acpi_add,
+                          .remove = sonypi_acpi_remove,
        },
 };
+#endif
 
 static int __devinit sonypi_create_input_devices(void)
 {
        struct input_dev *jog_dev;
        struct input_dev *key_dev;
        int i;
+       int error;
 
        sonypi_device.input_jog_dev = jog_dev = input_allocate_device();
        if (!jog_dev)
@@ -1219,9 +1221,8 @@ static int __devinit sonypi_create_input_devices(void)
 
        sonypi_device.input_key_dev = key_dev = input_allocate_device();
        if (!key_dev) {
-               input_free_device(jog_dev);
-               sonypi_device.input_jog_dev = NULL;
-               return -ENOMEM;
+               error = -ENOMEM;
+               goto err_free_jogdev;
        }
 
        key_dev->name = "Sony Vaio Keys";
@@ -1234,56 +1235,122 @@ static int __devinit sonypi_create_input_devices(void)
                if (sonypi_inputkeys[i].inputev)
                        set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit);
 
-       input_register_device(jog_dev);
-       input_register_device(key_dev);
+       error = input_register_device(jog_dev);
+       if (error)
+               goto err_free_keydev;
+
+       error = input_register_device(key_dev);
+       if (error)
+               goto err_unregister_jogdev;
 
        return 0;
+
+ err_unregister_jogdev:
+       input_unregister_device(jog_dev);
+       /* Set to NULL so we don't free it again below */
+       jog_dev = NULL;
+ err_free_keydev:
+       input_free_device(key_dev);
+       sonypi_device.input_key_dev = NULL;
+ err_free_jogdev:
+       input_free_device(jog_dev);
+       sonypi_device.input_jog_dev = NULL;
+
+       return error;
 }
 
-static int __devinit sonypi_probe(void)
+static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
+                               const struct sonypi_ioport_list *ioport_list)
 {
-       int i, ret;
-       struct sonypi_ioport_list *ioport_list;
-       struct sonypi_irq_list *irq_list;
-       struct pci_dev *pcidev;
+       while (ioport_list->port1) {
 
-       if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                    PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
-               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
-       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                         PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
-               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
-       else
-               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
+               if (request_region(ioport_list->port1,
+                                  sonypi_device.region_size,
+                                  "Sony Programable I/O Device")) {
+                       dev->ioport1 = ioport_list->port1;
+                       dev->ioport2 = ioport_list->port2;
+                       return 0;
+               }
+               ioport_list++;
+       }
 
-       sonypi_device.dev = pcidev;
+       return -EBUSY;
+}
+
+static int __devinit sonypi_setup_irq(struct sonypi_device *dev,
+                                     const struct sonypi_irq_list *irq_list)
+{
+       while (irq_list->irq) {
+
+               if (!request_irq(irq_list->irq, sonypi_irq,
+                                SA_SHIRQ, "sonypi", sonypi_irq)) {
+                       dev->irq = irq_list->irq;
+                       dev->bits = irq_list->bits;
+                       return 0;
+               }
+               irq_list++;
+       }
+
+       return -EBUSY;
+}
+
+static void __devinit sonypi_display_info(void)
+{
+       printk(KERN_INFO "sonypi: detected type%d model, "
+              "verbose = %d, fnkeyinit = %s, camera = %s, "
+              "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
+              sonypi_device.model,
+              verbose,
+              fnkeyinit ? "on" : "off",
+              camera ? "on" : "off",
+              compat ? "on" : "off",
+              mask,
+              useinput ? "on" : "off",
+              SONYPI_ACPI_ACTIVE ? "on" : "off");
+       printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
+              sonypi_device.irq,
+              sonypi_device.ioport1, sonypi_device.ioport2);
+
+       if (minor == -1)
+               printk(KERN_INFO "sonypi: device allocated minor is %d\n",
+                      sonypi_misc_device.minor);
+}
+
+static int __devinit sonypi_probe(struct platform_device *dev)
+{
+       const struct sonypi_ioport_list *ioport_list;
+       const struct sonypi_irq_list *irq_list;
+       struct pci_dev *pcidev;
+       int error;
 
        spin_lock_init(&sonypi_device.fifo_lock);
        sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
                                         &sonypi_device.fifo_lock);
        if (IS_ERR(sonypi_device.fifo)) {
                printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
-               ret = PTR_ERR(sonypi_device.fifo);
-               goto out_fifo;
+               return PTR_ERR(sonypi_device.fifo);
        }
 
        init_waitqueue_head(&sonypi_device.fifo_proc_list);
        init_MUTEX(&sonypi_device.lock);
        sonypi_device.bluetooth_power = -1;
 
+       if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                    PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
+       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                         PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+       else
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
+
        if (pcidev && pci_enable_device(pcidev)) {
                printk(KERN_ERR "sonypi: pci_enable_device failed\n");
-               ret = -EIO;
-               goto out_pcienable;
-       }
-
-       if (minor != -1)
-               sonypi_misc_device.minor = minor;
-       if ((ret = misc_register(&sonypi_misc_device))) {
-               printk(KERN_ERR "sonypi: misc_register failed\n");
-               goto out_miscreg;
+               error = -EIO;
+               goto err_put_pcidev;
        }
 
+       sonypi_device.dev = pcidev;
 
        if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
                ioport_list = sonypi_type1_ioport_list;
@@ -1302,43 +1369,36 @@ static int __devinit sonypi_probe(void)
                irq_list = sonypi_type3_irq_list;
        }
 
-       for (i = 0; ioport_list[i].port1; i++) {
-               if (request_region(ioport_list[i].port1,
-                                  sonypi_device.region_size,
-                                  "Sony Programable I/O Device")) {
-                       /* get the ioport */
-                       sonypi_device.ioport1 = ioport_list[i].port1;
-                       sonypi_device.ioport2 = ioport_list[i].port2;
-                       break;
-               }
-       }
-       if (!sonypi_device.ioport1) {
-               printk(KERN_ERR "sonypi: request_region failed\n");
-               ret = -ENODEV;
-               goto out_reqreg;
+       error = sonypi_setup_ioports(&sonypi_device, ioport_list);
+       if (error) {
+               printk(KERN_ERR "sonypi: failed to request ioports\n");
+               goto err_disable_pcidev;
        }
 
-       for (i = 0; irq_list[i].irq; i++) {
-
-               sonypi_device.irq = irq_list[i].irq;
-               sonypi_device.bits = irq_list[i].bits;
-
-               if (!request_irq(sonypi_device.irq, sonypi_irq,
-                                SA_SHIRQ, "sonypi", sonypi_irq))
-                       break;
+       error = sonypi_setup_irq(&sonypi_device, irq_list);
+       if (error) {
+               printk(KERN_ERR "sonypi: request_irq failed\n");
+               goto err_free_ioports;
        }
 
-       if (!irq_list[i].irq) {
-               printk(KERN_ERR "sonypi: request_irq failed\n");
-               ret = -ENODEV;
-               goto out_reqirq;
+       if (minor != -1)
+               sonypi_misc_device.minor = minor;
+       error = misc_register(&sonypi_misc_device);
+       if (error) {
+               printk(KERN_ERR "sonypi: misc_register failed\n");
+               goto err_free_irq;
        }
 
+       sonypi_display_info();
+
        if (useinput) {
 
-               ret = sonypi_create_input_devices();
-               if (ret)
-                       goto out_inputdevices;
+               error = sonypi_create_input_devices();
+               if (error) {
+                       printk(KERN_ERR
+                               "sonypi: failed to create input devices\n");
+                       goto err_miscdev_unregister;
+               }
 
                spin_lock_init(&sonypi_device.input_fifo_lock);
                sonypi_device.input_fifo =
@@ -1346,91 +1406,104 @@ static int __devinit sonypi_probe(void)
                                    &sonypi_device.input_fifo_lock);
                if (IS_ERR(sonypi_device.input_fifo)) {
                        printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
-                       ret = PTR_ERR(sonypi_device.input_fifo);
-                       goto out_infifo;
+                       error = PTR_ERR(sonypi_device.input_fifo);
+                       goto err_inpdev_unregister;
                }
 
                INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL);
        }
 
-       sonypi_device.pdev = platform_device_register_simple("sonypi", -1,
-                                                            NULL, 0);
-       if (IS_ERR(sonypi_device.pdev)) {
-               ret = PTR_ERR(sonypi_device.pdev);
-               goto out_platformdev;
-       }
-
        sonypi_enable(0);
 
-       printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver"
-              "v%s.\n", SONYPI_DRIVER_VERSION);
-       printk(KERN_INFO "sonypi: detected type%d model, "
-              "verbose = %d, fnkeyinit = %s, camera = %s, "
-              "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
-              sonypi_device.model,
-              verbose,
-              fnkeyinit ? "on" : "off",
-              camera ? "on" : "off",
-              compat ? "on" : "off",
-              mask,
-              useinput ? "on" : "off",
-              SONYPI_ACPI_ACTIVE ? "on" : "off");
-       printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
-              sonypi_device.irq,
-              sonypi_device.ioport1, sonypi_device.ioport2);
-
-       if (minor == -1)
-               printk(KERN_INFO "sonypi: device allocated minor is %d\n",
-                      sonypi_misc_device.minor);
-
        return 0;
 
-out_platformdev:
-       kfifo_free(sonypi_device.input_fifo);
-out_infifo:
+ err_inpdev_unregister:
        input_unregister_device(sonypi_device.input_key_dev);
        input_unregister_device(sonypi_device.input_jog_dev);
-out_inputdevices:
+ err_miscdev_unregister:
+       misc_deregister(&sonypi_misc_device);
+ err_free_irq:
        free_irq(sonypi_device.irq, sonypi_irq);
-out_reqirq:
+ err_free_ioports:
        release_region(sonypi_device.ioport1, sonypi_device.region_size);
-out_reqreg:
-       misc_deregister(&sonypi_misc_device);
-out_miscreg:
+ err_disable_pcidev:
        if (pcidev)
                pci_disable_device(pcidev);
-out_pcienable:
+ err_put_pcidev:
+       pci_dev_put(pcidev);
        kfifo_free(sonypi_device.fifo);
-out_fifo:
-       pci_dev_put(sonypi_device.dev);
-       return ret;
+
+       return error;
 }
 
-static void __devexit sonypi_remove(void)
+static int __devexit sonypi_remove(struct platform_device *dev)
 {
        sonypi_disable();
 
        synchronize_sched();  /* Allow sonypi interrupt to complete. */
        flush_scheduled_work();
 
-       platform_device_unregister(sonypi_device.pdev);
-
        if (useinput) {
                input_unregister_device(sonypi_device.input_key_dev);
                input_unregister_device(sonypi_device.input_jog_dev);
                kfifo_free(sonypi_device.input_fifo);
        }
 
+       misc_deregister(&sonypi_misc_device);
+
        free_irq(sonypi_device.irq, sonypi_irq);
        release_region(sonypi_device.ioport1, sonypi_device.region_size);
-       misc_deregister(&sonypi_misc_device);
-       if (sonypi_device.dev)
+
+       if (sonypi_device.dev) {
                pci_disable_device(sonypi_device.dev);
+               pci_dev_put(sonypi_device.dev);
+       }
+
        kfifo_free(sonypi_device.fifo);
-       pci_dev_put(sonypi_device.dev);
-       printk(KERN_INFO "sonypi: removed.\n");
+
+       return 0;
 }
 
+#ifdef CONFIG_PM
+static int old_camera_power;
+
+static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
+{
+       old_camera_power = sonypi_device.camera_power;
+       sonypi_disable();
+
+       return 0;
+}
+
+static int sonypi_resume(struct platform_device *dev)
+{
+       sonypi_enable(old_camera_power);
+       return 0;
+}
+#else
+#define sonypi_suspend NULL
+#define sonypi_resume  NULL
+#endif
+
+static void sonypi_shutdown(struct platform_device *dev)
+{
+       sonypi_disable();
+}
+
+static struct platform_driver sonypi_driver = {
+       .driver         = {
+               .name   = "sonypi",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sonypi_probe,
+       .remove         = __devexit_p(sonypi_remove),
+       .shutdown       = sonypi_shutdown,
+       .suspend        = sonypi_suspend,
+       .resume         = sonypi_resume,
+};
+
+static struct platform_device *sonypi_platform_device;
+
 static struct dmi_system_id __initdata sonypi_dmi_table[] = {
        {
                .ident = "Sony Vaio",
@@ -1451,26 +1524,52 @@ static struct dmi_system_id __initdata sonypi_dmi_table[] = {
 
 static int __init sonypi_init(void)
 {
-       int ret;
+       int error;
+
+       printk(KERN_INFO
+               "sonypi: Sony Programmable I/O Controller Driver v%s.\n",
+               SONYPI_DRIVER_VERSION);
 
        if (!dmi_check_system(sonypi_dmi_table))
                return -ENODEV;
 
-       ret = platform_driver_register(&sonypi_driver);
-       if (ret)
-               return ret;
+       error = platform_driver_register(&sonypi_driver);
+       if (error)
+               return error;
 
-       ret = sonypi_probe();
-       if (ret)
-               platform_driver_unregister(&sonypi_driver);
+       sonypi_platform_device = platform_device_alloc("sonypi", -1);
+       if (!sonypi_platform_device) {
+               error = -ENOMEM;
+               goto err_driver_unregister;
+       }
 
-       return ret;
+       error = platform_device_add(sonypi_platform_device);
+       if (error)
+               goto err_free_device;
+
+#ifdef CONFIG_ACPI
+       if (acpi_bus_register_driver(&sonypi_acpi_driver) > 0)
+               acpi_enabled = 1;
+#endif
+
+       return 0;
+
+ err_free_device:
+       platform_device_put(sonypi_platform_device);
+ err_driver_unregister:
+       platform_driver_unregister(&sonypi_driver);
+       return error;
 }
 
 static void __exit sonypi_exit(void)
 {
+#ifdef CONFIG_ACPI
+       if (acpi_enabled)
+               acpi_bus_unregister_driver(&sonypi_acpi_driver);
+#endif
+       platform_device_unregister(sonypi_platform_device);
        platform_driver_unregister(&sonypi_driver);
-       sonypi_remove();
+       printk(KERN_INFO "sonypi: removed.\n");
 }
 
 module_init(sonypi_init);
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
new file mode 100644 (file)
index 0000000..2b9cde9
--- /dev/null
@@ -0,0 +1,4501 @@
+/*
+ * $Id: synclink_gt.c,v 4.20 2005/11/08 19:51:55 paulkf Exp $
+ *
+ * Device driver for Microgate SyncLink GT serial adapters.
+ *
+ * written by Paul Fulghum for Microgate Corporation
+ * paulkf@microgate.com
+ *
+ * Microgate and SyncLink are trademarks of Microgate Corporation
+ *
+ * This code is released under the GNU General Public License (GPL)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * DEBUG OUTPUT DEFINITIONS
+ *
+ * uncomment lines below to enable specific types of debug output
+ *
+ * DBGINFO   information - most verbose output
+ * DBGERR    serious errors
+ * DBGBH     bottom half service routine debugging
+ * DBGISR    interrupt service routine debugging
+ * DBGDATA   output receive and transmit data
+ * DBGTBUF   output transmit DMA buffers and registers
+ * DBGRBUF   output receive DMA buffers and registers
+ */
+
+#define DBGINFO(fmt) if (debug_level >= DEBUG_LEVEL_INFO) printk fmt
+#define DBGERR(fmt) if (debug_level >= DEBUG_LEVEL_ERROR) printk fmt
+#define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt
+#define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt
+#define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label))
+//#define DBGTBUF(info) dump_tbufs(info)
+//#define DBGRBUF(info) dump_rbufs(info)
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+#include <linux/termios.h>
+#include <linux/bitops.h>
+#include <linux/workqueue.h>
+#include <linux/hdlc.h>
+
+#include <asm/serial.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+
+#include "linux/synclink.h"
+
+#ifdef CONFIG_HDLC_MODULE
+#define CONFIG_HDLC 1
+#endif
+
+/*
+ * module identification
+ */
+static char *driver_name     = "SyncLink GT";
+static char *driver_version  = "$Revision: 4.20 $";
+static char *tty_driver_name = "synclink_gt";
+static char *tty_dev_prefix  = "ttySLG";
+MODULE_LICENSE("GPL");
+#define MGSL_MAGIC 0x5401
+#define MAX_DEVICES 12
+
+static struct pci_device_id pci_table[] = {
+       {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {0,}, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_table);
+
+static int  init_one(struct pci_dev *dev,const struct pci_device_id *ent);
+static void remove_one(struct pci_dev *dev);
+static struct pci_driver pci_driver = {
+       .name           = "synclink_gt",
+       .id_table       = pci_table,
+       .probe          = init_one,
+       .remove         = __devexit_p(remove_one),
+};
+
+static int pci_registered;
+
+/*
+ * module configuration and status
+ */
+static struct slgt_info *slgt_device_list;
+static int slgt_device_count;
+
+static int ttymajor;
+static int debug_level;
+static int maxframe[MAX_DEVICES];
+static int dosyncppp[MAX_DEVICES];
+
+module_param(ttymajor, int, 0);
+module_param(debug_level, int, 0);
+module_param_array(maxframe, int, NULL, 0);
+module_param_array(dosyncppp, int, NULL, 0);
+
+MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned");
+MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail");
+MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)");
+MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable");
+
+/*
+ * tty support and callbacks
+ */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+static struct tty_driver *serial_driver;
+
+static int  open(struct tty_struct *tty, struct file * filp);
+static void close(struct tty_struct *tty, struct file * filp);
+static void hangup(struct tty_struct *tty);
+static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+
+static int  write(struct tty_struct *tty, const unsigned char *buf, int count);
+static void put_char(struct tty_struct *tty, unsigned char ch);
+static void send_xchar(struct tty_struct *tty, char ch);
+static void wait_until_sent(struct tty_struct *tty, int timeout);
+static int  write_room(struct tty_struct *tty);
+static void flush_chars(struct tty_struct *tty);
+static void flush_buffer(struct tty_struct *tty);
+static void tx_hold(struct tty_struct *tty);
+static void tx_release(struct tty_struct *tty);
+
+static int  ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
+static int  read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
+static int  chars_in_buffer(struct tty_struct *tty);
+static void throttle(struct tty_struct * tty);
+static void unthrottle(struct tty_struct * tty);
+static void set_break(struct tty_struct *tty, int break_state);
+
+/*
+ * generic HDLC support and callbacks
+ */
+#ifdef CONFIG_HDLC
+#define dev_to_port(D) (dev_to_hdlc(D)->priv)
+static void hdlcdev_tx_done(struct slgt_info *info);
+static void hdlcdev_rx(struct slgt_info *info, char *buf, int size);
+static int  hdlcdev_init(struct slgt_info *info);
+static void hdlcdev_exit(struct slgt_info *info);
+#endif
+
+
+/*
+ * device specific structures, macros and functions
+ */
+
+#define SLGT_MAX_PORTS 4
+#define SLGT_REG_SIZE  256
+
+/*
+ * DMA buffer descriptor and access macros
+ */
+struct slgt_desc
+{
+       unsigned short count;
+       unsigned short status;
+       unsigned int pbuf;  /* physical address of data buffer */
+       unsigned int next;  /* physical address of next descriptor */
+
+       /* driver book keeping */
+       char *buf;          /* virtual  address of data buffer */
+       unsigned int pdesc; /* physical address of this descriptor */
+       dma_addr_t buf_dma_addr;
+};
+
+#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b))
+#define set_desc_next(a,b) (a).next   = cpu_to_le32((unsigned int)(b))
+#define set_desc_count(a,b)(a).count  = cpu_to_le16((unsigned short)(b))
+#define set_desc_eof(a,b)  (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))
+#define desc_count(a)      (le16_to_cpu((a).count))
+#define desc_status(a)     (le16_to_cpu((a).status))
+#define desc_complete(a)   (le16_to_cpu((a).status) & BIT15)
+#define desc_eof(a)        (le16_to_cpu((a).status) & BIT2)
+#define desc_crc_error(a)  (le16_to_cpu((a).status) & BIT1)
+#define desc_abort(a)      (le16_to_cpu((a).status) & BIT0)
+#define desc_residue(a)    ((le16_to_cpu((a).status) & 0x38) >> 3)
+
+struct _input_signal_events {
+       int ri_up;
+       int ri_down;
+       int dsr_up;
+       int dsr_down;
+       int dcd_up;
+       int dcd_down;
+       int cts_up;
+       int cts_down;
+};
+
+/*
+ * device instance data structure
+ */
+struct slgt_info {
+       void *if_ptr;           /* General purpose pointer (used by SPPP) */
+
+       struct slgt_info *next_device;  /* device list link */
+
+       int magic;
+       int flags;
+
+       char device_name[25];
+       struct pci_dev *pdev;
+
+       int port_count;  /* count of ports on adapter */
+       int adapter_num; /* adapter instance number */
+       int port_num;    /* port instance number */
+
+       /* array of pointers to port contexts on this adapter */
+       struct slgt_info *port_array[SLGT_MAX_PORTS];
+
+       int                     count;          /* count of opens */
+       int                     line;           /* tty line instance number */
+       unsigned short          close_delay;
+       unsigned short          closing_wait;   /* time to wait before closing */
+
+       struct mgsl_icount      icount;
+
+       struct tty_struct       *tty;
+       int                     timeout;
+       int                     x_char;         /* xon/xoff character */
+       int                     blocked_open;   /* # of blocked opens */
+       unsigned int            read_status_mask;
+       unsigned int            ignore_status_mask;
+
+       wait_queue_head_t       open_wait;
+       wait_queue_head_t       close_wait;
+
+       wait_queue_head_t       status_event_wait_q;
+       wait_queue_head_t       event_wait_q;
+       struct timer_list       tx_timer;
+       struct timer_list       rx_timer;
+
+       spinlock_t lock;        /* spinlock for synchronizing with ISR */
+
+       struct work_struct task;
+       u32 pending_bh;
+       int bh_requested;
+       int bh_running;
+
+       int isr_overflow;
+       int irq_requested;      /* nonzero if IRQ requested */
+       int irq_occurred;       /* for diagnostics use */
+
+       /* device configuration */
+
+       unsigned int bus_type;
+       unsigned int irq_level;
+       unsigned long irq_flags;
+
+       unsigned char __iomem * reg_addr;  /* memory mapped registers address */
+       u32 phys_reg_addr;
+       u32 reg_offset;
+       int reg_addr_requested;
+
+       MGSL_PARAMS params;       /* communications parameters */
+       u32 idle_mode;
+       u32 max_frame_size;       /* as set by device config */
+
+       unsigned int raw_rx_size;
+       unsigned int if_mode;
+
+       /* device status */
+
+       int rx_enabled;
+       int rx_restart;
+
+       int tx_enabled;
+       int tx_active;
+
+       unsigned char signals;    /* serial signal states */
+       unsigned int init_error;  /* initialization error */
+
+       unsigned char *tx_buf;
+       int tx_count;
+
+       char flag_buf[MAX_ASYNC_BUFFER_SIZE];
+       char char_buf[MAX_ASYNC_BUFFER_SIZE];
+       BOOLEAN drop_rts_on_tx_done;
+       struct  _input_signal_events    input_signal_events;
+
+       int dcd_chkcount;       /* check counts to prevent */
+       int cts_chkcount;       /* too many IRQs if a signal */
+       int dsr_chkcount;       /* is floating */
+       int ri_chkcount;
+
+       char *bufs;             /* virtual address of DMA buffer lists */
+       dma_addr_t bufs_dma_addr; /* physical address of buffer descriptors */
+
+       unsigned int rbuf_count;
+       struct slgt_desc *rbufs;
+       unsigned int rbuf_current;
+       unsigned int rbuf_index;
+
+       unsigned int tbuf_count;
+       struct slgt_desc *tbufs;
+       unsigned int tbuf_current;
+       unsigned int tbuf_start;
+
+       unsigned char *tmp_rbuf;
+       unsigned int tmp_rbuf_count;
+
+       /* SPPP/Cisco HDLC device parts */
+
+       int netcount;
+       int dosyncppp;
+       spinlock_t netlock;
+#ifdef CONFIG_HDLC
+       struct net_device *netdev;
+#endif
+
+};
+
+static MGSL_PARAMS default_params = {
+       .mode            = MGSL_MODE_HDLC,
+       .loopback        = 0,
+       .flags           = HDLC_FLAG_UNDERRUN_ABORT15,
+       .encoding        = HDLC_ENCODING_NRZI_SPACE,
+       .clock_speed     = 0,
+       .addr_filter     = 0xff,
+       .crc_type        = HDLC_CRC_16_CCITT,
+       .preamble_length = HDLC_PREAMBLE_LENGTH_8BITS,
+       .preamble        = HDLC_PREAMBLE_PATTERN_NONE,
+       .data_rate       = 9600,
+       .data_bits       = 8,
+       .stop_bits       = 1,
+       .parity          = ASYNC_PARITY_NONE
+};
+
+
+#define BH_RECEIVE  1
+#define BH_TRANSMIT 2
+#define BH_STATUS   4
+#define IO_PIN_SHUTDOWN_LIMIT 100
+
+#define DMABUFSIZE 256
+#define DESC_LIST_SIZE 4096
+
+#define MASK_PARITY  BIT1
+#define MASK_FRAMING BIT2
+#define MASK_BREAK   BIT3
+#define MASK_OVERRUN BIT4
+
+#define GSR   0x00 /* global status */
+#define TDR   0x80 /* tx data */
+#define RDR   0x80 /* rx data */
+#define TCR   0x82 /* tx control */
+#define TIR   0x84 /* tx idle */
+#define TPR   0x85 /* tx preamble */
+#define RCR   0x86 /* rx control */
+#define VCR   0x88 /* V.24 control */
+#define CCR   0x89 /* clock control */
+#define BDR   0x8a /* baud divisor */
+#define SCR   0x8c /* serial control */
+#define SSR   0x8e /* serial status */
+#define RDCSR 0x90 /* rx DMA control/status */
+#define TDCSR 0x94 /* tx DMA control/status */
+#define RDDAR 0x98 /* rx DMA descriptor address */
+#define TDDAR 0x9c /* tx DMA descriptor address */
+
+#define RXIDLE      BIT14
+#define RXBREAK     BIT14
+#define IRQ_TXDATA  BIT13
+#define IRQ_TXIDLE  BIT12
+#define IRQ_TXUNDER BIT11 /* HDLC */
+#define IRQ_RXDATA  BIT10
+#define IRQ_RXIDLE  BIT9  /* HDLC */
+#define IRQ_RXBREAK BIT9  /* async */
+#define IRQ_RXOVER  BIT8
+#define IRQ_DSR     BIT7
+#define IRQ_CTS     BIT6
+#define IRQ_DCD     BIT5
+#define IRQ_RI      BIT4
+#define IRQ_ALL     0x3ff0
+#define IRQ_MASTER  BIT0
+
+#define slgt_irq_on(info, mask) \
+       wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) | (mask)))
+#define slgt_irq_off(info, mask) \
+       wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) & ~(mask)))
+
+static __u8  rd_reg8(struct slgt_info *info, unsigned int addr);
+static void  wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value);
+static __u16 rd_reg16(struct slgt_info *info, unsigned int addr);
+static void  wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value);
+static __u32 rd_reg32(struct slgt_info *info, unsigned int addr);
+static void  wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value);
+
+static void  msc_set_vcr(struct slgt_info *info);
+
+static int  startup(struct slgt_info *info);
+static int  block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info);
+static void shutdown(struct slgt_info *info);
+static void program_hw(struct slgt_info *info);
+static void change_params(struct slgt_info *info);
+
+static int  register_test(struct slgt_info *info);
+static int  irq_test(struct slgt_info *info);
+static int  loopback_test(struct slgt_info *info);
+static int  adapter_test(struct slgt_info *info);
+
+static void reset_adapter(struct slgt_info *info);
+static void reset_port(struct slgt_info *info);
+static void async_mode(struct slgt_info *info);
+static void hdlc_mode(struct slgt_info *info);
+
+static void rx_stop(struct slgt_info *info);
+static void rx_start(struct slgt_info *info);
+static void reset_rbufs(struct slgt_info *info);
+static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last);
+static void rdma_reset(struct slgt_info *info);
+static int  rx_get_frame(struct slgt_info *info);
+static int  rx_get_buf(struct slgt_info *info);
+
+static void tx_start(struct slgt_info *info);
+static void tx_stop(struct slgt_info *info);
+static void tx_set_idle(struct slgt_info *info);
+static unsigned int free_tbuf_count(struct slgt_info *info);
+static void reset_tbufs(struct slgt_info *info);
+static void tdma_reset(struct slgt_info *info);
+static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
+
+static void get_signals(struct slgt_info *info);
+static void set_signals(struct slgt_info *info);
+static void enable_loopback(struct slgt_info *info);
+static void set_rate(struct slgt_info *info, u32 data_rate);
+
+static int  bh_action(struct slgt_info *info);
+static void bh_handler(void* context);
+static void bh_transmit(struct slgt_info *info);
+static void isr_serial(struct slgt_info *info);
+static void isr_rdma(struct slgt_info *info);
+static void isr_txeom(struct slgt_info *info, unsigned short status);
+static void isr_tdma(struct slgt_info *info);
+static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+
+static int  alloc_dma_bufs(struct slgt_info *info);
+static void free_dma_bufs(struct slgt_info *info);
+static int  alloc_desc(struct slgt_info *info);
+static void free_desc(struct slgt_info *info);
+static int  alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count);
+static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count);
+
+static int  alloc_tmp_rbuf(struct slgt_info *info);
+static void free_tmp_rbuf(struct slgt_info *info);
+
+static void tx_timeout(unsigned long context);
+static void rx_timeout(unsigned long context);
+
+/*
+ * ioctl handlers
+ */
+static int  get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount);
+static int  get_params(struct slgt_info *info, MGSL_PARAMS __user *params);
+static int  set_params(struct slgt_info *info, MGSL_PARAMS __user *params);
+static int  get_txidle(struct slgt_info *info, int __user *idle_mode);
+static int  set_txidle(struct slgt_info *info, int idle_mode);
+static int  tx_enable(struct slgt_info *info, int enable);
+static int  tx_abort(struct slgt_info *info);
+static int  rx_enable(struct slgt_info *info, int enable);
+static int  modem_input_wait(struct slgt_info *info,int arg);
+static int  wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr);
+static int  tiocmget(struct tty_struct *tty, struct file *file);
+static int  tiocmset(struct tty_struct *tty, struct file *file,
+                    unsigned int set, unsigned int clear);
+static void set_break(struct tty_struct *tty, int break_state);
+static int  get_interface(struct slgt_info *info, int __user *if_mode);
+static int  set_interface(struct slgt_info *info, int if_mode);
+
+/*
+ * driver functions
+ */
+static void add_device(struct slgt_info *info);
+static void device_init(int adapter_num, struct pci_dev *pdev);
+static int  claim_resources(struct slgt_info *info);
+static void release_resources(struct slgt_info *info);
+
+/*
+ * DEBUG OUTPUT CODE
+ */
+#ifndef DBGINFO
+#define DBGINFO(fmt)
+#endif
+#ifndef DBGERR
+#define DBGERR(fmt)
+#endif
+#ifndef DBGBH
+#define DBGBH(fmt)
+#endif
+#ifndef DBGISR
+#define DBGISR(fmt)
+#endif
+
+#ifdef DBGDATA
+static void trace_block(struct slgt_info *info, const char *data, int count, const char *label)
+{
+       int i;
+       int linecount;
+       printk("%s %s data:\n",info->device_name, label);
+       while(count) {
+               linecount = (count > 16) ? 16 : count;
+               for(i=0; i < linecount; i++)
+                       printk("%02X ",(unsigned char)data[i]);
+               for(;i<17;i++)
+                       printk("   ");
+               for(i=0;i<linecount;i++) {
+                       if (data[i]>=040 && data[i]<=0176)
+                               printk("%c",data[i]);
+                       else
+                               printk(".");
+               }
+               printk("\n");
+               data  += linecount;
+               count -= linecount;
+       }
+}
+#else
+#define DBGDATA(info, buf, size, label)
+#endif
+
+#ifdef DBGTBUF
+static void dump_tbufs(struct slgt_info *info)
+{
+       int i;
+       printk("tbuf_current=%d\n", info->tbuf_current);
+       for (i=0 ; i < info->tbuf_count ; i++) {
+               printk("%d: count=%04X status=%04X\n",
+                       i, le16_to_cpu(info->tbufs[i].count), le16_to_cpu(info->tbufs[i].status));
+       }
+}
+#else
+#define DBGTBUF(info)
+#endif
+
+#ifdef DBGRBUF
+static void dump_rbufs(struct slgt_info *info)
+{
+       int i;
+       printk("rbuf_current=%d\n", info->rbuf_current);
+       for (i=0 ; i < info->rbuf_count ; i++) {
+               printk("%d: count=%04X status=%04X\n",
+                       i, le16_to_cpu(info->rbufs[i].count), le16_to_cpu(info->rbufs[i].status));
+       }
+}
+#else
+#define DBGRBUF(info)
+#endif
+
+static inline int sanity_check(struct slgt_info *info, char *devname, const char *name)
+{
+#ifdef SANITY_CHECK
+       if (!info) {
+               printk("null struct slgt_info for (%s) in %s\n", devname, name);
+               return 1;
+       }
+       if (info->magic != MGSL_MAGIC) {
+               printk("bad magic number struct slgt_info (%s) in %s\n", devname, name);
+               return 1;
+       }
+#else
+       if (!info)
+               return 1;
+#endif
+       return 0;
+}
+
+/**
+ * line discipline callback wrappers
+ *
+ * The wrappers maintain line discipline references
+ * while calling into the line discipline.
+ *
+ * ldisc_receive_buf  - pass receive data to line discipline
+ */
+static void ldisc_receive_buf(struct tty_struct *tty,
+                             const __u8 *data, char *flags, int count)
+{
+       struct tty_ldisc *ld;
+       if (!tty)
+               return;
+       ld = tty_ldisc_ref(tty);
+       if (ld) {
+               if (ld->receive_buf)
+                       ld->receive_buf(tty, data, flags, count);
+               tty_ldisc_deref(ld);
+       }
+}
+
+/* tty callbacks */
+
+static int open(struct tty_struct *tty, struct file *filp)
+{
+       struct slgt_info *info;
+       int retval, line;
+       unsigned long flags;
+
+       line = tty->index;
+       if ((line < 0) || (line >= slgt_device_count)) {
+               DBGERR(("%s: open with invalid line #%d.\n", driver_name, line));
+               return -ENODEV;
+       }
+
+       info = slgt_device_list;
+       while(info && info->line != line)
+               info = info->next_device;
+       if (sanity_check(info, tty->name, "open"))
+               return -ENODEV;
+       if (info->init_error) {
+               DBGERR(("%s init error=%d\n", info->device_name, info->init_error));
+               return -ENODEV;
+       }
+
+       tty->driver_data = info;
+       info->tty = tty;
+
+       DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->count));
+
+       /* If port is closing, signal caller to try again */
+       if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+               retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+                       -EAGAIN : -ERESTARTSYS);
+               goto cleanup;
+       }
+
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+       spin_lock_irqsave(&info->netlock, flags);
+       if (info->netcount) {
+               retval = -EBUSY;
+               spin_unlock_irqrestore(&info->netlock, flags);
+               goto cleanup;
+       }
+       info->count++;
+       spin_unlock_irqrestore(&info->netlock, flags);
+
+       if (info->count == 1) {
+               /* 1st open on this device, init hardware */
+               retval = startup(info);
+               if (retval < 0)
+                       goto cleanup;
+       }
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+               DBGINFO(("%s block_til_ready rc=%d\n", info->device_name, retval));
+               goto cleanup;
+       }
+
+       retval = 0;
+
+cleanup:
+       if (retval) {
+               if (tty->count == 1)
+                       info->tty = NULL; /* tty layer will release tty struct */
+               if(info->count)
+                       info->count--;
+       }
+
+       DBGINFO(("%s open rc=%d\n", info->device_name, retval));
+       return retval;
+}
+
+static void close(struct tty_struct *tty, struct file *filp)
+{
+       struct slgt_info *info = tty->driver_data;
+
+       if (sanity_check(info, tty->name, "close"))
+               return;
+       DBGINFO(("%s close entry, count=%d\n", info->device_name, info->count));
+
+       if (!info->count)
+               return;
+
+       if (tty_hung_up_p(filp))
+               goto cleanup;
+
+       if ((tty->count == 1) && (info->count != 1)) {
+               /*
+                * tty->count is 1 and the tty structure will be freed.
+                * info->count should be one in this case.
+                * if it's not, correct it so that the port is shutdown.
+                */
+               DBGERR(("%s close: bad refcount; tty->count=1, "
+                      "info->count=%d\n", info->device_name, info->count));
+               info->count = 1;
+       }
+
+       info->count--;
+
+       /* if at least one open remaining, leave hardware active */
+       if (info->count)
+               goto cleanup;
+
+       info->flags |= ASYNC_CLOSING;
+
+       /* set tty->closing to notify line discipline to
+        * only process XON/XOFF characters. Only the N_TTY
+        * discipline appears to use this (ppp does not).
+        */
+       tty->closing = 1;
+
+       /* wait for transmit data to clear all layers */
+
+       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+               DBGINFO(("%s call tty_wait_until_sent\n", info->device_name));
+               tty_wait_until_sent(tty, info->closing_wait);
+       }
+
+       if (info->flags & ASYNC_INITIALIZED)
+               wait_until_sent(tty, info->timeout);
+       if (tty->driver->flush_buffer)
+               tty->driver->flush_buffer(tty);
+       tty_ldisc_flush(tty);
+
+       shutdown(info);
+
+       tty->closing = 0;
+       info->tty = NULL;
+
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+
+       wake_up_interruptible(&info->close_wait);
+
+cleanup:
+       DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->count));
+}
+
+static void hangup(struct tty_struct *tty)
+{
+       struct slgt_info *info = tty->driver_data;
+
+       if (sanity_check(info, tty->name, "hangup"))
+               return;
+       DBGINFO(("%s hangup\n", info->device_name));
+
+       flush_buffer(tty);
+       shutdown(info);
+
+       info->count = 0;
+       info->flags &= ~ASYNC_NORMAL_ACTIVE;
+       info->tty = NULL;
+
+       wake_up_interruptible(&info->open_wait);
+}
+
+static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       DBGINFO(("%s set_termios\n", tty->driver->name));
+
+       /* just return if nothing has changed */
+       if ((tty->termios->c_cflag == old_termios->c_cflag)
+           && (RELEVANT_IFLAG(tty->termios->c_iflag)
+               == RELEVANT_IFLAG(old_termios->c_iflag)))
+               return;
+
+       change_params(info);
+
+       /* Handle transition to B0 status */
+       if (old_termios->c_cflag & CBAUD &&
+           !(tty->termios->c_cflag & CBAUD)) {
+               info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+               spin_lock_irqsave(&info->lock,flags);
+               set_signals(info);
+               spin_unlock_irqrestore(&info->lock,flags);
+       }
+
+       /* Handle transition away from B0 status */
+       if (!(old_termios->c_cflag & CBAUD) &&
+           tty->termios->c_cflag & CBAUD) {
+               info->signals |= SerialSignal_DTR;
+               if (!(tty->termios->c_cflag & CRTSCTS) ||
+                   !test_bit(TTY_THROTTLED, &tty->flags)) {
+                       info->signals |= SerialSignal_RTS;
+               }
+               spin_lock_irqsave(&info->lock,flags);
+               set_signals(info);
+               spin_unlock_irqrestore(&info->lock,flags);
+       }
+
+       /* Handle turning off CRTSCTS */
+       if (old_termios->c_cflag & CRTSCTS &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               tx_release(tty);
+       }
+}
+
+static int write(struct tty_struct *tty,
+                const unsigned char *buf, int count)
+{
+       int ret = 0;
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "write"))
+               goto cleanup;
+       DBGINFO(("%s write count=%d\n", info->device_name, count));
+
+       if (!tty || !info->tx_buf)
+               goto cleanup;
+
+       if (count > info->max_frame_size) {
+               ret = -EIO;
+               goto cleanup;
+       }
+
+       if (!count)
+               goto cleanup;
+
+       if (info->params.mode == MGSL_MODE_RAW) {
+               unsigned int bufs_needed = (count/DMABUFSIZE);
+               unsigned int bufs_free = free_tbuf_count(info);
+               if (count % DMABUFSIZE)
+                       ++bufs_needed;
+               if (bufs_needed > bufs_free)
+                       goto cleanup;
+       } else {
+               if (info->tx_active)
+                       goto cleanup;
+               if (info->tx_count) {
+                       /* send accumulated data from send_char() calls */
+                       /* as frame and wait before accepting more data. */
+                       tx_load(info, info->tx_buf, info->tx_count);
+                       goto start;
+               }
+       }
+
+       ret = info->tx_count = count;
+       tx_load(info, buf, count);
+       goto start;
+
+start:
+       if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+               spin_lock_irqsave(&info->lock,flags);
+               if (!info->tx_active)
+                       tx_start(info);
+               spin_unlock_irqrestore(&info->lock,flags);
+       }
+
+cleanup:
+       DBGINFO(("%s write rc=%d\n", info->device_name, ret));
+       return ret;
+}
+
+static void put_char(struct tty_struct *tty, unsigned char ch)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "put_char"))
+               return;
+       DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
+       if (!tty || !info->tx_buf)
+               return;
+       spin_lock_irqsave(&info->lock,flags);
+       if (!info->tx_active && (info->tx_count < info->max_frame_size))
+               info->tx_buf[info->tx_count++] = ch;
+       spin_unlock_irqrestore(&info->lock,flags);
+}
+
+static void send_xchar(struct tty_struct *tty, char ch)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "send_xchar"))
+               return;
+       DBGINFO(("%s send_xchar(%d)\n", info->device_name, ch));
+       info->x_char = ch;
+       if (ch) {
+               spin_lock_irqsave(&info->lock,flags);
+               if (!info->tx_enabled)
+                       tx_start(info);
+               spin_unlock_irqrestore(&info->lock,flags);
+       }
+}
+
+static void wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long orig_jiffies, char_time;
+
+       if (!info )
+               return;
+       if (sanity_check(info, tty->name, "wait_until_sent"))
+               return;
+       DBGINFO(("%s wait_until_sent entry\n", info->device_name));
+       if (!(info->flags & ASYNC_INITIALIZED))
+               goto exit;
+
+       orig_jiffies = jiffies;
+
+       /* Set check interval to 1/5 of estimated time to
+        * send a character, and make it at least 1. The check
+        * interval should also be less than the timeout.
+        * Note: use tight timings here to satisfy the NIST-PCTS.
+        */
+
+       if (info->params.data_rate) {
+               char_time = info->timeout/(32 * 5);
+               if (!char_time)
+                       char_time++;
+       } else
+               char_time = 1;
+
+       if (timeout)
+               char_time = min_t(unsigned long, char_time, timeout);
+
+       while (info->tx_active) {
+               msleep_interruptible(jiffies_to_msecs(char_time));
+               if (signal_pending(current))
+                       break;
+               if (timeout && time_after(jiffies, orig_jiffies + timeout))
+                       break;
+       }
+
+exit:
+       DBGINFO(("%s wait_until_sent exit\n", info->device_name));
+}
+
+static int write_room(struct tty_struct *tty)
+{
+       struct slgt_info *info = tty->driver_data;
+       int ret;
+
+       if (sanity_check(info, tty->name, "write_room"))
+               return 0;
+       ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
+       DBGINFO(("%s write_room=%d\n", info->device_name, ret));
+       return ret;
+}
+
+static void flush_chars(struct tty_struct *tty)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "flush_chars"))
+               return;
+       DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count));
+
+       if (info->tx_count <= 0 || tty->stopped ||
+           tty->hw_stopped || !info->tx_buf)
+               return;
+
+       DBGINFO(("%s flush_chars start transmit\n", info->device_name));
+
+       spin_lock_irqsave(&info->lock,flags);
+       if (!info->tx_active && info->tx_count) {
+               tx_load(info, info->tx_buf,info->tx_count);
+               tx_start(info);
+       }
+       spin_unlock_irqrestore(&info->lock,flags);
+}
+
+static void flush_buffer(struct tty_struct *tty)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "flush_buffer"))
+               return;
+       DBGINFO(("%s flush_buffer\n", info->device_name));
+
+       spin_lock_irqsave(&info->lock,flags);
+       if (!info->tx_active)
+               info->tx_count = 0;
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
+}
+
+/*
+ * throttle (stop) transmitter
+ */
+static void tx_hold(struct tty_struct *tty)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "tx_hold"))
+               return;
+       DBGINFO(("%s tx_hold\n", info->device_name));
+       spin_lock_irqsave(&info->lock,flags);
+       if (info->tx_enabled && info->params.mode == MGSL_MODE_ASYNC)
+               tx_stop(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/*
+ * release (start) transmitter
+ */
+static void tx_release(struct tty_struct *tty)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "tx_release"))
+               return;
+       DBGINFO(("%s tx_release\n", info->device_name));
+       spin_lock_irqsave(&info->lock,flags);
+       if (!info->tx_active && info->tx_count) {
+               tx_load(info, info->tx_buf, info->tx_count);
+               tx_start(info);
+       }
+       spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/*
+ * Service an IOCTL request
+ *
+ * Arguments
+ *
+ *     tty     pointer to tty instance data
+ *     file    pointer to associated file object for device
+ *     cmd     IOCTL command code
+ *     arg     command argument/context
+ *
+ * Return 0 if success, otherwise error code
+ */
+static int ioctl(struct tty_struct *tty, struct file *file,
+                unsigned int cmd, unsigned long arg)
+{
+       struct slgt_info *info = tty->driver_data;
+       struct mgsl_icount cnow;        /* kernel counter temps */
+       struct serial_icounter_struct __user *p_cuser;  /* user space */
+       unsigned long flags;
+       void __user *argp = (void __user *)arg;
+
+       if (sanity_check(info, tty->name, "ioctl"))
+               return -ENODEV;
+       DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd));
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+
+       switch (cmd) {
+       case MGSL_IOCGPARAMS:
+               return get_params(info, argp);
+       case MGSL_IOCSPARAMS:
+               return set_params(info, argp);
+       case MGSL_IOCGTXIDLE:
+               return get_txidle(info, argp);
+       case MGSL_IOCSTXIDLE:
+               return set_txidle(info, (int)arg);
+       case MGSL_IOCTXENABLE:
+               return tx_enable(info, (int)arg);
+       case MGSL_IOCRXENABLE:
+               return rx_enable(info, (int)arg);
+       case MGSL_IOCTXABORT:
+               return tx_abort(info);
+       case MGSL_IOCGSTATS:
+               return get_stats(info, argp);
+       case MGSL_IOCWAITEVENT:
+               return wait_mgsl_event(info, argp);
+       case TIOCMIWAIT:
+               return modem_input_wait(info,(int)arg);
+       case MGSL_IOCGIF:
+               return get_interface(info, argp);
+       case MGSL_IOCSIF:
+               return set_interface(info,(int)arg);
+       case TIOCGICOUNT:
+               spin_lock_irqsave(&info->lock,flags);
+               cnow = info->icount;
+               spin_unlock_irqrestore(&info->lock,flags);
+               p_cuser = argp;
+               if (put_user(cnow.cts, &p_cuser->cts) ||
+                   put_user(cnow.dsr, &p_cuser->dsr) ||
+                   put_user(cnow.rng, &p_cuser->rng) ||
+                   put_user(cnow.dcd, &p_cuser->dcd) ||
+                   put_user(cnow.rx, &p_cuser->rx) ||
+                   put_user(cnow.tx, &p_cuser->tx) ||
+                   put_user(cnow.frame, &p_cuser->frame) ||
+                   put_user(cnow.overrun, &p_cuser->overrun) ||
+                   put_user(cnow.parity, &p_cuser->parity) ||
+                   put_user(cnow.brk, &p_cuser->brk) ||
+                   put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
+                       return -EFAULT;
+               return 0;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+/*
+ * proc fs support
+ */
+static inline int line_info(char *buf, struct slgt_info *info)
+{
+       char stat_buf[30];
+       int ret;
+       unsigned long flags;
+
+       ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n",
+                     info->device_name, info->phys_reg_addr,
+                     info->irq_level, info->max_frame_size);
+
+       /* output current serial signal states */
+       spin_lock_irqsave(&info->lock,flags);
+       get_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       stat_buf[0] = 0;
+       stat_buf[1] = 0;
+       if (info->signals & SerialSignal_RTS)
+               strcat(stat_buf, "|RTS");
+       if (info->signals & SerialSignal_CTS)
+               strcat(stat_buf, "|CTS");
+       if (info->signals & SerialSignal_DTR)
+               strcat(stat_buf, "|DTR");
+       if (info->signals & SerialSignal_DSR)
+               strcat(stat_buf, "|DSR");
+       if (info->signals & SerialSignal_DCD)
+               strcat(stat_buf, "|CD");
+       if (info->signals & SerialSignal_RI)
+               strcat(stat_buf, "|RI");
+
+       if (info->params.mode != MGSL_MODE_ASYNC) {
+               ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+                              info->icount.txok, info->icount.rxok);
+               if (info->icount.txunder)
+                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+               if (info->icount.txabort)
+                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+               if (info->icount.rxshort)
+                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+               if (info->icount.rxlong)
+                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+               if (info->icount.rxover)
+                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+               if (info->icount.rxcrc)
+                       ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+       } else {
+               ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+                              info->icount.tx, info->icount.rx);
+               if (info->icount.frame)
+                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+               if (info->icount.parity)
+                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+               if (info->icount.brk)
+                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+               if (info->icount.overrun)
+                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+       }
+
+       /* Append serial signal status to end */
+       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+
+       ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+                      info->tx_active,info->bh_requested,info->bh_running,
+                      info->pending_bh);
+
+       return ret;
+}
+
+/* Called to print information about devices
+ */
+static int read_proc(char *page, char **start, off_t off, int count,
+                    int *eof, void *data)
+{
+       int len = 0, l;
+       off_t   begin = 0;
+       struct slgt_info *info;
+
+       len += sprintf(page, "synclink_gt driver:%s\n", driver_version);
+
+       info = slgt_device_list;
+       while( info ) {
+               l = line_info(page + len, info);
+               len += l;
+               if (len+begin > off+count)
+                       goto done;
+               if (len+begin < off) {
+                       begin += len;
+                       len = 0;
+               }
+               info = info->next_device;
+       }
+
+       *eof = 1;
+done:
+       if (off >= len+begin)
+               return 0;
+       *start = page + (off-begin);
+       return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * return count of bytes in transmit buffer
+ */
+static int chars_in_buffer(struct tty_struct *tty)
+{
+       struct slgt_info *info = tty->driver_data;
+       if (sanity_check(info, tty->name, "chars_in_buffer"))
+               return 0;
+       DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count));
+       return info->tx_count;
+}
+
+/*
+ * signal remote device to throttle send data (our receive data)
+ */
+static void throttle(struct tty_struct * tty)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "throttle"))
+               return;
+       DBGINFO(("%s throttle\n", info->device_name));
+       if (I_IXOFF(tty))
+               send_xchar(tty, STOP_CHAR(tty));
+       if (tty->termios->c_cflag & CRTSCTS) {
+               spin_lock_irqsave(&info->lock,flags);
+               info->signals &= ~SerialSignal_RTS;
+               set_signals(info);
+               spin_unlock_irqrestore(&info->lock,flags);
+       }
+}
+
+/*
+ * signal remote device to stop throttling send data (our receive data)
+ */
+static void unthrottle(struct tty_struct * tty)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "unthrottle"))
+               return;
+       DBGINFO(("%s unthrottle\n", info->device_name));
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       send_xchar(tty, START_CHAR(tty));
+       }
+       if (tty->termios->c_cflag & CRTSCTS) {
+               spin_lock_irqsave(&info->lock,flags);
+               info->signals |= SerialSignal_RTS;
+               set_signals(info);
+               spin_unlock_irqrestore(&info->lock,flags);
+       }
+}
+
+/*
+ * set or clear transmit break condition
+ * break_state -1=set break condition, 0=clear
+ */
+static void set_break(struct tty_struct *tty, int break_state)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned short value;
+       unsigned long flags;
+
+       if (sanity_check(info, tty->name, "set_break"))
+               return;
+       DBGINFO(("%s set_break(%d)\n", info->device_name, break_state));
+
+       spin_lock_irqsave(&info->lock,flags);
+       value = rd_reg16(info, TCR);
+       if (break_state == -1)
+               value |= BIT6;
+       else
+               value &= ~BIT6;
+       wr_reg16(info, TCR, value);
+       spin_unlock_irqrestore(&info->lock,flags);
+}
+
+#ifdef CONFIG_HDLC
+
+/**
+ * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
+ * set encoding and frame check sequence (FCS) options
+ *
+ * dev       pointer to network device structure
+ * encoding  serial encoding setting
+ * parity    FCS setting
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
+                         unsigned short parity)
+{
+       struct slgt_info *info = dev_to_port(dev);
+       unsigned char  new_encoding;
+       unsigned short new_crctype;
+
+       /* return error if TTY interface open */
+       if (info->count)
+               return -EBUSY;
+
+       DBGINFO(("%s hdlcdev_attach\n", info->device_name));
+
+       switch (encoding)
+       {
+       case ENCODING_NRZ:        new_encoding = HDLC_ENCODING_NRZ; break;
+       case ENCODING_NRZI:       new_encoding = HDLC_ENCODING_NRZI_SPACE; break;
+       case ENCODING_FM_MARK:    new_encoding = HDLC_ENCODING_BIPHASE_MARK; break;
+       case ENCODING_FM_SPACE:   new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break;
+       case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break;
+       default: return -EINVAL;
+       }
+
+       switch (parity)
+       {
+       case PARITY_NONE:            new_crctype = HDLC_CRC_NONE; break;
+       case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break;
+       case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break;
+       default: return -EINVAL;
+       }
+
+       info->params.encoding = new_encoding;
+       info->params.crc_type = new_crctype;;
+
+       /* if network interface up, reprogram hardware */
+       if (info->netcount)
+               program_hw(info);
+
+       return 0;
+}
+
+/**
+ * called by generic HDLC layer to send frame
+ *
+ * skb  socket buffer containing HDLC frame
+ * dev  pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct slgt_info *info = dev_to_port(dev);
+       struct net_device_stats *stats = hdlc_stats(dev);
+       unsigned long flags;
+
+       DBGINFO(("%s hdlc_xmit\n", dev->name));
+
+       /* stop sending until this frame completes */
+       netif_stop_queue(dev);
+
+       /* copy data to device buffers */
+       info->tx_count = skb->len;
+       tx_load(info, skb->data, skb->len);
+
+       /* update network statistics */
+       stats->tx_packets++;
+       stats->tx_bytes += skb->len;
+
+       /* done with socket buffer, so free it */
+       dev_kfree_skb(skb);
+
+       /* save start time for transmit timeout detection */
+       dev->trans_start = jiffies;
+
+       /* start hardware transmitter if necessary */
+       spin_lock_irqsave(&info->lock,flags);
+       if (!info->tx_active)
+               tx_start(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       return 0;
+}
+
+/**
+ * called by network layer when interface enabled
+ * claim resources and initialize hardware
+ *
+ * dev  pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_open(struct net_device *dev)
+{
+       struct slgt_info *info = dev_to_port(dev);
+       int rc;
+       unsigned long flags;
+
+       DBGINFO(("%s hdlcdev_open\n", dev->name));
+
+       /* generic HDLC layer open processing */
+       if ((rc = hdlc_open(dev)))
+               return rc;
+
+       /* arbitrate between network and tty opens */
+       spin_lock_irqsave(&info->netlock, flags);
+       if (info->count != 0 || info->netcount != 0) {
+               DBGINFO(("%s hdlc_open busy\n", dev->name));
+               spin_unlock_irqrestore(&info->netlock, flags);
+               return -EBUSY;
+       }
+       info->netcount=1;
+       spin_unlock_irqrestore(&info->netlock, flags);
+
+       /* claim resources and init adapter */
+       if ((rc = startup(info)) != 0) {
+               spin_lock_irqsave(&info->netlock, flags);
+               info->netcount=0;
+               spin_unlock_irqrestore(&info->netlock, flags);
+               return rc;
+       }
+
+       /* assert DTR and RTS, apply hardware settings */
+       info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+       program_hw(info);
+
+       /* enable network layer transmit */
+       dev->trans_start = jiffies;
+       netif_start_queue(dev);
+
+       /* inform generic HDLC layer of current DCD status */
+       spin_lock_irqsave(&info->lock, flags);
+       get_signals(info);
+       spin_unlock_irqrestore(&info->lock, flags);
+       hdlc_set_carrier(info->signals & SerialSignal_DCD, dev);
+
+       return 0;
+}
+
+/**
+ * called by network layer when interface is disabled
+ * shutdown hardware and release resources
+ *
+ * dev  pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_close(struct net_device *dev)
+{
+       struct slgt_info *info = dev_to_port(dev);
+       unsigned long flags;
+
+       DBGINFO(("%s hdlcdev_close\n", dev->name));
+
+       netif_stop_queue(dev);
+
+       /* shutdown adapter and release resources */
+       shutdown(info);
+
+       hdlc_close(dev);
+
+       spin_lock_irqsave(&info->netlock, flags);
+       info->netcount=0;
+       spin_unlock_irqrestore(&info->netlock, flags);
+
+       return 0;
+}
+
+/**
+ * called by network layer to process IOCTL call to network device
+ *
+ * dev  pointer to network device structure
+ * ifr  pointer to network interface request structure
+ * cmd  IOCTL command code
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       const size_t size = sizeof(sync_serial_settings);
+       sync_serial_settings new_line;
+       sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+       struct slgt_info *info = dev_to_port(dev);
+       unsigned int flags;
+
+       DBGINFO(("%s hdlcdev_ioctl\n", dev->name));
+
+       /* return error if TTY interface open */
+       if (info->count)
+               return -EBUSY;
+
+       if (cmd != SIOCWANDEV)
+               return hdlc_ioctl(dev, ifr, cmd);
+
+       switch(ifr->ifr_settings.type) {
+       case IF_GET_IFACE: /* return current sync_serial_settings */
+
+               ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+               if (ifr->ifr_settings.size < size) {
+                       ifr->ifr_settings.size = size; /* data size wanted */
+                       return -ENOBUFS;
+               }
+
+               flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+                                             HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
+                                             HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+                                             HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN);
+
+               switch (flags){
+               case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
+               case (HDLC_FLAG_RXC_BRG    | HDLC_FLAG_TXC_BRG):    new_line.clock_type = CLOCK_INT; break;
+               case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG):    new_line.clock_type = CLOCK_TXINT; break;
+               case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break;
+               default: new_line.clock_type = CLOCK_DEFAULT;
+               }
+
+               new_line.clock_rate = info->params.clock_speed;
+               new_line.loopback   = info->params.loopback ? 1:0;
+
+               if (copy_to_user(line, &new_line, size))
+                       return -EFAULT;
+               return 0;
+
+       case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */
+
+               if(!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (copy_from_user(&new_line, line, size))
+                       return -EFAULT;
+
+               switch (new_line.clock_type)
+               {
+               case CLOCK_EXT:      flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break;
+               case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break;
+               case CLOCK_INT:      flags = HDLC_FLAG_RXC_BRG    | HDLC_FLAG_TXC_BRG;    break;
+               case CLOCK_TXINT:    flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG;    break;
+               case CLOCK_DEFAULT:  flags = info->params.flags &
+                                            (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+                                             HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
+                                             HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+                                             HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN); break;
+               default: return -EINVAL;
+               }
+
+               if (new_line.loopback != 0 && new_line.loopback != 1)
+                       return -EINVAL;
+
+               info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+                                       HDLC_FLAG_RXC_BRG    | HDLC_FLAG_RXC_TXCPIN |
+                                       HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+                                       HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN);
+               info->params.flags |= flags;
+
+               info->params.loopback = new_line.loopback;
+
+               if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG))
+                       info->params.clock_speed = new_line.clock_rate;
+               else
+                       info->params.clock_speed = 0;
+
+               /* if network interface up, reprogram hardware */
+               if (info->netcount)
+                       program_hw(info);
+               return 0;
+
+       default:
+               return hdlc_ioctl(dev, ifr, cmd);
+       }
+}
+
+/**
+ * called by network layer when transmit timeout is detected
+ *
+ * dev  pointer to network device structure
+ */
+static void hdlcdev_tx_timeout(struct net_device *dev)
+{
+       struct slgt_info *info = dev_to_port(dev);
+       struct net_device_stats *stats = hdlc_stats(dev);
+       unsigned long flags;
+
+       DBGINFO(("%s hdlcdev_tx_timeout\n", dev->name));
+
+       stats->tx_errors++;
+       stats->tx_aborted_errors++;
+
+       spin_lock_irqsave(&info->lock,flags);
+       tx_stop(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       netif_wake_queue(dev);
+}
+
+/**
+ * called by device driver when transmit completes
+ * reenable network layer transmit if stopped
+ *
+ * info  pointer to device instance information
+ */
+static void hdlcdev_tx_done(struct slgt_info *info)
+{
+       if (netif_queue_stopped(info->netdev))
+               netif_wake_queue(info->netdev);
+}
+
+/**
+ * called by device driver when frame received
+ * pass frame to network layer
+ *
+ * info  pointer to device instance information
+ * buf   pointer to buffer contianing frame data
+ * size  count of data bytes in buf
+ */
+static void hdlcdev_rx(struct slgt_info *info, char *buf, int size)
+{
+       struct sk_buff *skb = dev_alloc_skb(size);
+       struct net_device *dev = info->netdev;
+       struct net_device_stats *stats = hdlc_stats(dev);
+
+       DBGINFO(("%s hdlcdev_rx\n", dev->name));
+
+       if (skb == NULL) {
+               DBGERR(("%s: can't alloc skb, drop packet\n", dev->name));
+               stats->rx_dropped++;
+               return;
+       }
+
+       memcpy(skb_put(skb, size),buf,size);
+
+       skb->protocol = hdlc_type_trans(skb, info->netdev);
+
+       stats->rx_packets++;
+       stats->rx_bytes += size;
+
+       netif_rx(skb);
+
+       info->netdev->last_rx = jiffies;
+}
+
+/**
+ * called by device driver when adding device instance
+ * do generic HDLC initialization
+ *
+ * info  pointer to device instance information
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_init(struct slgt_info *info)
+{
+       int rc;
+       struct net_device *dev;
+       hdlc_device *hdlc;
+
+       /* allocate and initialize network and HDLC layer objects */
+
+       if (!(dev = alloc_hdlcdev(info))) {
+               printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name);
+               return -ENOMEM;
+       }
+
+       /* for network layer reporting purposes only */
+       dev->mem_start = info->phys_reg_addr;
+       dev->mem_end   = info->phys_reg_addr + SLGT_REG_SIZE - 1;
+       dev->irq       = info->irq_level;
+
+       /* network layer callbacks and settings */
+       dev->do_ioctl       = hdlcdev_ioctl;
+       dev->open           = hdlcdev_open;
+       dev->stop           = hdlcdev_close;
+       dev->tx_timeout     = hdlcdev_tx_timeout;
+       dev->watchdog_timeo = 10*HZ;
+       dev->tx_queue_len   = 50;
+
+       /* generic HDLC layer callbacks and settings */
+       hdlc         = dev_to_hdlc(dev);
+       hdlc->attach = hdlcdev_attach;
+       hdlc->xmit   = hdlcdev_xmit;
+
+       /* register objects with HDLC layer */
+       if ((rc = register_hdlc_device(dev))) {
+               printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
+               free_netdev(dev);
+               return rc;
+       }
+
+       info->netdev = dev;
+       return 0;
+}
+
+/**
+ * called by device driver when removing device instance
+ * do generic HDLC cleanup
+ *
+ * info  pointer to device instance information
+ */
+static void hdlcdev_exit(struct slgt_info *info)
+{
+       unregister_hdlc_device(info->netdev);
+       free_netdev(info->netdev);
+       info->netdev = NULL;
+}
+
+#endif /* ifdef CONFIG_HDLC */
+
+/*
+ * get async data from rx DMA buffers
+ */
+static void rx_async(struct slgt_info *info)
+{
+       struct tty_struct *tty = info->tty;
+       struct mgsl_icount *icount = &info->icount;
+       unsigned int start, end;
+       unsigned char *p;
+       unsigned char status;
+       struct slgt_desc *bufs = info->rbufs;
+       int i, count;
+
+       start = end = info->rbuf_current;
+
+       while(desc_complete(bufs[end])) {
+               count = desc_count(bufs[end]) - info->rbuf_index;
+               p     = bufs[end].buf + info->rbuf_index;
+
+               DBGISR(("%s rx_async count=%d\n", info->device_name, count));
+               DBGDATA(info, p, count, "rx");
+
+               for(i=0 ; i < count; i+=2, p+=2) {
+                       if (tty) {
+                               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                                       tty_flip_buffer_push(tty);
+                               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                                       break;
+                               *tty->flip.char_buf_ptr = *p;
+                               *tty->flip.flag_buf_ptr = 0;
+                       }
+                       icount->rx++;
+
+                       if ((status = *(p+1) & (BIT9 + BIT8))) {
+                               if (status & BIT9)
+                                       icount->parity++;
+                               else if (status & BIT8)
+                                       icount->frame++;
+                               /* discard char if tty control flags say so */
+                               if (status & info->ignore_status_mask)
+                                       continue;
+                               if (tty) {
+                                       if (status & BIT9)
+                                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                                       else if (status & BIT8)
+                                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               }
+                       }
+                       if (tty) {
+                               tty->flip.flag_buf_ptr++;
+                               tty->flip.char_buf_ptr++;
+                               tty->flip.count++;
+                       }
+               }
+
+               if (i < count) {
+                       /* receive buffer not completed */
+                       info->rbuf_index += i;
+                       info->rx_timer.expires = jiffies + 1;
+                       add_timer(&info->rx_timer);
+                       break;
+               }
+
+               info->rbuf_index = 0;
+               free_rbufs(info, end, end);
+
+               if (++end == info->rbuf_count)
+                       end = 0;
+
+               /* if entire list searched then no frame available */
+               if (end == start)
+                       break;
+       }
+
+       if (tty && tty->flip.count)
+               tty_flip_buffer_push(tty);
+}
+
+/*
+ * return next bottom half action to perform
+ */
+static int bh_action(struct slgt_info *info)
+{
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&info->lock,flags);
+
+       if (info->pending_bh & BH_RECEIVE) {
+               info->pending_bh &= ~BH_RECEIVE;
+               rc = BH_RECEIVE;
+       } else if (info->pending_bh & BH_TRANSMIT) {
+               info->pending_bh &= ~BH_TRANSMIT;
+               rc = BH_TRANSMIT;
+       } else if (info->pending_bh & BH_STATUS) {
+               info->pending_bh &= ~BH_STATUS;
+               rc = BH_STATUS;
+       } else {
+               /* Mark BH routine as complete */
+               info->bh_running   = 0;
+               info->bh_requested = 0;
+               rc = 0;
+       }
+
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       return rc;
+}
+
+/*
+ * perform bottom half processing
+ */
+static void bh_handler(void* context)
+{
+       struct slgt_info *info = context;
+       int action;
+
+       if (!info)
+               return;
+       info->bh_running = 1;
+
+       while((action = bh_action(info))) {
+               switch (action) {
+               case BH_RECEIVE:
+                       DBGBH(("%s bh receive\n", info->device_name));
+                       switch(info->params.mode) {
+                       case MGSL_MODE_ASYNC:
+                               rx_async(info);
+                               break;
+                       case MGSL_MODE_HDLC:
+                               while(rx_get_frame(info));
+                               break;
+                       case MGSL_MODE_RAW:
+                               while(rx_get_buf(info));
+                               break;
+                       }
+                       /* restart receiver if rx DMA buffers exhausted */
+                       if (info->rx_restart)
+                               rx_start(info);
+                       break;
+               case BH_TRANSMIT:
+                       bh_transmit(info);
+                       break;
+               case BH_STATUS:
+                       DBGBH(("%s bh status\n", info->device_name));
+                       info->ri_chkcount = 0;
+                       info->dsr_chkcount = 0;
+                       info->dcd_chkcount = 0;
+                       info->cts_chkcount = 0;
+                       break;
+               default:
+                       DBGBH(("%s unknown action\n", info->device_name));
+                       break;
+               }
+       }
+       DBGBH(("%s bh_handler exit\n", info->device_name));
+}
+
+static void bh_transmit(struct slgt_info *info)
+{
+       struct tty_struct *tty = info->tty;
+
+       DBGBH(("%s bh_transmit\n", info->device_name));
+       if (tty) {
+               tty_wakeup(tty);
+               wake_up_interruptible(&tty->write_wait);
+       }
+}
+
+static void dsr_change(struct slgt_info *info)
+{
+       get_signals(info);
+       DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));
+       if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
+               slgt_irq_off(info, IRQ_DSR);
+               return;
+       }
+       info->icount.dsr++;
+       if (info->signals & SerialSignal_DSR)
+               info->input_signal_events.dsr_up++;
+       else
+               info->input_signal_events.dsr_down++;
+       wake_up_interruptible(&info->status_event_wait_q);
+       wake_up_interruptible(&info->event_wait_q);
+       info->pending_bh |= BH_STATUS;
+}
+
+static void cts_change(struct slgt_info *info)
+{
+       get_signals(info);
+       DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));
+       if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
+               slgt_irq_off(info, IRQ_CTS);
+               return;
+       }
+       info->icount.cts++;
+       if (info->signals & SerialSignal_CTS)
+               info->input_signal_events.cts_up++;
+       else
+               info->input_signal_events.cts_down++;
+       wake_up_interruptible(&info->status_event_wait_q);
+       wake_up_interruptible(&info->event_wait_q);
+       info->pending_bh |= BH_STATUS;
+
+       if (info->flags & ASYNC_CTS_FLOW) {
+               if (info->tty) {
+                       if (info->tty->hw_stopped) {
+                               if (info->signals & SerialSignal_CTS) {
+                                       info->tty->hw_stopped = 0;
+                                       info->pending_bh |= BH_TRANSMIT;
+                                       return;
+                               }
+                       } else {
+                               if (!(info->signals & SerialSignal_CTS))
+                                       info->tty->hw_stopped = 1;
+                       }
+               }
+       }
+}
+
+static void dcd_change(struct slgt_info *info)
+{
+       get_signals(info);
+       DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));
+       if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
+               slgt_irq_off(info, IRQ_DCD);
+               return;
+       }
+       info->icount.dcd++;
+       if (info->signals & SerialSignal_DCD) {
+               info->input_signal_events.dcd_up++;
+       } else {
+               info->input_signal_events.dcd_down++;
+       }
+#ifdef CONFIG_HDLC
+       if (info->netcount)
+               hdlc_set_carrier(info->signals & SerialSignal_DCD, info->netdev);
+#endif
+       wake_up_interruptible(&info->status_event_wait_q);
+       wake_up_interruptible(&info->event_wait_q);
+       info->pending_bh |= BH_STATUS;
+
+       if (info->flags & ASYNC_CHECK_CD) {
+               if (info->signals & SerialSignal_DCD)
+                       wake_up_interruptible(&info->open_wait);
+               else {
+                       if (info->tty)
+                               tty_hangup(info->tty);
+               }
+       }
+}
+
+static void ri_change(struct slgt_info *info)
+{
+       get_signals(info);
+       DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));
+       if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
+               slgt_irq_off(info, IRQ_RI);
+               return;
+       }
+       info->icount.dcd++;
+       if (info->signals & SerialSignal_RI) {
+               info->input_signal_events.ri_up++;
+       } else {
+               info->input_signal_events.ri_down++;
+       }
+       wake_up_interruptible(&info->status_event_wait_q);
+       wake_up_interruptible(&info->event_wait_q);
+       info->pending_bh |= BH_STATUS;
+}
+
+static void isr_serial(struct slgt_info *info)
+{
+       unsigned short status = rd_reg16(info, SSR);
+
+       DBGISR(("%s isr_serial status=%04X\n", info->device_name, status));
+
+       wr_reg16(info, SSR, status); /* clear pending */
+
+       info->irq_occurred = 1;
+
+       if (info->params.mode == MGSL_MODE_ASYNC) {
+               if (status & IRQ_TXIDLE) {
+                       if (info->tx_count)
+                               isr_txeom(info, status);
+               }
+               if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
+                       info->icount.brk++;
+                       /* process break detection if tty control allows */
+                       if (info->tty) {
+                               if (!(status & info->ignore_status_mask)) {
+                                       if (info->read_status_mask & MASK_BREAK) {
+                                               *info->tty->flip.flag_buf_ptr = TTY_BREAK;
+                                               if (info->flags & ASYNC_SAK)
+                                                       do_SAK(info->tty);
+                                       }
+                               }
+                       }
+               }
+       } else {
+               if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
+                       isr_txeom(info, status);
+
+               if (status & IRQ_RXIDLE) {
+                       if (status & RXIDLE)
+                               info->icount.rxidle++;
+                       else
+                               info->icount.exithunt++;
+                       wake_up_interruptible(&info->event_wait_q);
+               }
+
+               if (status & IRQ_RXOVER)
+                       rx_start(info);
+       }
+
+       if (status & IRQ_DSR)
+               dsr_change(info);
+       if (status & IRQ_CTS)
+               cts_change(info);
+       if (status & IRQ_DCD)
+               dcd_change(info);
+       if (status & IRQ_RI)
+               ri_change(info);
+}
+
+static void isr_rdma(struct slgt_info *info)
+{
+       unsigned int status = rd_reg32(info, RDCSR);
+
+       DBGISR(("%s isr_rdma status=%08x\n", info->device_name, status));
+
+       /* RDCSR (rx DMA control/status)
+        *
+        * 31..07  reserved
+        * 06      save status byte to DMA buffer
+        * 05      error
+        * 04      eol (end of list)
+        * 03      eob (end of buffer)
+        * 02      IRQ enable
+        * 01      reset
+        * 00      enable
+        */
+       wr_reg32(info, RDCSR, status);  /* clear pending */
+
+       if (status & (BIT5 + BIT4)) {
+               DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name));
+               info->rx_restart = 1;
+       }
+       info->pending_bh |= BH_RECEIVE;
+}
+
+static void isr_tdma(struct slgt_info *info)
+{
+       unsigned int status = rd_reg32(info, TDCSR);
+
+       DBGISR(("%s isr_tdma status=%08x\n", info->device_name, status));
+
+       /* TDCSR (tx DMA control/status)
+        *
+        * 31..06  reserved
+        * 05      error
+        * 04      eol (end of list)
+        * 03      eob (end of buffer)
+        * 02      IRQ enable
+        * 01      reset
+        * 00      enable
+        */
+       wr_reg32(info, TDCSR, status);  /* clear pending */
+
+       if (status & (BIT5 + BIT4 + BIT3)) {
+               // another transmit buffer has completed
+               // run bottom half to get more send data from user
+               info->pending_bh |= BH_TRANSMIT;
+       }
+}
+
+static void isr_txeom(struct slgt_info *info, unsigned short status)
+{
+       DBGISR(("%s txeom status=%04x\n", info->device_name, status));
+
+       slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
+       tdma_reset(info);
+       reset_tbufs(info);
+       if (status & IRQ_TXUNDER) {
+               unsigned short val = rd_reg16(info, TCR);
+               wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
+               wr_reg16(info, TCR, val); /* clear reset bit */
+       }
+
+       if (info->tx_active) {
+               if (info->params.mode != MGSL_MODE_ASYNC) {
+                       if (status & IRQ_TXUNDER)
+                               info->icount.txunder++;
+                       else if (status & IRQ_TXIDLE)
+                               info->icount.txok++;
+               }
+
+               info->tx_active = 0;
+               info->tx_count = 0;
+
+               del_timer(&info->tx_timer);
+
+               if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) {
+                       info->signals &= ~SerialSignal_RTS;
+                       info->drop_rts_on_tx_done = 0;
+                       set_signals(info);
+               }
+
+#ifdef CONFIG_HDLC
+               if (info->netcount)
+                       hdlcdev_tx_done(info);
+               else
+#endif
+               {
+                       if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+                               tx_stop(info);
+                               return;
+                       }
+                       info->pending_bh |= BH_TRANSMIT;
+               }
+       }
+}
+
+/* interrupt service routine
+ *
+ *     irq     interrupt number
+ *     dev_id  device ID supplied during interrupt registration
+ *     regs    interrupted processor context
+ */
+static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct slgt_info *info;
+       unsigned int gsr;
+       unsigned int i;
+
+       DBGISR(("slgt_interrupt irq=%d entry\n", irq));
+
+       info = dev_id;
+       if (!info)
+               return IRQ_NONE;
+
+       spin_lock(&info->lock);
+
+       while((gsr = rd_reg32(info, GSR) & 0xffffff00)) {
+               DBGISR(("%s gsr=%08x\n", info->device_name, gsr));
+               info->irq_occurred = 1;
+               for(i=0; i < info->port_count ; i++) {
+                       if (info->port_array[i] == NULL)
+                               continue;
+                       if (gsr & (BIT8 << i))
+                               isr_serial(info->port_array[i]);
+                       if (gsr & (BIT16 << (i*2)))
+                               isr_rdma(info->port_array[i]);
+                       if (gsr & (BIT17 << (i*2)))
+                               isr_tdma(info->port_array[i]);
+               }
+       }
+
+       for(i=0; i < info->port_count ; i++) {
+               struct slgt_info *port = info->port_array[i];
+
+               if (port && (port->count || port->netcount) &&
+                   port->pending_bh && !port->bh_running &&
+                   !port->bh_requested) {
+                       DBGISR(("%s bh queued\n", port->device_name));
+                       schedule_work(&port->task);
+                       port->bh_requested = 1;
+               }
+       }
+
+       spin_unlock(&info->lock);
+
+       DBGISR(("slgt_interrupt irq=%d exit\n", irq));
+       return IRQ_HANDLED;
+}
+
+static int startup(struct slgt_info *info)
+{
+       DBGINFO(("%s startup\n", info->device_name));
+
+       if (info->flags & ASYNC_INITIALIZED)
+               return 0;
+
+       if (!info->tx_buf) {
+               info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL);
+               if (!info->tx_buf) {
+                       DBGERR(("%s can't allocate tx buffer\n", info->device_name));
+                       return -ENOMEM;
+               }
+       }
+
+       info->pending_bh = 0;
+
+       memset(&info->icount, 0, sizeof(info->icount));
+
+       /* program hardware for current parameters */
+       change_params(info);
+
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       info->flags |= ASYNC_INITIALIZED;
+
+       return 0;
+}
+
+/*
+ *  called by close() and hangup() to shutdown hardware
+ */
+static void shutdown(struct slgt_info *info)
+{
+       unsigned long flags;
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+       DBGINFO(("%s shutdown\n", info->device_name));
+
+       /* clear status wait queue because status changes */
+       /* can't happen after shutting down the hardware */
+       wake_up_interruptible(&info->status_event_wait_q);
+       wake_up_interruptible(&info->event_wait_q);
+
+       del_timer_sync(&info->tx_timer);
+       del_timer_sync(&info->rx_timer);
+
+       kfree(info->tx_buf);
+       info->tx_buf = NULL;
+
+       spin_lock_irqsave(&info->lock,flags);
+
+       tx_stop(info);
+       rx_stop(info);
+
+       slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
+
+       if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+               info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+               set_signals(info);
+       }
+
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       info->flags &= ~ASYNC_INITIALIZED;
+}
+
+static void program_hw(struct slgt_info *info)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock,flags);
+
+       rx_stop(info);
+       tx_stop(info);
+
+       if (info->params.mode == MGSL_MODE_HDLC ||
+           info->params.mode == MGSL_MODE_RAW ||
+           info->netcount)
+               hdlc_mode(info);
+       else
+               async_mode(info);
+
+       set_signals(info);
+
+       info->dcd_chkcount = 0;
+       info->cts_chkcount = 0;
+       info->ri_chkcount = 0;
+       info->dsr_chkcount = 0;
+
+       slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR);
+       get_signals(info);
+
+       if (info->netcount ||
+           (info->tty && info->tty->termios->c_cflag & CREAD))
+               rx_start(info);
+
+       spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/*
+ * reconfigure adapter based on new parameters
+ */
+static void change_params(struct slgt_info *info)
+{
+       unsigned cflag;
+       int bits_per_char;
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       DBGINFO(("%s change_params\n", info->device_name));
+
+       cflag = info->tty->termios->c_cflag;
+
+       /* if B0 rate (hangup) specified then negate DTR and RTS */
+       /* otherwise assert DTR and RTS */
+       if (cflag & CBAUD)
+               info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+       else
+               info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+
+       /* byte size and parity */
+
+       switch (cflag & CSIZE) {
+       case CS5: info->params.data_bits = 5; break;
+       case CS6: info->params.data_bits = 6; break;
+       case CS7: info->params.data_bits = 7; break;
+       case CS8: info->params.data_bits = 8; break;
+       default:  info->params.data_bits = 7; break;
+       }
+
+       info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1;
+
+       if (cflag & PARENB)
+               info->params.parity = (cflag & PARODD) ? ASYNC_PARITY_ODD : ASYNC_PARITY_EVEN;
+       else
+               info->params.parity = ASYNC_PARITY_NONE;
+
+       /* calculate number of jiffies to transmit a full
+        * FIFO (32 bytes) at specified data rate
+        */
+       bits_per_char = info->params.data_bits +
+                       info->params.stop_bits + 1;
+
+       info->params.data_rate = tty_get_baud_rate(info->tty);
+
+       if (info->params.data_rate) {
+               info->timeout = (32*HZ*bits_per_char) /
+                               info->params.data_rate;
+       }
+       info->timeout += HZ/50;         /* Add .02 seconds of slop */
+
+       if (cflag & CRTSCTS)
+               info->flags |= ASYNC_CTS_FLOW;
+       else
+               info->flags &= ~ASYNC_CTS_FLOW;
+
+       if (cflag & CLOCAL)
+               info->flags &= ~ASYNC_CHECK_CD;
+       else
+               info->flags |= ASYNC_CHECK_CD;
+
+       /* process tty input control flags */
+
+       info->read_status_mask = IRQ_RXOVER;
+       if (I_INPCK(info->tty))
+               info->read_status_mask |= MASK_PARITY | MASK_FRAMING;
+       if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+               info->read_status_mask |= MASK_BREAK;
+       if (I_IGNPAR(info->tty))
+               info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING;
+       if (I_IGNBRK(info->tty)) {
+               info->ignore_status_mask |= MASK_BREAK;
+               /* If ignoring parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (I_IGNPAR(info->tty))
+                       info->ignore_status_mask |= MASK_OVERRUN;
+       }
+
+       program_hw(info);
+}
+
+static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount)
+{
+       DBGINFO(("%s get_stats\n",  info->device_name));
+       if (!user_icount) {
+               memset(&info->icount, 0, sizeof(info->icount));
+       } else {
+               if (copy_to_user(user_icount, &info->icount, sizeof(struct mgsl_icount)))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+static int get_params(struct slgt_info *info, MGSL_PARAMS __user *user_params)
+{
+       DBGINFO(("%s get_params\n", info->device_name));
+       if (copy_to_user(user_params, &info->params, sizeof(MGSL_PARAMS)))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params)
+{
+       unsigned long flags;
+       MGSL_PARAMS tmp_params;
+
+       DBGINFO(("%s set_params\n", info->device_name));
+       if (copy_from_user(&tmp_params, new_params, sizeof(MGSL_PARAMS)))
+               return -EFAULT;
+
+       spin_lock_irqsave(&info->lock, flags);
+       memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
+       spin_unlock_irqrestore(&info->lock, flags);
+
+       change_params(info);
+
+       return 0;
+}
+
+static int get_txidle(struct slgt_info *info, int __user *idle_mode)
+{
+       DBGINFO(("%s get_txidle=%d\n", info->device_name, info->idle_mode));
+       if (put_user(info->idle_mode, idle_mode))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_txidle(struct slgt_info *info, int idle_mode)
+{
+       unsigned long flags;
+       DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode));
+       spin_lock_irqsave(&info->lock,flags);
+       info->idle_mode = idle_mode;
+       tx_set_idle(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
+}
+
+static int tx_enable(struct slgt_info *info, int enable)
+{
+       unsigned long flags;
+       DBGINFO(("%s tx_enable(%d)\n", info->device_name, enable));
+       spin_lock_irqsave(&info->lock,flags);
+       if (enable) {
+               if (!info->tx_enabled)
+                       tx_start(info);
+       } else {
+               if (info->tx_enabled)
+                       tx_stop(info);
+       }
+       spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
+}
+
+/*
+ * abort transmit HDLC frame
+ */
+static int tx_abort(struct slgt_info *info)
+{
+       unsigned long flags;
+       DBGINFO(("%s tx_abort\n", info->device_name));
+       spin_lock_irqsave(&info->lock,flags);
+       tdma_reset(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
+}
+
+static int rx_enable(struct slgt_info *info, int enable)
+{
+       unsigned long flags;
+       DBGINFO(("%s rx_enable(%d)\n", info->device_name, enable));
+       spin_lock_irqsave(&info->lock,flags);
+       if (enable) {
+               if (!info->rx_enabled)
+                       rx_start(info);
+       } else {
+               if (info->rx_enabled)
+                       rx_stop(info);
+       }
+       spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
+}
+
+/*
+ *  wait for specified event to occur
+ */
+static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr)
+{
+       unsigned long flags;
+       int s;
+       int rc=0;
+       struct mgsl_icount cprev, cnow;
+       int events;
+       int mask;
+       struct  _input_signal_events oldsigs, newsigs;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (get_user(mask, mask_ptr))
+               return -EFAULT;
+
+       DBGINFO(("%s wait_mgsl_event(%d)\n", info->device_name, mask));
+
+       spin_lock_irqsave(&info->lock,flags);
+
+       /* return immediately if state matches requested events */
+       get_signals(info);
+       s = info->signals;
+
+       events = mask &
+               ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
+                 ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
+                 ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
+                 ((s & SerialSignal_RI)  ? MgslEvent_RiActive :MgslEvent_RiInactive) );
+       if (events) {
+               spin_unlock_irqrestore(&info->lock,flags);
+               goto exit;
+       }
+
+       /* save current irq counts */
+       cprev = info->icount;
+       oldsigs = info->input_signal_events;
+
+       /* enable hunt and idle irqs if needed */
+       if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) {
+               unsigned short val = rd_reg16(info, SCR);
+               if (!(val & IRQ_RXIDLE))
+                       wr_reg16(info, SCR, (unsigned short)(val | IRQ_RXIDLE));
+       }
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       add_wait_queue(&info->event_wait_q, &wait);
+
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       for(;;) {
+               schedule();
+               if (signal_pending(current)) {
+                       rc = -ERESTARTSYS;
+                       break;
+               }
+
+               /* get current irq counts */
+               spin_lock_irqsave(&info->lock,flags);
+               cnow = info->icount;
+               newsigs = info->input_signal_events;
+               set_current_state(TASK_INTERRUPTIBLE);
+               spin_unlock_irqrestore(&info->lock,flags);
+
+               /* if no change, wait aborted for some reason */
+               if (newsigs.dsr_up   == oldsigs.dsr_up   &&
+                   newsigs.dsr_down == oldsigs.dsr_down &&
+                   newsigs.dcd_up   == oldsigs.dcd_up   &&
+                   newsigs.dcd_down == oldsigs.dcd_down &&
+                   newsigs.cts_up   == oldsigs.cts_up   &&
+                   newsigs.cts_down == oldsigs.cts_down &&
+                   newsigs.ri_up    == oldsigs.ri_up    &&
+                   newsigs.ri_down  == oldsigs.ri_down  &&
+                   cnow.exithunt    == cprev.exithunt   &&
+                   cnow.rxidle      == cprev.rxidle) {
+                       rc = -EIO;
+                       break;
+               }
+
+               events = mask &
+                       ( (newsigs.dsr_up   != oldsigs.dsr_up   ? MgslEvent_DsrActive:0)   +
+                         (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
+                         (newsigs.dcd_up   != oldsigs.dcd_up   ? MgslEvent_DcdActive:0)   +
+                         (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
+                         (newsigs.cts_up   != oldsigs.cts_up   ? MgslEvent_CtsActive:0)   +
+                         (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
+                         (newsigs.ri_up    != oldsigs.ri_up    ? MgslEvent_RiActive:0)    +
+                         (newsigs.ri_down  != oldsigs.ri_down  ? MgslEvent_RiInactive:0)  +
+                         (cnow.exithunt    != cprev.exithunt   ? MgslEvent_ExitHuntMode:0) +
+                         (cnow.rxidle      != cprev.rxidle     ? MgslEvent_IdleReceived:0) );
+               if (events)
+                       break;
+
+               cprev = cnow;
+               oldsigs = newsigs;
+       }
+
+       remove_wait_queue(&info->event_wait_q, &wait);
+       set_current_state(TASK_RUNNING);
+
+
+       if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
+               spin_lock_irqsave(&info->lock,flags);
+               if (!waitqueue_active(&info->event_wait_q)) {
+                       /* disable enable exit hunt mode/idle rcvd IRQs */
+                       wr_reg16(info, SCR,
+                               (unsigned short)(rd_reg16(info, SCR) & ~IRQ_RXIDLE));
+               }
+               spin_unlock_irqrestore(&info->lock,flags);
+       }
+exit:
+       if (rc == 0)
+               rc = put_user(events, mask_ptr);
+       return rc;
+}
+
+static int get_interface(struct slgt_info *info, int __user *if_mode)
+{
+       DBGINFO(("%s get_interface=%x\n", info->device_name, info->if_mode));
+       if (put_user(info->if_mode, if_mode))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_interface(struct slgt_info *info, int if_mode)
+{
+       unsigned long flags;
+       unsigned char val;
+
+       DBGINFO(("%s set_interface=%x)\n", info->device_name, if_mode));
+       spin_lock_irqsave(&info->lock,flags);
+       info->if_mode = if_mode;
+
+       msc_set_vcr(info);
+
+       /* TCR (tx control) 07  1=RTS driver control */
+       val = rd_reg16(info, TCR);
+       if (info->if_mode & MGSL_INTERFACE_RTS_EN)
+               val |= BIT7;
+       else
+               val &= ~BIT7;
+       wr_reg16(info, TCR, val);
+
+       spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
+}
+
+static int modem_input_wait(struct slgt_info *info,int arg)
+{
+       unsigned long flags;
+       int rc;
+       struct mgsl_icount cprev, cnow;
+       DECLARE_WAITQUEUE(wait, current);
+
+       /* save current irq counts */
+       spin_lock_irqsave(&info->lock,flags);
+       cprev = info->icount;
+       add_wait_queue(&info->status_event_wait_q, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       for(;;) {
+               schedule();
+               if (signal_pending(current)) {
+                       rc = -ERESTARTSYS;
+                       break;
+               }
+
+               /* get new irq counts */
+               spin_lock_irqsave(&info->lock,flags);
+               cnow = info->icount;
+               set_current_state(TASK_INTERRUPTIBLE);
+               spin_unlock_irqrestore(&info->lock,flags);
+
+               /* if no change, wait aborted for some reason */
+               if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+                       rc = -EIO;
+                       break;
+               }
+
+               /* check for change in caller specified modem input */
+               if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) ||
+                   (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) ||
+                   (arg & TIOCM_CD  && cnow.dcd != cprev.dcd) ||
+                   (arg & TIOCM_CTS && cnow.cts != cprev.cts)) {
+                       rc = 0;
+                       break;
+               }
+
+               cprev = cnow;
+       }
+       remove_wait_queue(&info->status_event_wait_q, &wait);
+       set_current_state(TASK_RUNNING);
+       return rc;
+}
+
+/*
+ *  return state of serial control and status signals
+ */
+static int tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned int result;
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock,flags);
+       get_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       result = ((info->signals & SerialSignal_RTS) ? TIOCM_RTS:0) +
+               ((info->signals & SerialSignal_DTR) ? TIOCM_DTR:0) +
+               ((info->signals & SerialSignal_DCD) ? TIOCM_CAR:0) +
+               ((info->signals & SerialSignal_RI)  ? TIOCM_RNG:0) +
+               ((info->signals & SerialSignal_DSR) ? TIOCM_DSR:0) +
+               ((info->signals & SerialSignal_CTS) ? TIOCM_CTS:0);
+
+       DBGINFO(("%s tiocmget value=%08X\n", info->device_name, result));
+       return result;
+}
+
+/*
+ * set modem control signals (DTR/RTS)
+ *
+ *     cmd     signal command: TIOCMBIS = set bit TIOCMBIC = clear bit
+ *             TIOCMSET = set/clear signal values
+ *     value   bit mask for command
+ */
+static int tiocmset(struct tty_struct *tty, struct file *file,
+                   unsigned int set, unsigned int clear)
+{
+       struct slgt_info *info = tty->driver_data;
+       unsigned long flags;
+
+       DBGINFO(("%s tiocmset(%x,%x)\n", info->device_name, set, clear));
+
+       if (set & TIOCM_RTS)
+               info->signals |= SerialSignal_RTS;
+       if (set & TIOCM_DTR)
+               info->signals |= SerialSignal_DTR;
+       if (clear & TIOCM_RTS)
+               info->signals &= ~SerialSignal_RTS;
+       if (clear & TIOCM_DTR)
+               info->signals &= ~SerialSignal_DTR;
+
+       spin_lock_irqsave(&info->lock,flags);
+       set_signals(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+       return 0;
+}
+
+/*
+ *  block current process until the device is ready to open
+ */
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+                          struct slgt_info *info)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int             retval;
+       int             do_clocal = 0, extra_count = 0;
+       unsigned long   flags;
+
+       DBGINFO(("%s block_til_ready\n", tty->driver->name));
+
+       if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
+               /* nonblock mode is set or port is not enabled */
+               info->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (tty->termios->c_cflag & CLOCAL)
+               do_clocal = 1;
+
+       /* Wait for carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, info->count is dropped by one, so that
+        * close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+
+       retval = 0;
+       add_wait_queue(&info->open_wait, &wait);
+
+       spin_lock_irqsave(&info->lock, flags);
+       if (!tty_hung_up_p(filp)) {
+               extra_count = 1;
+               info->count--;
+       }
+       spin_unlock_irqrestore(&info->lock, flags);
+       info->blocked_open++;
+
+       while (1) {
+               if ((tty->termios->c_cflag & CBAUD)) {
+                       spin_lock_irqsave(&info->lock,flags);
+                       info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+                       set_signals(info);
+                       spin_unlock_irqrestore(&info->lock,flags);
+               }
+
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
+                       retval = (info->flags & ASYNC_HUP_NOTIFY) ?
+                                       -EAGAIN : -ERESTARTSYS;
+                       break;
+               }
+
+               spin_lock_irqsave(&info->lock,flags);
+               get_signals(info);
+               spin_unlock_irqrestore(&info->lock,flags);
+
+               if (!(info->flags & ASYNC_CLOSING) &&
+                   (do_clocal || (info->signals & SerialSignal_DCD)) ) {
+                       break;
+               }
+
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+
+               DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
+               schedule();
+       }
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&info->open_wait, &wait);
+
+       if (extra_count)
+               info->count++;
+       info->blocked_open--;
+
+       if (!retval)
+               info->flags |= ASYNC_NORMAL_ACTIVE;
+
+       DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
+       return retval;
+}
+
+static int alloc_tmp_rbuf(struct slgt_info *info)
+{
+       info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL);
+       if (info->tmp_rbuf == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static void free_tmp_rbuf(struct slgt_info *info)
+{
+       kfree(info->tmp_rbuf);
+       info->tmp_rbuf = NULL;
+}
+
+/*
+ * allocate DMA descriptor lists.
+ */
+static int alloc_desc(struct slgt_info *info)
+{
+       unsigned int i;
+       unsigned int pbufs;
+
+       /* allocate memory to hold descriptor lists */
+       info->bufs = pci_alloc_consistent(info->pdev, DESC_LIST_SIZE, &info->bufs_dma_addr);
+       if (info->bufs == NULL)
+               return -ENOMEM;
+
+       memset(info->bufs, 0, DESC_LIST_SIZE);
+
+       info->rbufs = (struct slgt_desc*)info->bufs;
+       info->tbufs = ((struct slgt_desc*)info->bufs) + info->rbuf_count;
+
+       pbufs = (unsigned int)info->bufs_dma_addr;
+
+       /*
+        * Build circular lists of descriptors
+        */
+
+       for (i=0; i < info->rbuf_count; i++) {
+               /* physical address of this descriptor */
+               info->rbufs[i].pdesc = pbufs + (i * sizeof(struct slgt_desc));
+
+               /* physical address of next descriptor */
+               if (i == info->rbuf_count - 1)
+                       info->rbufs[i].next = cpu_to_le32(pbufs);
+               else
+                       info->rbufs[i].next = cpu_to_le32(pbufs + ((i+1) * sizeof(struct slgt_desc)));
+               set_desc_count(info->rbufs[i], DMABUFSIZE);
+       }
+
+       for (i=0; i < info->tbuf_count; i++) {
+               /* physical address of this descriptor */
+               info->tbufs[i].pdesc = pbufs + ((info->rbuf_count + i) * sizeof(struct slgt_desc));
+
+               /* physical address of next descriptor */
+               if (i == info->tbuf_count - 1)
+                       info->tbufs[i].next = cpu_to_le32(pbufs + info->rbuf_count * sizeof(struct slgt_desc));
+               else
+                       info->tbufs[i].next = cpu_to_le32(pbufs + ((info->rbuf_count + i + 1) * sizeof(struct slgt_desc)));
+       }
+
+       return 0;
+}
+
+static void free_desc(struct slgt_info *info)
+{
+       if (info->bufs != NULL) {
+               pci_free_consistent(info->pdev, DESC_LIST_SIZE, info->bufs, info->bufs_dma_addr);
+               info->bufs  = NULL;
+               info->rbufs = NULL;
+               info->tbufs = NULL;
+       }
+}
+
+static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count)
+{
+       int i;
+       for (i=0; i < count; i++) {
+               if ((bufs[i].buf = pci_alloc_consistent(info->pdev, DMABUFSIZE, &bufs[i].buf_dma_addr)) == NULL)
+                       return -ENOMEM;
+               bufs[i].pbuf  = cpu_to_le32((unsigned int)bufs[i].buf_dma_addr);
+       }
+       return 0;
+}
+
+static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count)
+{
+       int i;
+       for (i=0; i < count; i++) {
+               if (bufs[i].buf == NULL)
+                       continue;
+               pci_free_consistent(info->pdev, DMABUFSIZE, bufs[i].buf, bufs[i].buf_dma_addr);
+               bufs[i].buf = NULL;
+       }
+}
+
+static int alloc_dma_bufs(struct slgt_info *info)
+{
+       info->rbuf_count = 32;
+       info->tbuf_count = 32;
+
+       if (alloc_desc(info) < 0 ||
+           alloc_bufs(info, info->rbufs, info->rbuf_count) < 0 ||
+           alloc_bufs(info, info->tbufs, info->tbuf_count) < 0 ||
+           alloc_tmp_rbuf(info) < 0) {
+               DBGERR(("%s DMA buffer alloc fail\n", info->device_name));
+               return -ENOMEM;
+       }
+       reset_rbufs(info);
+       return 0;
+}
+
+static void free_dma_bufs(struct slgt_info *info)
+{
+       if (info->bufs) {
+               free_bufs(info, info->rbufs, info->rbuf_count);
+               free_bufs(info, info->tbufs, info->tbuf_count);
+               free_desc(info);
+       }
+       free_tmp_rbuf(info);
+}
+
+static int claim_resources(struct slgt_info *info)
+{
+       if (request_mem_region(info->phys_reg_addr, SLGT_REG_SIZE, "synclink_gt") == NULL) {
+               DBGERR(("%s reg addr conflict, addr=%08X\n",
+                       info->device_name, info->phys_reg_addr));
+               info->init_error = DiagStatus_AddressConflict;
+               goto errout;
+       }
+       else
+               info->reg_addr_requested = 1;
+
+       info->reg_addr = ioremap(info->phys_reg_addr, PAGE_SIZE);
+       if (!info->reg_addr) {
+               DBGERR(("%s cant map device registers, addr=%08X\n",
+                       info->device_name, info->phys_reg_addr));
+               info->init_error = DiagStatus_CantAssignPciResources;
+               goto errout;
+       }
+       info->reg_addr += info->reg_offset;
+       return 0;
+
+errout:
+       release_resources(info);
+       return -ENODEV;
+}
+
+static void release_resources(struct slgt_info *info)
+{
+       if (info->irq_requested) {
+               free_irq(info->irq_level, info);
+               info->irq_requested = 0;
+       }
+
+       if (info->reg_addr_requested) {
+               release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE);
+               info->reg_addr_requested = 0;
+       }
+
+       if (info->reg_addr) {
+               iounmap(info->reg_addr - info->reg_offset);
+               info->reg_addr = NULL;
+       }
+}
+
+/* Add the specified device instance data structure to the
+ * global linked list of devices and increment the device count.
+ */
+static void add_device(struct slgt_info *info)
+{
+       char *devstr;
+
+       info->next_device = NULL;
+       info->line = slgt_device_count;
+       sprintf(info->device_name, "%s%d", tty_dev_prefix, info->line);
+
+       if (info->line < MAX_DEVICES) {
+               if (maxframe[info->line])
+                       info->max_frame_size = maxframe[info->line];
+               info->dosyncppp = dosyncppp[info->line];
+       }
+
+       slgt_device_count++;
+
+       if (!slgt_device_list)
+               slgt_device_list = info;
+       else {
+               struct slgt_info *current_dev = slgt_device_list;
+               while(current_dev->next_device)
+                       current_dev = current_dev->next_device;
+               current_dev->next_device = info;
+       }
+
+       if (info->max_frame_size < 4096)
+               info->max_frame_size = 4096;
+       else if (info->max_frame_size > 65535)
+               info->max_frame_size = 65535;
+
+       switch(info->pdev->device) {
+       case SYNCLINK_GT_DEVICE_ID:
+               devstr = "GT";
+               break;
+       case SYNCLINK_GT4_DEVICE_ID:
+               devstr = "GT4";
+               break;
+       case SYNCLINK_AC_DEVICE_ID:
+               devstr = "AC";
+               info->params.mode = MGSL_MODE_ASYNC;
+               break;
+       default:
+               devstr = "(unknown model)";
+       }
+       printk("SyncLink %s %s IO=%08x IRQ=%d MaxFrameSize=%u\n",
+               devstr, info->device_name, info->phys_reg_addr,
+               info->irq_level, info->max_frame_size);
+
+#ifdef CONFIG_HDLC
+       hdlcdev_init(info);
+#endif
+}
+
+/*
+ *  allocate device instance structure, return NULL on failure
+ */
+static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
+{
+       struct slgt_info *info;
+
+       info = kmalloc(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);
+               info->max_frame_size = 4096;
+               info->raw_rx_size = DMABUFSIZE;
+               info->close_delay = 5*HZ/10;
+               info->closing_wait = 30*HZ;
+               init_waitqueue_head(&info->open_wait);
+               init_waitqueue_head(&info->close_wait);
+               init_waitqueue_head(&info->status_event_wait_q);
+               init_waitqueue_head(&info->event_wait_q);
+               spin_lock_init(&info->netlock);
+               memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
+               info->idle_mode = HDLC_TXIDLE_FLAGS;
+               info->adapter_num = adapter_num;
+               info->port_num = port_num;
+
+               init_timer(&info->tx_timer);
+               info->tx_timer.data = (unsigned long)info;
+               info->tx_timer.function = tx_timeout;
+
+               init_timer(&info->rx_timer);
+               info->rx_timer.data = (unsigned long)info;
+               info->rx_timer.function = rx_timeout;
+
+               /* Copy configuration info to device instance data */
+               info->pdev = pdev;
+               info->irq_level = pdev->irq;
+               info->phys_reg_addr = pci_resource_start(pdev,0);
+
+               /* veremap works on page boundaries
+                * map full page starting at the page boundary
+                */
+               info->reg_offset    = info->phys_reg_addr & (PAGE_SIZE-1);
+               info->phys_reg_addr &= ~(PAGE_SIZE-1);
+
+               info->bus_type = MGSL_BUS_TYPE_PCI;
+               info->irq_flags = SA_SHIRQ;
+
+               info->init_error = -1; /* assume error, set to 0 on successful init */
+       }
+
+       return info;
+}
+
+static void device_init(int adapter_num, struct pci_dev *pdev)
+{
+       struct slgt_info *port_array[SLGT_MAX_PORTS];
+       int i;
+       int port_count = 1;
+
+       if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
+               port_count = 4;
+
+       /* allocate device instances for all ports */
+       for (i=0; i < port_count; ++i) {
+               port_array[i] = alloc_dev(adapter_num, i, pdev);
+               if (port_array[i] == NULL) {
+                       for (--i; i >= 0; --i)
+                               kfree(port_array[i]);
+                       return;
+               }
+       }
+
+       /* give copy of port_array to all ports and add to device list  */
+       for (i=0; i < port_count; ++i) {
+               memcpy(port_array[i]->port_array, port_array, sizeof(port_array));
+               add_device(port_array[i]);
+               port_array[i]->port_count = port_count;
+               spin_lock_init(&port_array[i]->lock);
+       }
+
+       /* Allocate and claim adapter resources */
+       if (!claim_resources(port_array[0])) {
+
+               alloc_dma_bufs(port_array[0]);
+
+               /* copy resource information from first port to others */
+               for (i = 1; i < port_count; ++i) {
+                       port_array[i]->lock      = port_array[0]->lock;
+                       port_array[i]->irq_level = port_array[0]->irq_level;
+                       port_array[i]->reg_addr  = port_array[0]->reg_addr;
+                       alloc_dma_bufs(port_array[i]);
+               }
+
+               if (request_irq(port_array[0]->irq_level,
+                                       slgt_interrupt,
+                                       port_array[0]->irq_flags,
+                                       port_array[0]->device_name,
+                                       port_array[0]) < 0) {
+                       DBGERR(("%s request_irq failed IRQ=%d\n",
+                               port_array[0]->device_name,
+                               port_array[0]->irq_level));
+               } else {
+                       port_array[0]->irq_requested = 1;
+                       adapter_test(port_array[0]);
+                       for (i=1 ; i < port_count ; i++)
+                               port_array[i]->init_error = port_array[0]->init_error;
+               }
+       }
+}
+
+static int __devinit init_one(struct pci_dev *dev,
+                             const struct pci_device_id *ent)
+{
+       if (pci_enable_device(dev)) {
+               printk("error enabling pci device %p\n", dev);
+               return -EIO;
+       }
+       pci_set_master(dev);
+       device_init(slgt_device_count, dev);
+       return 0;
+}
+
+static void __devexit remove_one(struct pci_dev *dev)
+{
+}
+
+static struct tty_operations ops = {
+       .open = open,
+       .close = close,
+       .write = write,
+       .put_char = put_char,
+       .flush_chars = flush_chars,
+       .write_room = write_room,
+       .chars_in_buffer = chars_in_buffer,
+       .flush_buffer = flush_buffer,
+       .ioctl = ioctl,
+       .throttle = throttle,
+       .unthrottle = unthrottle,
+       .send_xchar = send_xchar,
+       .break_ctl = set_break,
+       .wait_until_sent = wait_until_sent,
+       .read_proc = read_proc,
+       .set_termios = set_termios,
+       .stop = tx_hold,
+       .start = tx_release,
+       .hangup = hangup,
+       .tiocmget = tiocmget,
+       .tiocmset = tiocmset,
+};
+
+static void slgt_cleanup(void)
+{
+       int rc;
+       struct slgt_info *info;
+       struct slgt_info *tmp;
+
+       printk("unload %s %s\n", driver_name, driver_version);
+
+       if (serial_driver) {
+               if ((rc = tty_unregister_driver(serial_driver)))
+                       DBGERR(("tty_unregister_driver error=%d\n", rc));
+               put_tty_driver(serial_driver);
+       }
+
+       /* reset devices */
+       info = slgt_device_list;
+       while(info) {
+               reset_port(info);
+               info = info->next_device;
+       }
+
+       /* release devices */
+       info = slgt_device_list;
+       while(info) {
+#ifdef CONFIG_HDLC
+               hdlcdev_exit(info);
+#endif
+               free_dma_bufs(info);
+               free_tmp_rbuf(info);
+               if (info->port_num == 0)
+                       release_resources(info);
+               tmp = info;
+               info = info->next_device;
+               kfree(tmp);
+       }
+
+       if (pci_registered)
+               pci_unregister_driver(&pci_driver);
+}
+
+/*
+ *  Driver initialization entry point.
+ */
+static int __init slgt_init(void)
+{
+       int rc;
+
+       printk("%s %s\n", driver_name, driver_version);
+
+       slgt_device_count = 0;
+       if ((rc = pci_register_driver(&pci_driver)) < 0) {
+               printk("%s pci_register_driver error=%d\n", driver_name, rc);
+               return rc;
+       }
+       pci_registered = 1;
+
+       if (!slgt_device_list) {
+               printk("%s no devices found\n",driver_name);
+               return -ENODEV;
+       }
+
+       serial_driver = alloc_tty_driver(MAX_DEVICES);
+       if (!serial_driver) {
+               rc = -ENOMEM;
+               goto error;
+       }
+
+       /* Initialize the tty_driver structure */
+
+       serial_driver->owner = THIS_MODULE;
+       serial_driver->driver_name = tty_driver_name;
+       serial_driver->name = tty_dev_prefix;
+       serial_driver->major = ttymajor;
+       serial_driver->minor_start = 64;
+       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver->subtype = SERIAL_TYPE_NORMAL;
+       serial_driver->init_termios = tty_std_termios;
+       serial_driver->init_termios.c_cflag =
+               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver->flags = TTY_DRIVER_REAL_RAW;
+       tty_set_operations(serial_driver, &ops);
+       if ((rc = tty_register_driver(serial_driver)) < 0) {
+               DBGERR(("%s can't register serial driver\n", driver_name));
+               put_tty_driver(serial_driver);
+               serial_driver = NULL;
+               goto error;
+       }
+
+       printk("%s %s, tty major#%d\n",
+               driver_name, driver_version,
+               serial_driver->major);
+
+       return 0;
+
+error:
+       slgt_cleanup();
+       return rc;
+}
+
+static void __exit slgt_exit(void)
+{
+       slgt_cleanup();
+}
+
+module_init(slgt_init);
+module_exit(slgt_exit);
+
+/*
+ * register access routines
+ */
+
+#define CALC_REGADDR() \
+       unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \
+       if (addr >= 0x80) \
+               reg_addr += (info->port_num) * 32;
+
+static __u8 rd_reg8(struct slgt_info *info, unsigned int addr)
+{
+       CALC_REGADDR();
+       return readb((void __iomem *)reg_addr);
+}
+
+static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value)
+{
+       CALC_REGADDR();
+       writeb(value, (void __iomem *)reg_addr);
+}
+
+static __u16 rd_reg16(struct slgt_info *info, unsigned int addr)
+{
+       CALC_REGADDR();
+       return readw((void __iomem *)reg_addr);
+}
+
+static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value)
+{
+       CALC_REGADDR();
+       writew(value, (void __iomem *)reg_addr);
+}
+
+static __u32 rd_reg32(struct slgt_info *info, unsigned int addr)
+{
+       CALC_REGADDR();
+       return readl((void __iomem *)reg_addr);
+}
+
+static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value)
+{
+       CALC_REGADDR();
+       writel(value, (void __iomem *)reg_addr);
+}
+
+static void rdma_reset(struct slgt_info *info)
+{
+       unsigned int i;
+
+       /* set reset bit */
+       wr_reg32(info, RDCSR, BIT1);
+
+       /* wait for enable bit cleared */
+       for(i=0 ; i < 1000 ; i++)
+               if (!(rd_reg32(info, RDCSR) & BIT0))
+                       break;
+}
+
+static void tdma_reset(struct slgt_info *info)
+{
+       unsigned int i;
+
+       /* set reset bit */
+       wr_reg32(info, TDCSR, BIT1);
+
+       /* wait for enable bit cleared */
+       for(i=0 ; i < 1000 ; i++)
+               if (!(rd_reg32(info, TDCSR) & BIT0))
+                       break;
+}
+
+/*
+ * enable internal loopback
+ * TxCLK and RxCLK are generated from BRG
+ * and TxD is looped back to RxD internally.
+ */
+static void enable_loopback(struct slgt_info *info)
+{
+       /* SCR (serial control) BIT2=looopback enable */
+       wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT2));
+
+       if (info->params.mode != MGSL_MODE_ASYNC) {
+               /* CCR (clock control)
+                * 07..05  tx clock source (010 = BRG)
+                * 04..02  rx clock source (010 = BRG)
+                * 01      auxclk enable   (0 = disable)
+                * 00      BRG enable      (1 = enable)
+                *
+                * 0100 1001
+                */
+               wr_reg8(info, CCR, 0x49);
+
+               /* set speed if available, otherwise use default */
+               if (info->params.clock_speed)
+                       set_rate(info, info->params.clock_speed);
+               else
+                       set_rate(info, 3686400);
+       }
+}
+
+/*
+ *  set baud rate generator to specified rate
+ */
+static void set_rate(struct slgt_info *info, u32 rate)
+{
+       unsigned int div;
+       static unsigned int osc = 14745600;
+
+       /* div = osc/rate - 1
+        *
+        * Round div up if osc/rate is not integer to
+        * force to next slowest rate.
+        */
+
+       if (rate) {
+               div = osc/rate;
+               if (!(osc % rate) && div)
+                       div--;
+               wr_reg16(info, BDR, (unsigned short)div);
+       }
+}
+
+static void rx_stop(struct slgt_info *info)
+{
+       unsigned short val;
+
+       /* disable and reset receiver */
+       val = rd_reg16(info, RCR) & ~BIT1;          /* clear enable bit */
+       wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */
+       wr_reg16(info, RCR, val);                  /* clear reset bit */
+
+       slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA + IRQ_RXIDLE);
+
+       /* clear pending rx interrupts */
+       wr_reg16(info, SSR, IRQ_RXIDLE + IRQ_RXOVER);
+
+       rdma_reset(info);
+
+       info->rx_enabled = 0;
+       info->rx_restart = 0;
+}
+
+static void rx_start(struct slgt_info *info)
+{
+       unsigned short val;
+
+       slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA);
+
+       /* clear pending rx overrun IRQ */
+       wr_reg16(info, SSR, IRQ_RXOVER);
+
+       /* reset and disable receiver */
+       val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */
+       wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */
+       wr_reg16(info, RCR, val);                  /* clear reset bit */
+
+       rdma_reset(info);
+       reset_rbufs(info);
+
+       /* set 1st descriptor address */
+       wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
+
+       if (info->params.mode != MGSL_MODE_ASYNC) {
+               /* enable rx DMA and DMA interrupt */
+               wr_reg32(info, RDCSR, (BIT2 + BIT0));
+       } else {
+               /* enable saving of rx status, rx DMA and DMA interrupt */
+               wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
+       }
+
+       slgt_irq_on(info, IRQ_RXOVER);
+
+       /* enable receiver */
+       wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1));
+
+       info->rx_restart = 0;
+       info->rx_enabled = 1;
+}
+
+static void tx_start(struct slgt_info *info)
+{
+       if (!info->tx_enabled) {
+               wr_reg16(info, TCR,
+                       (unsigned short)(rd_reg16(info, TCR) | BIT1));
+               info->tx_enabled = TRUE;
+       }
+
+       if (info->tx_count) {
+               info->drop_rts_on_tx_done = 0;
+
+               if (info->params.mode != MGSL_MODE_ASYNC) {
+                       if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
+                               get_signals(info);
+                               if (!(info->signals & SerialSignal_RTS)) {
+                                       info->signals |= SerialSignal_RTS;
+                                       set_signals(info);
+                                       info->drop_rts_on_tx_done = 1;
+                               }
+                       }
+
+                       slgt_irq_off(info, IRQ_TXDATA);
+                       slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
+                       /* clear tx idle and underrun status bits */
+                       wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
+
+                       if (!(rd_reg32(info, TDCSR) & BIT0)) {
+                               /* tx DMA stopped, restart tx DMA */
+                               tdma_reset(info);
+                               /* set 1st descriptor address */
+                               wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+                               if (info->params.mode == MGSL_MODE_RAW)
+                                       wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
+                               else
+                                       wr_reg32(info, TDCSR, BIT0); /* DMA enable */
+                       }
+
+                       if (info->params.mode != MGSL_MODE_RAW) {
+                               info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
+                               add_timer(&info->tx_timer);
+                       }
+               } else {
+                       tdma_reset(info);
+                       /* set 1st descriptor address */
+                       wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+
+                       slgt_irq_off(info, IRQ_TXDATA);
+                       slgt_irq_on(info, IRQ_TXIDLE);
+                       /* clear tx idle status bit */
+                       wr_reg16(info, SSR, IRQ_TXIDLE);
+
+                       /* enable tx DMA */
+                       wr_reg32(info, TDCSR, BIT0);
+               }
+
+               info->tx_active = 1;
+       }
+}
+
+static void tx_stop(struct slgt_info *info)
+{
+       unsigned short val;
+
+       del_timer(&info->tx_timer);
+
+       tdma_reset(info);
+
+       /* reset and disable transmitter */
+       val = rd_reg16(info, TCR) & ~BIT1;          /* clear enable bit */
+       wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
+       wr_reg16(info, TCR, val);                  /* clear reset */
+
+       slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
+
+       /* clear tx idle and underrun status bit */
+       wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
+
+       reset_tbufs(info);
+
+       info->tx_enabled = 0;
+       info->tx_active  = 0;
+}
+
+static void reset_port(struct slgt_info *info)
+{
+       if (!info->reg_addr)
+               return;
+
+       tx_stop(info);
+       rx_stop(info);
+
+       info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+       set_signals(info);
+
+       slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
+}
+
+static void reset_adapter(struct slgt_info *info)
+{
+       int i;
+       for (i=0; i < info->port_count; ++i) {
+               if (info->port_array[i])
+                       reset_port(info->port_array[i]);
+       }
+}
+
+static void async_mode(struct slgt_info *info)
+{
+       unsigned short val;
+
+       slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
+       tx_stop(info);
+       rx_stop(info);
+
+       /* TCR (tx control)
+        *
+        * 15..13  mode, 010=async
+        * 12..10  encoding, 000=NRZ
+        * 09      parity enable
+        * 08      1=odd parity, 0=even parity
+        * 07      1=RTS driver control
+        * 06      1=break enable
+        * 05..04  character length
+        *         00=5 bits
+        *         01=6 bits
+        *         10=7 bits
+        *         11=8 bits
+        * 03      0=1 stop bit, 1=2 stop bits
+        * 02      reset
+        * 01      enable
+        * 00      auto-CTS enable
+        */
+       val = 0x4000;
+
+       if (info->if_mode & MGSL_INTERFACE_RTS_EN)
+               val |= BIT7;
+
+       if (info->params.parity != ASYNC_PARITY_NONE) {
+               val |= BIT9;
+               if (info->params.parity == ASYNC_PARITY_ODD)
+                       val |= BIT8;
+       }
+
+       switch (info->params.data_bits)
+       {
+       case 6: val |= BIT4; break;
+       case 7: val |= BIT5; break;
+       case 8: val |= BIT5 + BIT4; break;
+       }
+
+       if (info->params.stop_bits != 1)
+               val |= BIT3;
+
+       if (info->params.flags & HDLC_FLAG_AUTO_CTS)
+               val |= BIT0;
+
+       wr_reg16(info, TCR, val);
+
+       /* RCR (rx control)
+        *
+        * 15..13  mode, 010=async
+        * 12..10  encoding, 000=NRZ
+        * 09      parity enable
+        * 08      1=odd parity, 0=even parity
+        * 07..06  reserved, must be 0
+        * 05..04  character length
+        *         00=5 bits
+        *         01=6 bits
+        *         10=7 bits
+        *         11=8 bits
+        * 03      reserved, must be zero
+        * 02      reset
+        * 01      enable
+        * 00      auto-DCD enable
+        */
+       val = 0x4000;
+
+       if (info->params.parity != ASYNC_PARITY_NONE) {
+               val |= BIT9;
+               if (info->params.parity == ASYNC_PARITY_ODD)
+                       val |= BIT8;
+       }
+
+       switch (info->params.data_bits)
+       {
+       case 6: val |= BIT4; break;
+       case 7: val |= BIT5; break;
+       case 8: val |= BIT5 + BIT4; break;
+       }
+
+       if (info->params.flags & HDLC_FLAG_AUTO_DCD)
+               val |= BIT0;
+
+       wr_reg16(info, RCR, val);
+
+       /* CCR (clock control)
+        *
+        * 07..05  011 = tx clock source is BRG/16
+        * 04..02  010 = rx clock source is BRG
+        * 01      0 = auxclk disabled
+        * 00      1 = BRG enabled
+        *
+        * 0110 1001
+        */
+       wr_reg8(info, CCR, 0x69);
+
+       msc_set_vcr(info);
+
+       tx_set_idle(info);
+
+       /* SCR (serial control)
+        *
+        * 15  1=tx req on FIFO half empty
+        * 14  1=rx req on FIFO half full
+        * 13  tx data  IRQ enable
+        * 12  tx idle  IRQ enable
+        * 11  rx break on IRQ enable
+        * 10  rx data  IRQ enable
+        * 09  rx break off IRQ enable
+        * 08  overrun  IRQ enable
+        * 07  DSR      IRQ enable
+        * 06  CTS      IRQ enable
+        * 05  DCD      IRQ enable
+        * 04  RI       IRQ enable
+        * 03  reserved, must be zero
+        * 02  1=txd->rxd internal loopback enable
+        * 01  reserved, must be zero
+        * 00  1=master IRQ enable
+        */
+       val = BIT15 + BIT14 + BIT0;
+       wr_reg16(info, SCR, val);
+
+       slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER);
+
+       set_rate(info, info->params.data_rate * 16);
+
+       if (info->params.loopback)
+               enable_loopback(info);
+}
+
+static void hdlc_mode(struct slgt_info *info)
+{
+       unsigned short val;
+
+       slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
+       tx_stop(info);
+       rx_stop(info);
+
+       /* TCR (tx control)
+        *
+        * 15..13  mode, 000=HDLC 001=raw sync
+        * 12..10  encoding
+        * 09      CRC enable
+        * 08      CRC32
+        * 07      1=RTS driver control
+        * 06      preamble enable
+        * 05..04  preamble length
+        * 03      share open/close flag
+        * 02      reset
+        * 01      enable
+        * 00      auto-CTS enable
+        */
+       val = 0;
+
+       if (info->params.mode == MGSL_MODE_RAW)
+               val |= BIT13;
+       if (info->if_mode & MGSL_INTERFACE_RTS_EN)
+               val |= BIT7;
+
+       switch(info->params.encoding)
+       {
+       case HDLC_ENCODING_NRZB:          val |= BIT10; break;
+       case HDLC_ENCODING_NRZI_MARK:     val |= BIT11; break;
+       case HDLC_ENCODING_NRZI:          val |= BIT11 + BIT10; break;
+       case HDLC_ENCODING_BIPHASE_MARK:  val |= BIT12; break;
+       case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break;
+       case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break;
+       case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
+       }
+
+       switch (info->params.crc_type)
+       {
+       case HDLC_CRC_16_CCITT: val |= BIT9; break;
+       case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
+       }
+
+       if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
+               val |= BIT6;
+
+       switch (info->params.preamble_length)
+       {
+       case HDLC_PREAMBLE_LENGTH_16BITS: val |= BIT5; break;
+       case HDLC_PREAMBLE_LENGTH_32BITS: val |= BIT4; break;
+       case HDLC_PREAMBLE_LENGTH_64BITS: val |= BIT5 + BIT4; break;
+       }
+
+       if (info->params.flags & HDLC_FLAG_AUTO_CTS)
+               val |= BIT0;
+
+       wr_reg16(info, TCR, val);
+
+       /* TPR (transmit preamble) */
+
+       switch (info->params.preamble)
+       {
+       case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break;
+       case HDLC_PREAMBLE_PATTERN_ONES:  val = 0xff; break;
+       case HDLC_PREAMBLE_PATTERN_ZEROS: val = 0x00; break;
+       case HDLC_PREAMBLE_PATTERN_10:    val = 0x55; break;
+       case HDLC_PREAMBLE_PATTERN_01:    val = 0xaa; break;
+       default:                          val = 0x7e; break;
+       }
+       wr_reg8(info, TPR, (unsigned char)val);
+
+       /* RCR (rx control)
+        *
+        * 15..13  mode, 000=HDLC 001=raw sync
+        * 12..10  encoding
+        * 09      CRC enable
+        * 08      CRC32
+        * 07..03  reserved, must be 0
+        * 02      reset
+        * 01      enable
+        * 00      auto-DCD enable
+        */
+       val = 0;
+
+       if (info->params.mode == MGSL_MODE_RAW)
+               val |= BIT13;
+
+       switch(info->params.encoding)
+       {
+       case HDLC_ENCODING_NRZB:          val |= BIT10; break;
+       case HDLC_ENCODING_NRZI_MARK:     val |= BIT11; break;
+       case HDLC_ENCODING_NRZI:          val |= BIT11 + BIT10; break;
+       case HDLC_ENCODING_BIPHASE_MARK:  val |= BIT12; break;
+       case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break;
+       case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break;
+       case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
+       }
+
+       switch (info->params.crc_type)
+       {
+       case HDLC_CRC_16_CCITT: val |= BIT9; break;
+       case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
+       }
+
+       if (info->params.flags & HDLC_FLAG_AUTO_DCD)
+               val |= BIT0;
+
+       wr_reg16(info, RCR, val);
+
+       /* CCR (clock control)
+        *
+        * 07..05  tx clock source
+        * 04..02  rx clock source
+        * 01      auxclk enable
+        * 00      BRG enable
+        */
+       val = 0;
+
+       if (info->params.flags & HDLC_FLAG_TXC_BRG)
+       {
+               // when RxC source is DPLL, BRG generates 16X DPLL
+               // reference clock, so take TxC from BRG/16 to get
+               // transmit clock at actual data rate
+               if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+                       val |= BIT6 + BIT5;     /* 011, txclk = BRG/16 */
+               else
+                       val |= BIT6;    /* 010, txclk = BRG */
+       }
+       else if (info->params.flags & HDLC_FLAG_TXC_DPLL)
+               val |= BIT7;    /* 100, txclk = DPLL Input */
+       else if (info->params.flags & HDLC_FLAG_TXC_RXCPIN)
+               val |= BIT5;    /* 001, txclk = RXC Input */
+
+       if (info->params.flags & HDLC_FLAG_RXC_BRG)
+               val |= BIT3;    /* 010, rxclk = BRG */
+       else if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+               val |= BIT4;    /* 100, rxclk = DPLL */
+       else if (info->params.flags & HDLC_FLAG_RXC_TXCPIN)
+               val |= BIT2;    /* 001, rxclk = TXC Input */
+
+       if (info->params.clock_speed)
+               val |= BIT1 + BIT0;
+
+       wr_reg8(info, CCR, (unsigned char)val);
+
+       if (info->params.flags & (HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL))
+       {
+               // program DPLL mode
+               switch(info->params.encoding)
+               {
+               case HDLC_ENCODING_BIPHASE_MARK:
+               case HDLC_ENCODING_BIPHASE_SPACE:
+                       val = BIT7; break;
+               case HDLC_ENCODING_BIPHASE_LEVEL:
+               case HDLC_ENCODING_DIFF_BIPHASE_LEVEL:
+                       val = BIT7 + BIT6; break;
+               default: val = BIT6;    // NRZ encodings
+               }
+               wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | val));
+
+               // DPLL requires a 16X reference clock from BRG
+               set_rate(info, info->params.clock_speed * 16);
+       }
+       else
+               set_rate(info, info->params.clock_speed);
+
+       tx_set_idle(info);
+
+       msc_set_vcr(info);
+
+       /* SCR (serial control)
+        *
+        * 15  1=tx req on FIFO half empty
+        * 14  1=rx req on FIFO half full
+        * 13  tx data  IRQ enable
+        * 12  tx idle  IRQ enable
+        * 11  underrun IRQ enable
+        * 10  rx data  IRQ enable
+        * 09  rx idle  IRQ enable
+        * 08  overrun  IRQ enable
+        * 07  DSR      IRQ enable
+        * 06  CTS      IRQ enable
+        * 05  DCD      IRQ enable
+        * 04  RI       IRQ enable
+        * 03  reserved, must be zero
+        * 02  1=txd->rxd internal loopback enable
+        * 01  reserved, must be zero
+        * 00  1=master IRQ enable
+        */
+       wr_reg16(info, SCR, BIT15 + BIT14 + BIT0);
+
+       if (info->params.loopback)
+               enable_loopback(info);
+}
+
+/*
+ *  set transmit idle mode
+ */
+static void tx_set_idle(struct slgt_info *info)
+{
+       unsigned char val = 0xff;
+
+       switch(info->idle_mode)
+       {
+       case HDLC_TXIDLE_FLAGS:          val = 0x7e; break;
+       case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break;
+       case HDLC_TXIDLE_ZEROS:          val = 0x00; break;
+       case HDLC_TXIDLE_ONES:           val = 0xff; break;
+       case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
+       case HDLC_TXIDLE_SPACE:          val = 0x00; break;
+       case HDLC_TXIDLE_MARK:           val = 0xff; break;
+       }
+
+       wr_reg8(info, TIR, val);
+}
+
+/*
+ * get state of V24 status (input) signals
+ */
+static void get_signals(struct slgt_info *info)
+{
+       unsigned short status = rd_reg16(info, SSR);
+
+       /* clear all serial signals except DTR and RTS */
+       info->signals &= SerialSignal_DTR + SerialSignal_RTS;
+
+       if (status & BIT3)
+               info->signals |= SerialSignal_DSR;
+       if (status & BIT2)
+               info->signals |= SerialSignal_CTS;
+       if (status & BIT1)
+               info->signals |= SerialSignal_DCD;
+       if (status & BIT0)
+               info->signals |= SerialSignal_RI;
+}
+
+/*
+ * set V.24 Control Register based on current configuration
+ */
+static void msc_set_vcr(struct slgt_info *info)
+{
+       unsigned char val = 0;
+
+       /* VCR (V.24 control)
+        *
+        * 07..04  serial IF select
+        * 03      DTR
+        * 02      RTS
+        * 01      LL
+        * 00      RL
+        */
+
+       switch(info->if_mode & MGSL_INTERFACE_MASK)
+       {
+       case MGSL_INTERFACE_RS232:
+               val |= BIT5; /* 0010 */
+               break;
+       case MGSL_INTERFACE_V35:
+               val |= BIT7 + BIT6 + BIT5; /* 1110 */
+               break;
+       case MGSL_INTERFACE_RS422:
+               val |= BIT6; /* 0100 */
+               break;
+       }
+
+       if (info->signals & SerialSignal_DTR)
+               val |= BIT3;
+       if (info->signals & SerialSignal_RTS)
+               val |= BIT2;
+       if (info->if_mode & MGSL_INTERFACE_LL)
+               val |= BIT1;
+       if (info->if_mode & MGSL_INTERFACE_RL)
+               val |= BIT0;
+       wr_reg8(info, VCR, val);
+}
+
+/*
+ * set state of V24 control (output) signals
+ */
+static void set_signals(struct slgt_info *info)
+{
+       unsigned char val = rd_reg8(info, VCR);
+       if (info->signals & SerialSignal_DTR)
+               val |= BIT3;
+       else
+               val &= ~BIT3;
+       if (info->signals & SerialSignal_RTS)
+               val |= BIT2;
+       else
+               val &= ~BIT2;
+       wr_reg8(info, VCR, val);
+}
+
+/*
+ * free range of receive DMA buffers (i to last)
+ */
+static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last)
+{
+       int done = 0;
+
+       while(!done) {
+               /* reset current buffer for reuse */
+               info->rbufs[i].status = 0;
+               if (info->params.mode == MGSL_MODE_RAW)
+                       set_desc_count(info->rbufs[i], info->raw_rx_size);
+               else
+                       set_desc_count(info->rbufs[i], DMABUFSIZE);
+
+               if (i == last)
+                       done = 1;
+               if (++i == info->rbuf_count)
+                       i = 0;
+       }
+       info->rbuf_current = i;
+}
+
+/*
+ * mark all receive DMA buffers as free
+ */
+static void reset_rbufs(struct slgt_info *info)
+{
+       free_rbufs(info, 0, info->rbuf_count - 1);
+}
+
+/*
+ * pass receive HDLC frame to upper layer
+ *
+ * return 1 if frame available, otherwise 0
+ */
+static int rx_get_frame(struct slgt_info *info)
+{
+       unsigned int start, end;
+       unsigned short status;
+       unsigned int framesize = 0;
+       int rc = 0;
+       unsigned long flags;
+       struct tty_struct *tty = info->tty;
+       unsigned char addr_field = 0xff;
+
+check_again:
+
+       framesize = 0;
+       addr_field = 0xff;
+       start = end = info->rbuf_current;
+
+       for (;;) {
+               if (!desc_complete(info->rbufs[end]))
+                       goto cleanup;
+
+               if (framesize == 0 && info->params.addr_filter != 0xff)
+                       addr_field = info->rbufs[end].buf[0];
+
+               framesize += desc_count(info->rbufs[end]);
+
+               if (desc_eof(info->rbufs[end]))
+                       break;
+
+               if (++end == info->rbuf_count)
+                       end = 0;
+
+               if (end == info->rbuf_current) {
+                       if (info->rx_enabled){
+                               spin_lock_irqsave(&info->lock,flags);
+                               rx_start(info);
+                               spin_unlock_irqrestore(&info->lock,flags);
+                       }
+                       goto cleanup;
+               }
+       }
+
+       /* status
+        *
+        * 15      buffer complete
+        * 14..06  reserved
+        * 05..04  residue
+        * 02      eof (end of frame)
+        * 01      CRC error
+        * 00      abort
+        */
+       status = desc_status(info->rbufs[end]);
+
+       /* ignore CRC bit if not using CRC (bit is undefined) */
+       if (info->params.crc_type == HDLC_CRC_NONE)
+               status &= ~BIT1;
+
+       if (framesize == 0 ||
+                (addr_field != 0xff && addr_field != info->params.addr_filter)) {
+               free_rbufs(info, start, end);
+               goto check_again;
+       }
+
+       if (framesize < 2 || status & (BIT1+BIT0)) {
+               if (framesize < 2 || (status & BIT0))
+                       info->icount.rxshort++;
+               else
+                       info->icount.rxcrc++;
+               framesize = 0;
+
+#ifdef CONFIG_HDLC
+               {
+                       struct net_device_stats *stats = hdlc_stats(info->netdev);
+                       stats->rx_errors++;
+                       stats->rx_frame_errors++;
+               }
+#endif
+       } else {
+               /* adjust frame size for CRC, if any */
+               if (info->params.crc_type == HDLC_CRC_16_CCITT)
+                       framesize -= 2;
+               else if (info->params.crc_type == HDLC_CRC_32_CCITT)
+                       framesize -= 4;
+       }
+
+       DBGBH(("%s rx frame status=%04X size=%d\n",
+               info->device_name, status, framesize));
+       DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx");
+
+       if (framesize) {
+               if (framesize > info->max_frame_size)
+                       info->icount.rxlong++;
+               else {
+                       /* copy dma buffer(s) to contiguous temp buffer */
+                       int copy_count = framesize;
+                       int i = start;
+                       unsigned char *p = info->tmp_rbuf;
+                       info->tmp_rbuf_count = framesize;
+
+                       info->icount.rxok++;
+
+                       while(copy_count) {
+                               int partial_count = min(copy_count, DMABUFSIZE);
+                               memcpy(p, info->rbufs[i].buf, partial_count);
+                               p += partial_count;
+                               copy_count -= partial_count;
+                               if (++i == info->rbuf_count)
+                                       i = 0;
+                       }
+
+#ifdef CONFIG_HDLC
+                       if (info->netcount)
+                               hdlcdev_rx(info,info->tmp_rbuf, framesize);
+                       else
+#endif
+                               ldisc_receive_buf(tty, info->tmp_rbuf, info->flag_buf, framesize);
+               }
+       }
+       free_rbufs(info, start, end);
+       rc = 1;
+
+cleanup:
+       return rc;
+}
+
+/*
+ * pass receive buffer (RAW synchronous mode) to tty layer
+ * return 1 if buffer available, otherwise 0
+ */
+static int rx_get_buf(struct slgt_info *info)
+{
+       unsigned int i = info->rbuf_current;
+
+       if (!desc_complete(info->rbufs[i]))
+               return 0;
+       DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx");
+       DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i])));
+       ldisc_receive_buf(info->tty, info->rbufs[i].buf,
+                         info->flag_buf, desc_count(info->rbufs[i]));
+       free_rbufs(info, i, i);
+       return 1;
+}
+
+static void reset_tbufs(struct slgt_info *info)
+{
+       unsigned int i;
+       info->tbuf_current = 0;
+       for (i=0 ; i < info->tbuf_count ; i++) {
+               info->tbufs[i].status = 0;
+               info->tbufs[i].count  = 0;
+       }
+}
+
+/*
+ * return number of free transmit DMA buffers
+ */
+static unsigned int free_tbuf_count(struct slgt_info *info)
+{
+       unsigned int count = 0;
+       unsigned int i = info->tbuf_current;
+
+       do
+       {
+               if (desc_count(info->tbufs[i]))
+                       break; /* buffer in use */
+               ++count;
+               if (++i == info->tbuf_count)
+                       i=0;
+       } while (i != info->tbuf_current);
+
+       /* last buffer with zero count may be in use, assume it is */
+       if (count)
+               --count;
+
+       return count;
+}
+
+/*
+ * load transmit DMA buffer(s) with data
+ */
+static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
+{
+       unsigned short count;
+       unsigned int i;
+       struct slgt_desc *d;
+
+       if (size == 0)
+               return;
+
+       DBGDATA(info, buf, size, "tx");
+
+       info->tbuf_start = i = info->tbuf_current;
+
+       while (size) {
+               d = &info->tbufs[i];
+               if (++i == info->tbuf_count)
+                       i = 0;
+
+               count = (unsigned short)((size > DMABUFSIZE) ? DMABUFSIZE : size);
+               memcpy(d->buf, buf, count);
+
+               size -= count;
+               buf  += count;
+
+               if (!size && info->params.mode != MGSL_MODE_RAW)
+                       set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */
+               else
+                       set_desc_eof(*d, 0);
+
+               set_desc_count(*d, count);
+       }
+
+       info->tbuf_current = i;
+}
+
+static int register_test(struct slgt_info *info)
+{
+       static unsigned short patterns[] =
+               {0x0000, 0xffff, 0xaaaa, 0x5555, 0x6969, 0x9696};
+       static unsigned int count = sizeof(patterns)/sizeof(patterns[0]);
+       unsigned int i;
+       int rc = 0;
+
+       for (i=0 ; i < count ; i++) {
+               wr_reg16(info, TIR, patterns[i]);
+               wr_reg16(info, BDR, patterns[(i+1)%count]);
+               if ((rd_reg16(info, TIR) != patterns[i]) ||
+                   (rd_reg16(info, BDR) != patterns[(i+1)%count])) {
+                       rc = -ENODEV;
+                       break;
+               }
+       }
+
+       info->init_error = rc ? 0 : DiagStatus_AddressFailure;
+       return rc;
+}
+
+static int irq_test(struct slgt_info *info)
+{
+       unsigned long timeout;
+       unsigned long flags;
+       struct tty_struct *oldtty = info->tty;
+       u32 speed = info->params.data_rate;
+
+       info->params.data_rate = 921600;
+       info->tty = NULL;
+
+       spin_lock_irqsave(&info->lock, flags);
+       async_mode(info);
+       slgt_irq_on(info, IRQ_TXIDLE);
+
+       /* enable transmitter */
+       wr_reg16(info, TCR,
+               (unsigned short)(rd_reg16(info, TCR) | BIT1));
+
+       /* write one byte and wait for tx idle */
+       wr_reg16(info, TDR, 0);
+
+       /* assume failure */
+       info->init_error = DiagStatus_IrqFailure;
+       info->irq_occurred = FALSE;
+
+       spin_unlock_irqrestore(&info->lock, flags);
+
+       timeout=100;
+       while(timeout-- && !info->irq_occurred)
+               msleep_interruptible(10);
+
+       spin_lock_irqsave(&info->lock,flags);
+       reset_port(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       info->params.data_rate = speed;
+       info->tty = oldtty;
+
+       info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure;
+       return info->irq_occurred ? 0 : -ENODEV;
+}
+
+static int loopback_test_rx(struct slgt_info *info)
+{
+       unsigned char *src, *dest;
+       int count;
+
+       if (desc_complete(info->rbufs[0])) {
+               count = desc_count(info->rbufs[0]);
+               src   = info->rbufs[0].buf;
+               dest  = info->tmp_rbuf;
+
+               for( ; count ; count-=2, src+=2) {
+                       /* src=data byte (src+1)=status byte */
+                       if (!(*(src+1) & (BIT9 + BIT8))) {
+                               *dest = *src;
+                               dest++;
+                               info->tmp_rbuf_count++;
+                       }
+               }
+               DBGDATA(info, info->tmp_rbuf, info->tmp_rbuf_count, "rx");
+               return 1;
+       }
+       return 0;
+}
+
+static int loopback_test(struct slgt_info *info)
+{
+#define TESTFRAMESIZE 20
+
+       unsigned long timeout;
+       u16 count = TESTFRAMESIZE;
+       unsigned char buf[TESTFRAMESIZE];
+       int rc = -ENODEV;
+       unsigned long flags;
+
+       struct tty_struct *oldtty = info->tty;
+       MGSL_PARAMS params;
+
+       memcpy(&params, &info->params, sizeof(params));
+
+       info->params.mode = MGSL_MODE_ASYNC;
+       info->params.data_rate = 921600;
+       info->params.loopback = 1;
+       info->tty = NULL;
+
+       /* build and send transmit frame */
+       for (count = 0; count < TESTFRAMESIZE; ++count)
+               buf[count] = (unsigned char)count;
+
+       info->tmp_rbuf_count = 0;
+       memset(info->tmp_rbuf, 0, TESTFRAMESIZE);
+
+       /* program hardware for HDLC and enabled receiver */
+       spin_lock_irqsave(&info->lock,flags);
+       async_mode(info);
+       rx_start(info);
+       info->tx_count = count;
+       tx_load(info, buf, count);
+       tx_start(info);
+       spin_unlock_irqrestore(&info->lock, flags);
+
+       /* wait for receive complete */
+       for (timeout = 100; timeout; --timeout) {
+               msleep_interruptible(10);
+               if (loopback_test_rx(info)) {
+                       rc = 0;
+                       break;
+               }
+       }
+
+       /* verify received frame length and contents */
+       if (!rc && (info->tmp_rbuf_count != count ||
+                 memcmp(buf, info->tmp_rbuf, count))) {
+               rc = -ENODEV;
+       }
+
+       spin_lock_irqsave(&info->lock,flags);
+       reset_adapter(info);
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       memcpy(&info->params, &params, sizeof(info->params));
+       info->tty = oldtty;
+
+       info->init_error = rc ? DiagStatus_DmaFailure : 0;
+       return rc;
+}
+
+static int adapter_test(struct slgt_info *info)
+{
+       DBGINFO(("testing %s\n", info->device_name));
+       if ((info->init_error = register_test(info)) < 0) {
+               printk("register test failure %s addr=%08X\n",
+                       info->device_name, info->phys_reg_addr);
+       } else if ((info->init_error = irq_test(info)) < 0) {
+               printk("IRQ test failure %s IRQ=%d\n",
+                       info->device_name, info->irq_level);
+       } else if ((info->init_error = loopback_test(info)) < 0) {
+               printk("loopback test failure %s\n", info->device_name);
+       }
+       return info->init_error;
+}
+
+/*
+ * transmit timeout handler
+ */
+static void tx_timeout(unsigned long context)
+{
+       struct slgt_info *info = (struct slgt_info*)context;
+       unsigned long flags;
+
+       DBGINFO(("%s tx_timeout\n", info->device_name));
+       if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
+               info->icount.txtimeout++;
+       }
+       spin_lock_irqsave(&info->lock,flags);
+       info->tx_active = 0;
+       info->tx_count = 0;
+       spin_unlock_irqrestore(&info->lock,flags);
+
+#ifdef CONFIG_HDLC
+       if (info->netcount)
+               hdlcdev_tx_done(info);
+       else
+#endif
+               bh_transmit(info);
+}
+
+/*
+ * receive buffer polling timer
+ */
+static void rx_timeout(unsigned long context)
+{
+       struct slgt_info *info = (struct slgt_info*)context;
+       unsigned long flags;
+
+       DBGINFO(("%s rx_timeout\n", info->device_name));
+       spin_lock_irqsave(&info->lock, flags);
+       info->pending_bh |= BH_RECEIVE;
+       spin_unlock_irqrestore(&info->lock, flags);
+       bh_handler(info);
+}
+
index 2392e404e8d11520995a7110ad70dec8d7a80683..ba4582d160fd6081a852f57aa4d8abff8779f663 100644 (file)
@@ -2,6 +2,9 @@
 # Makefile for the kernel tpm device drivers.
 #
 obj-$(CONFIG_TCG_TPM) += tpm.o
+ifdef CONFIG_ACPI
+       obj-$(CONFIG_TCG_TPM) += tpm_bios.o
+endif
 obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
 obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
 obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
index a9be0e8eaea5dedc243af90cedb18d645537d612..5a3870477ef182ddb815ab196fa321b93c42872a 100644 (file)
@@ -466,6 +466,7 @@ void tpm_remove_hardware(struct device *dev)
        kfree(chip->vendor->miscdev.name);
 
        sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
+       tpm_bios_log_teardown(chip->bios_dir);
 
        dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &=
                ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
@@ -593,6 +594,8 @@ dev_num_search_complete:
 
        sysfs_create_group(&dev->kobj, chip->vendor->attr_group);
 
+       chip->bios_dir = tpm_bios_log_setup(devname);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_register_hardware);
index 159882ca69dd03bdd18ce991b9b01428c48ee4be..fd3a4beaa53d941adcc4d0bfab0932354fa0b8d2 100644 (file)
@@ -82,6 +82,8 @@ struct tpm_chip {
 
        struct tpm_vendor_specific *vendor;
 
+       struct dentry **bios_dir;
+
        struct list_head list;
 };
 
@@ -107,3 +109,16 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
 extern void tpm_remove_hardware(struct device *);
 extern int tpm_pm_suspend(struct device *, pm_message_t);
 extern int tpm_pm_resume(struct device *);
+
+#ifdef CONFIG_ACPI
+extern struct dentry ** tpm_bios_log_setup(char *);
+extern void tpm_bios_log_teardown(struct dentry **);
+#else
+static inline struct dentry* tpm_bios_log_setup(char *name)
+{
+       return NULL;
+}
+static inline void tpm_bios_log_teardown(struct dentry **dir)
+{
+}
+#endif
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
new file mode 100644 (file)
index 0000000..aedf7a8
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ *     Seiji Munetoh <munetoh@jp.ibm.com>
+ *     Stefan Berger <stefanb@us.ibm.com>
+ *     Reiner Sailer <sailer@watson.ibm.com>
+ *     Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Access to the eventlog extended by the TCG BIOS of PC platform
+ *
+ * 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/seq_file.h>
+#include <linux/fs.h>
+#include <linux/security.h>
+#include <linux/module.h>
+#include <acpi/acpi.h>
+#include <acpi/actypes.h>
+#include <acpi/actbl.h>
+#include "tpm.h"
+
+#define TCG_EVENT_NAME_LEN_MAX 255
+#define MAX_TEXT_EVENT         1000    /* Max event string length */
+#define ACPI_TCPA_SIG          "TCPA"  /* 0x41504354 /'TCPA' */
+
+struct tpm_bios_log {
+       void *bios_event_log;
+       void *bios_event_log_end;
+};
+
+struct acpi_tcpa {
+       struct acpi_table_header hdr;
+       u16 reserved;
+       u32 log_max_len __attribute__ ((packed));
+       u32 log_start_addr __attribute__ ((packed));
+};
+
+struct tcpa_event {
+       u32 pcr_index;
+       u32 event_type;
+       u8 pcr_value[20];       /* SHA1 */
+       u32 event_size;
+       u8 event_data[0];
+};
+
+enum tcpa_event_types {
+       PREBOOT = 0,
+       POST_CODE,
+       UNUSED,
+       NO_ACTION,
+       SEPARATOR,
+       ACTION,
+       EVENT_TAG,
+       SCRTM_CONTENTS,
+       SCRTM_VERSION,
+       CPU_MICROCODE,
+       PLATFORM_CONFIG_FLAGS,
+       TABLE_OF_DEVICES,
+       COMPACT_HASH,
+       IPL,
+       IPL_PARTITION_DATA,
+       NONHOST_CODE,
+       NONHOST_CONFIG,
+       NONHOST_INFO,
+};
+
+static const char* tcpa_event_type_strings[] = {
+       "PREBOOT",
+       "POST CODE",
+       "",
+       "NO ACTION",
+       "SEPARATOR",
+       "ACTION",
+       "EVENT TAG",
+       "S-CRTM Contents",
+       "S-CRTM Version",
+       "CPU Microcode",
+       "Platform Config Flags",
+       "Table of Devices",
+       "Compact Hash",
+       "IPL",
+       "IPL Partition Data",
+       "Non-Host Code",
+       "Non-Host Config",
+       "Non-Host Info"
+};
+
+enum tcpa_pc_event_ids {
+       SMBIOS = 1,
+       BIS_CERT,
+       POST_BIOS_ROM,
+       ESCD,
+       CMOS,
+       NVRAM,
+       OPTION_ROM_EXEC,
+       OPTION_ROM_CONFIG,
+       OPTION_ROM_MICROCODE,
+       S_CRTM_VERSION,
+       S_CRTM_CONTENTS,
+       POST_CONTENTS,
+};
+
+static const char* tcpa_pc_event_id_strings[] = {
+       ""
+       "SMBIOS",
+       "BIS Certificate",
+       "POST BIOS ",
+       "ESCD ",
+       "CMOS",
+       "NVRAM",
+       "Option ROM",
+       "Option ROM config",
+       "Option ROM microcode",
+       "S-CRTM Version",
+       "S-CRTM Contents",
+       "S-CRTM POST Contents",
+};
+
+/* returns pointer to start of pos. entry of tcg log */
+static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
+{
+       loff_t i;
+       struct tpm_bios_log *log = m->private;
+       void *addr = log->bios_event_log;
+       void *limit = log->bios_event_log_end;
+       struct tcpa_event *event;
+
+       /* read over *pos measurements */
+       for (i = 0; i < *pos; i++) {
+               event = addr;
+
+               if ((addr + sizeof(struct tcpa_event)) < limit) {
+                       if (event->event_type == 0 && event->event_size == 0)
+                               return NULL;
+                       addr += sizeof(struct tcpa_event) + event->event_size;
+               }
+       }
+
+       /* now check if current entry is valid */
+       if ((addr + sizeof(struct tcpa_event)) >= limit)
+               return NULL;
+
+       event = addr;
+
+       if ((event->event_type == 0 && event->event_size == 0) ||
+           ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
+               return NULL;
+
+       return addr;
+}
+
+static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
+                                       loff_t *pos)
+{
+       struct tcpa_event *event = v;
+       struct tpm_bios_log *log = m->private;
+       void *limit = log->bios_event_log_end;
+
+       v += sizeof(struct tcpa_event) + event->event_size;
+
+       /* now check if current entry is valid */
+       if ((v + sizeof(struct tcpa_event)) >= limit)
+               return NULL;
+
+       event = v;
+
+       if (event->event_type == 0 && event->event_size == 0)
+               return NULL;
+
+       if ((event->event_type == 0 && event->event_size == 0) ||
+           ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
+               return NULL;
+
+       (*pos)++;
+       return v;
+}
+
+static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+static int get_event_name(char *dest, struct tcpa_event *event,
+                       unsigned char * event_entry)
+{
+       const char *name = "";
+       char data[40] = "";
+       int i, n_len = 0, d_len = 0;
+       u32 event_id, event_data_size;
+
+       switch(event->event_type) {
+       case PREBOOT:
+       case POST_CODE:
+       case UNUSED:
+       case NO_ACTION:
+       case SCRTM_CONTENTS:
+       case SCRTM_VERSION:
+       case CPU_MICROCODE:
+       case PLATFORM_CONFIG_FLAGS:
+       case TABLE_OF_DEVICES:
+       case COMPACT_HASH:
+       case IPL:
+       case IPL_PARTITION_DATA:
+       case NONHOST_CODE:
+       case NONHOST_CONFIG:
+       case NONHOST_INFO:
+               name = tcpa_event_type_strings[event->event_type];
+               n_len = strlen(name);
+               break;
+       case SEPARATOR:
+       case ACTION:
+               if (MAX_TEXT_EVENT > event->event_size) {
+                       name = event_entry;
+                       n_len = event->event_size;
+               }
+               break;
+       case EVENT_TAG:
+               event_id = be32_to_cpu(event_entry);
+               event_data_size = be32_to_cpu(&event_entry[4]);
+
+               /* ToDo Row data -> Base64 */
+
+               switch (event_id) {
+               case SMBIOS:
+               case BIS_CERT:
+               case CMOS:
+               case NVRAM:
+               case OPTION_ROM_EXEC:
+               case OPTION_ROM_CONFIG:
+               case OPTION_ROM_MICROCODE:
+               case S_CRTM_VERSION:
+               case S_CRTM_CONTENTS:
+               case POST_CONTENTS:
+                       name = tcpa_pc_event_id_strings[event_id];
+                       n_len = strlen(name);
+                       break;
+               case POST_BIOS_ROM:
+               case ESCD:
+                       name = tcpa_pc_event_id_strings[event_id];
+                       n_len = strlen(name);
+                       for (i = 0; i < 20; i++)
+                               d_len += sprintf(data, "%02x",
+                                               event_entry[8 + i]);
+                       break;
+               default:
+                       break;
+               }
+       default:
+               break;
+       }
+
+       return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
+                       n_len, name, d_len, data);
+
+}
+
+static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
+{
+
+       char *eventname;
+       char data[4];
+       u32 help;
+       int i, len;
+       struct tcpa_event *event = (struct tcpa_event *) v;
+       unsigned char *event_entry =
+           (unsigned char *) (v + sizeof(struct tcpa_event));
+
+       eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
+       if (!eventname) {
+               printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
+                      __func__);
+               return -ENOMEM;
+       }
+
+       /* 1st: PCR used is in little-endian format (4 bytes) */
+       help = le32_to_cpu(event->pcr_index);
+       memcpy(data, &help, 4);
+       for (i = 0; i < 4; i++)
+               seq_putc(m, data[i]);
+
+       /* 2nd: SHA1 (20 bytes) */
+       for (i = 0; i < 20; i++)
+               seq_putc(m, event->pcr_value[i]);
+
+       /* 3rd: event type identifier (4 bytes) */
+       help = le32_to_cpu(event->event_type);
+       memcpy(data, &help, 4);
+       for (i = 0; i < 4; i++)
+               seq_putc(m, data[i]);
+
+       len = 0;
+
+       len += get_event_name(eventname, event, event_entry);
+
+       /* 4th:  filename <= 255 + \'0' delimiter */
+       if (len > TCG_EVENT_NAME_LEN_MAX)
+               len = TCG_EVENT_NAME_LEN_MAX;
+
+       for (i = 0; i < len; i++)
+               seq_putc(m, eventname[i]);
+
+       /* 5th: delimiter */
+       seq_putc(m, '\0');
+
+       return 0;
+}
+
+static int tpm_bios_measurements_release(struct inode *inode,
+                                        struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+       struct tpm_bios_log *log = seq->private;
+
+       if (log) {
+               kfree(log->bios_event_log);
+               kfree(log);
+       }
+
+       return seq_release(inode, file);
+}
+
+static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
+{
+       int len = 0;
+       int i;
+       char *eventname;
+       struct tcpa_event *event = v;
+       unsigned char *event_entry =
+           (unsigned char *) (v + sizeof(struct tcpa_event));
+
+       eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
+       if (!eventname) {
+               printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
+                      __func__);
+               return -EFAULT;
+       }
+
+       seq_printf(m, "%2d ", event->pcr_index);
+
+       /* 2nd: SHA1 */
+       for (i = 0; i < 20; i++)
+               seq_printf(m, "%02x", event->pcr_value[i]);
+
+       /* 3rd: event type identifier */
+       seq_printf(m, " %02x", event->event_type);
+
+       len += get_event_name(eventname, event, event_entry);
+
+       /* 4th: eventname <= max + \'0' delimiter */
+       seq_printf(m, " %s\n", eventname);
+
+       return 0;
+}
+
+static struct seq_operations tpm_ascii_b_measurments_seqops = {
+       .start = tpm_bios_measurements_start,
+       .next = tpm_bios_measurements_next,
+       .stop = tpm_bios_measurements_stop,
+       .show = tpm_ascii_bios_measurements_show,
+};
+
+static struct seq_operations tpm_binary_b_measurments_seqops = {
+       .start = tpm_bios_measurements_start,
+       .next = tpm_bios_measurements_next,
+       .stop = tpm_bios_measurements_stop,
+       .show = tpm_binary_bios_measurements_show,
+};
+
+/* read binary bios log */
+static int read_log(struct tpm_bios_log *log)
+{
+       struct acpi_tcpa *buff;
+       acpi_status status;
+       void *virt;
+
+       if (log->bios_event_log != NULL) {
+               printk(KERN_ERR
+                      "%s: ERROR - Eventlog already initialized\n",
+                      __func__);
+               return -EFAULT;
+       }
+
+       /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
+       status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
+                                        ACPI_LOGICAL_ADDRESSING,
+                                        (struct acpi_table_header **)
+                                        &buff);
+
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
+                      __func__);
+               return -EIO;
+       }
+
+       if (buff->log_max_len == 0) {
+               printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
+               return -EIO;
+       }
+
+       /* malloc EventLog space */
+       log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL);
+       if (!log->bios_event_log) {
+               printk
+                   ("%s: ERROR - Not enough  Memory for BIOS measurements\n",
+                    __func__);
+               return -ENOMEM;
+       }
+
+       log->bios_event_log_end = log->bios_event_log + buff->log_max_len;
+
+       acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, &virt);
+
+       memcpy(log->bios_event_log, virt, buff->log_max_len);
+
+       acpi_os_unmap_memory(virt, buff->log_max_len);
+       return 0;
+}
+
+static int tpm_ascii_bios_measurements_open(struct inode *inode,
+                                           struct file *file)
+{
+       int err;
+       struct tpm_bios_log *log;
+       struct seq_file *seq;
+
+       log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
+       if (!log)
+               return -ENOMEM;
+
+       if ((err = read_log(log)))
+               return err;
+
+       /* now register seq file */
+       err = seq_open(file, &tpm_ascii_b_measurments_seqops);
+       if (!err) {
+               seq = file->private_data;
+               seq->private = log;
+       } else {
+               kfree(log->bios_event_log);
+               kfree(log);
+       }
+       return err;
+}
+
+struct file_operations tpm_ascii_bios_measurements_ops = {
+       .open = tpm_ascii_bios_measurements_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = tpm_bios_measurements_release,
+};
+
+static int tpm_binary_bios_measurements_open(struct inode *inode,
+                                            struct file *file)
+{
+       int err;
+       struct tpm_bios_log *log;
+       struct seq_file *seq;
+
+       log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
+       if (!log)
+               return -ENOMEM;
+
+       if ((err = read_log(log)))
+               return err;
+
+       /* now register seq file */
+       err = seq_open(file, &tpm_binary_b_measurments_seqops);
+       if (!err) {
+               seq = file->private_data;
+               seq->private = log;
+       } else {
+               kfree(log->bios_event_log);
+               kfree(log);
+       }
+       return err;
+}
+
+struct file_operations tpm_binary_bios_measurements_ops = {
+       .open = tpm_binary_bios_measurements_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = tpm_bios_measurements_release,
+};
+
+struct dentry **tpm_bios_log_setup(char *name)
+{
+       struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
+
+       tpm_dir = securityfs_create_dir(name, NULL);
+       if (!tpm_dir)
+               goto out;
+
+       bin_file =
+           securityfs_create_file("binary_bios_measurements",
+                                  S_IRUSR | S_IRGRP, tpm_dir, NULL,
+                                  &tpm_binary_bios_measurements_ops);
+       if (!bin_file)
+               goto out_tpm;
+
+       ascii_file =
+           securityfs_create_file("ascii_bios_measurements",
+                                  S_IRUSR | S_IRGRP, tpm_dir, NULL,
+                                  &tpm_ascii_bios_measurements_ops);
+       if (!ascii_file)
+               goto out_bin;
+
+       ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
+       if (!ret)
+               goto out_ascii;
+
+       ret[0] = ascii_file;
+       ret[1] = bin_file;
+       ret[2] = tpm_dir;
+
+       return ret;
+
+out_ascii:
+       securityfs_remove(ascii_file);
+out_bin:
+       securityfs_remove(bin_file);
+out_tpm:
+       securityfs_remove(tpm_dir);
+out:
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
+
+void tpm_bios_log_teardown(struct dentry **lst)
+{
+       int i;
+
+       for (i = 0; i < 3; i++)
+               securityfs_remove(lst[i]);
+}
+EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
index 9ac6d43437b3cb6b1e4aa27529c11b79c77298fb..a5b18e086a9467f8a36053456aaacd1c308a9ee0 100644 (file)
@@ -718,7 +718,7 @@ static struct platform_driver giu_device_driver = {
        },
 };
 
-static int __devinit vr41xx_giu_init(void)
+static int __init vr41xx_giu_init(void)
 {
        int retval;
 
@@ -733,7 +733,7 @@ static int __devinit vr41xx_giu_init(void)
        return retval;
 }
 
-static void __devexit vr41xx_giu_exit(void)
+static void __exit vr41xx_giu_exit(void)
 {
        platform_driver_unregister(&giu_device_driver);
 
index 56d62ba7c6ce37218a6f3fbc3604f30acf24682d..b2fc71e20850191abc640b901ae63bb51184fb74 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/watchdog.h>
 #include <asm/8xx_immap.h>
 #include <asm/uaccess.h>
+#include <asm/io.h>
 #include <syslib/m8xx_wdt.h>
 
 static unsigned long wdt_opened;
@@ -25,18 +26,26 @@ static int wdt_status;
 
 static void mpc8xx_wdt_handler_disable(void)
 {
-       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+       volatile uint __iomem *piscr;
+       piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
 
-       imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
+       if (!m8xx_has_internal_rtc)
+               m8xx_wdt_stop_timer();
+       else
+               out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
 
        printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
 }
 
 static void mpc8xx_wdt_handler_enable(void)
 {
-       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+       volatile uint __iomem *piscr;
+       piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
 
-       imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
+       if (!m8xx_has_internal_rtc)
+               m8xx_wdt_install_timer();
+       else
+               out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
 
        printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
 }
@@ -68,9 +77,6 @@ static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
 static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
                                loff_t * ppos)
 {
-       if (ppos != &file->f_pos)
-               return -ESPIPE;
-
        if (len)
                m8xx_wdt_reset();
 
index 44d49dfacbb36db7d6d7dd14cafd586b611d77ea..3843900e94c49f8101364828f8d8bdeb656987b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     Wdt977  0.03:   A Watchdog Device for Netwinder W83977AF chip
+ *     Wdt977  0.04:   A Watchdog Device for Netwinder W83977AF chip
  *
  *     (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
  *
@@ -18,6 +18,8 @@
  *                                 from minutes to seconds.
  *      07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
  *                                    nwwatchdog_init.
+ *      25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks
+ *                                 remove limitiation to be used on Netwinders only
  */
 
 #include <linux/module.h>
@@ -28,6 +30,7 @@
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 #include <linux/watchdog.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
 
-#define PFX "Wdt977: "
-#define WATCHDOG_MINOR 130
+#define WATCHDOG_VERSION  "0.04"
+#define WATCHDOG_NAME     "Wdt977"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+
+#define IO_INDEX_PORT  0x370           /* on some systems it can be 0x3F0 */
+#define IO_DATA_PORT   (IO_INDEX_PORT+1)
+
+#define UNLOCK_DATA    0x87
+#define LOCK_DATA      0xAA
+#define DEVICE_REGISTER        0x07
+
 
 #define        DEFAULT_TIMEOUT 60                      /* default timeout in seconds */
 
@@ -47,6 +60,7 @@ static        int timeoutM;                           /* timeout in minutes */
 static unsigned long timer_alive;
 static int testmode;
 static char expect_close;
+static spinlock_t spinlock;
 
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
@@ -63,9 +77,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
 
 static int wdt977_start(void)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
        /* unlock the SuperIO chip */
-       outb(0x87,0x370);
-       outb(0x87,0x370);
+       outb_p(UNLOCK_DATA, IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA, IO_INDEX_PORT);
 
        /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
         * F2 has the timeout in minutes
@@ -73,28 +91,29 @@ static int wdt977_start(void)
         *   at timeout, and to reset timer on kbd/mouse activity (not impl.)
         * F4 is used to just clear the TIMEOUT'ed state (bit 0)
         */
-       outb(0x07,0x370);
-       outb(0x08,0x371);
-       outb(0xF2,0x370);
-       outb(timeoutM,0x371);
-       outb(0xF3,0x370);
-       outb(0x00,0x371);       /* another setting is 0E for kbd/mouse/LED */
-       outb(0xF4,0x370);
-       outb(0x00,0x371);
+       outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+       outb_p(0x08, IO_DATA_PORT);
+       outb_p(0xF2, IO_INDEX_PORT);
+       outb_p(timeoutM, IO_DATA_PORT);
+       outb_p(0xF3, IO_INDEX_PORT);
+       outb_p(0x00, IO_DATA_PORT);     /* another setting is 0E for kbd/mouse/LED */
+       outb_p(0xF4, IO_INDEX_PORT);
+       outb_p(0x00, IO_DATA_PORT);
 
        /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
        /* in test mode watch the bit 1 on F4 to indicate "triggered" */
        if (!testmode)
        {
-               outb(0x07,0x370);
-               outb(0x07,0x371);
-               outb(0xE6,0x370);
-               outb(0x08,0x371);
+               outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+               outb_p(0x07, IO_DATA_PORT);
+               outb_p(0xE6, IO_INDEX_PORT);
+               outb_p(0x08, IO_DATA_PORT);
        }
 
        /* lock the SuperIO chip */
-       outb(0xAA,0x370);
+       outb_p(LOCK_DATA, IO_INDEX_PORT);
 
+       spin_unlock_irqrestore(&spinlock, flags);
        printk(KERN_INFO PFX "activated.\n");
 
        return 0;
@@ -106,35 +125,39 @@ static int wdt977_start(void)
 
 static int wdt977_stop(void)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&spinlock, flags);
+
        /* unlock the SuperIO chip */
-       outb(0x87,0x370);
-       outb(0x87,0x370);
+       outb_p(UNLOCK_DATA, IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA, IO_INDEX_PORT);
 
        /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
        * F3 is reset to its default state
        * F4 can clear the TIMEOUT'ed state (bit 0) - back to default
        * We can not use GP17 as a PowerLed, as we use its usage as a RedLed
        */
-       outb(0x07,0x370);
-       outb(0x08,0x371);
-       outb(0xF2,0x370);
-       outb(0xFF,0x371);
-       outb(0xF3,0x370);
-       outb(0x00,0x371);
-       outb(0xF4,0x370);
-       outb(0x00,0x371);
-       outb(0xF2,0x370);
-       outb(0x00,0x371);
+       outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+       outb_p(0x08, IO_DATA_PORT);
+       outb_p(0xF2, IO_INDEX_PORT);
+       outb_p(0xFF, IO_DATA_PORT);
+       outb_p(0xF3, IO_INDEX_PORT);
+       outb_p(0x00, IO_DATA_PORT);
+       outb_p(0xF4, IO_INDEX_PORT);
+       outb_p(0x00, IO_DATA_PORT);
+       outb_p(0xF2, IO_INDEX_PORT);
+       outb_p(0x00, IO_DATA_PORT);
 
        /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
-       outb(0x07,0x370);
-       outb(0x07,0x371);
-       outb(0xE6,0x370);
-       outb(0x08,0x371);
+       outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+       outb_p(0x07, IO_DATA_PORT);
+       outb_p(0xE6, IO_INDEX_PORT);
+       outb_p(0x08, IO_DATA_PORT);
 
        /* lock the SuperIO chip */
-       outb(0xAA,0x370);
+       outb_p(LOCK_DATA, IO_INDEX_PORT);
 
+       spin_unlock_irqrestore(&spinlock, flags);
        printk(KERN_INFO PFX "shutdown.\n");
 
        return 0;
@@ -147,19 +170,23 @@ static int wdt977_stop(void)
 
 static int wdt977_keepalive(void)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&spinlock, flags);
+
        /* unlock the SuperIO chip */
-       outb(0x87,0x370);
-       outb(0x87,0x370);
+       outb_p(UNLOCK_DATA, IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA, IO_INDEX_PORT);
 
        /* select device Aux2 (device=8) and kicks watchdog reg F2 */
        /* F2 has the timeout in minutes */
-       outb(0x07,0x370);
-       outb(0x08,0x371);
-       outb(0xF2,0x370);
-       outb(timeoutM,0x371);
+       outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+       outb_p(0x08, IO_DATA_PORT);
+       outb_p(0xF2, IO_INDEX_PORT);
+       outb_p(timeoutM, IO_DATA_PORT);
 
        /* lock the SuperIO chip */
-       outb(0xAA,0x370);
+       outb_p(LOCK_DATA, IO_INDEX_PORT);
+       spin_unlock_irqrestore(&spinlock, flags);
 
        return 0;
 }
@@ -198,22 +225,26 @@ static int wdt977_set_timeout(int t)
 static int wdt977_get_status(int *status)
 {
        int new_status;
+       unsigned long flags;
 
-       *status=0;
+       spin_lock_irqsave(&spinlock, flags);
 
        /* unlock the SuperIO chip */
-       outb(0x87,0x370);
-       outb(0x87,0x370);
+       outb_p(UNLOCK_DATA, IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA, IO_INDEX_PORT);
 
        /* select device Aux2 (device=8) and read watchdog reg F4 */
-       outb(0x07,0x370);
-       outb(0x08,0x371);
-       outb(0xF4,0x370);
-       new_status = inb(0x371);
+       outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+       outb_p(0x08, IO_DATA_PORT);
+       outb_p(0xF4, IO_INDEX_PORT);
+       new_status = inb_p(IO_DATA_PORT);
 
        /* lock the SuperIO chip */
-       outb(0xAA,0x370);
+       outb_p(LOCK_DATA, IO_INDEX_PORT);
 
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       *status=0;
        if (new_status & 1)
                *status |= WDIOF_CARDRESET;
 
@@ -249,8 +280,8 @@ static int wdt977_release(struct inode *inode, struct file *file)
                wdt977_stop();
                clear_bit(0,&timer_alive);
        } else {
-               printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
                wdt977_keepalive();
+               printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
        }
        expect_close = 0;
        return 0;
@@ -271,14 +302,17 @@ static int wdt977_release(struct inode *inode, struct file *file)
 static ssize_t wdt977_write(struct file *file, const char __user *buf,
                            size_t count, loff_t *ppos)
 {
-       if (count) {
-               if (!nowayout) {
+       if (count)
+       {
+               if (!nowayout)
+               {
                        size_t i;
 
                        /* In case it was set long ago */
                        expect_close = 0;
 
-                       for (i = 0; i != count; i++) {
+                       for (i = 0; i != count; i++)
+                       {
                                char c;
                                if (get_user(c, buf + i))
                                        return -EFAULT;
@@ -287,6 +321,7 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf,
                        }
                }
 
+               /* someone wrote to us, we should restart timer */
                wdt977_keepalive();
        }
        return count;
@@ -308,7 +343,7 @@ static struct watchdog_info ident = {
                                WDIOF_MAGICCLOSE |
                                WDIOF_KEEPALIVEPING,
        .firmware_version =     1,
-       .identity =             "Winbond 83977",
+       .identity =             WATCHDOG_NAME,
 };
 
 static int wdt977_ioctl(struct inode *inode, struct file *file,
@@ -405,50 +440,81 @@ static struct notifier_block wdt977_notifier = {
        .notifier_call = wdt977_notify_sys,
 };
 
-static int __init nwwatchdog_init(void)
+static int __init wd977_init(void)
 {
-       int retval;
-       if (!machine_is_netwinder())
-               return -ENODEV;
+       int rc;
+
+       //if (!machine_is_netwinder())
+       //      return -ENODEV;
+
+       printk(KERN_INFO PFX DRIVER_VERSION);
+
+       spin_lock_init(&spinlock);
 
        /* Check that the timeout value is within it's range ; if not reset to the default */
-       if (wdt977_set_timeout(timeout)) {
+       if (wdt977_set_timeout(timeout))
+       {
                wdt977_set_timeout(DEFAULT_TIMEOUT);
                printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
                        DEFAULT_TIMEOUT);
        }
 
-       retval = register_reboot_notifier(&wdt977_notifier);
-       if (retval) {
-               printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-                       retval);
-               return retval;
+       /* on Netwinder the IOports are already reserved by
+        * arch/arm/mach-footbridge/netwinder-hw.c
+        */
+       if (!machine_is_netwinder())
+       {
+               if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
+               {
+                       printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+                               IO_INDEX_PORT);
+                       rc = -EIO;
+                       goto err_out;
+               }
        }
 
-       retval = misc_register(&wdt977_miscdev);
-       if (retval) {
+       rc = misc_register(&wdt977_miscdev);
+       if (rc)
+       {
                printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, retval);
-               unregister_reboot_notifier(&wdt977_notifier);
-               return retval;
+                       wdt977_miscdev.minor, rc);
+               goto err_out_region;
+       }
+
+       rc = register_reboot_notifier(&wdt977_notifier);
+       if (rc)
+       {
+               printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+                       rc);
+               goto err_out_miscdev;
        }
 
-       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode = %i)\n",
+       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
                timeout, nowayout, testmode);
 
        return 0;
+
+err_out_miscdev:
+        misc_deregister(&wdt977_miscdev);
+err_out_region:
+       if (!machine_is_netwinder())
+               release_region(IO_INDEX_PORT,2);
+err_out:
+       return rc;
 }
 
-static void __exit nwwatchdog_exit(void)
+static void __exit wd977_exit(void)
 {
+       wdt977_stop();
        misc_deregister(&wdt977_miscdev);
        unregister_reboot_notifier(&wdt977_notifier);
+       release_region(IO_INDEX_PORT,2);
 }
 
-module_init(nwwatchdog_init);
-module_exit(nwwatchdog_exit);
+module_init(wd977_init);
+module_exit(wd977_exit);
 
-MODULE_AUTHOR("Woody Suwalski <woody@netwinder.org>");
+MODULE_AUTHOR("Woody Suwalski <woodys@xandros.com>");
 MODULE_DESCRIPTION("W83977AF Watchdog driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 969d2b4aaec06952132d9fc4f516355bcdc38d3b..385e52930c02353a396df4009f0a421f2cecf1d5 100644 (file)
 static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);
 static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
 
-/* proc_counts is used as the sequence number of the netlink message */
+/* proc_event_counts is used as the sequence number of the netlink message */
 static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
 
 static inline void get_seq(__u32 *ts, int *cpu)
 {
        *ts = get_cpu_var(proc_event_counts)++;
        *cpu = smp_processor_id();
-       put_cpu_var(proc_counts);
+       put_cpu_var(proc_event_counts);
 }
 
 void proc_fork_connector(struct task_struct *task)
index 4010fe92e72b637f6c138813a82c15c744b79ba3..08d5b8fed2dc5f3440526110d9d5b13106a04174 100644 (file)
@@ -236,27 +236,17 @@ config I2C_IXP2000
          This support is also available as a module. If so, the module
          will be called i2c-ixp2000.
 
-config I2C_KEYWEST
-       tristate "Powermac Keywest I2C interface"
+config I2C_POWERMAC
+       tristate "Powermac I2C interface"
        depends on I2C && PPC_PMAC
+       default y
        help
-         This supports the use of the I2C interface in the combo-I/O
-         chip on recent Apple machines.  Say Y if you have such a machine.
-
-         This support is also available as a module.  If so, the module 
-         will be called i2c-keywest.
-
-config I2C_PMAC_SMU
-       tristate "Powermac SMU I2C interface"
-       depends on I2C && PMAC_SMU
-       help
-         This supports the use of the I2C interface in the SMU
-         chip on recent Apple machines like the iMac G5.  It is used
-         among others by the thermal control driver for those machines.
-         Say Y if you have such a machine.
+         This exposes the various PowerMac i2c interfaces to the linux i2c
+         layer and to userland. It is used by various drivers on the powemac
+         platform, thus should generally be enabled.
 
          This support is also available as a module.  If so, the module
-         will be called i2c-pmac-smu.
+         will be called i2c-powermac.
 
 config I2C_MPC
        tristate "MPC107/824x/85xx/52xx"
index f1df00f66c6cde856f188126fa1e4ab3a4ea2a5d..b44831dff6833a19e8c4f638b97eed0f1fa78905 100644 (file)
@@ -19,8 +19,7 @@ obj-$(CONFIG_I2C_ISA)         += i2c-isa.o
 obj-$(CONFIG_I2C_ITE)          += i2c-ite.o
 obj-$(CONFIG_I2C_IXP2000)      += i2c-ixp2000.o
 obj-$(CONFIG_I2C_IXP4XX)       += i2c-ixp4xx.o
-obj-$(CONFIG_I2C_KEYWEST)      += i2c-keywest.o
-obj-$(CONFIG_I2C_PMAC_SMU)     += i2c-pmac-smu.o
+obj-$(CONFIG_I2C_POWERMAC)     += i2c-powermac.o
 obj-$(CONFIG_I2C_MPC)          += i2c-mpc.o
 obj-$(CONFIG_I2C_MV64XXX)      += i2c-mv64xxx.o
 obj-$(CONFIG_I2C_NFORCE2)      += i2c-nforce2.o
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
deleted file mode 100644 (file)
index d61f748..0000000
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
-    i2c Support for Apple Keywest I2C Bus Controller
-
-    Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
-
-    Original work by
-    
-    Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Changes:
-
-    2001/12/13 BenH    New implementation
-    2001/12/15 BenH    Add support for "byte" and "quick"
-                        transfers. Add i2c_xfer routine.
-    2003/09/21 BenH    Rework state machine with Paulus help
-    2004/01/21 BenH    Merge in Greg KH changes, polled mode is back
-    2004/02/05 BenH    Merge 64 bits fixes from the g5 ppc64 tree
-
-    My understanding of the various modes supported by keywest are:
-
-     - Dumb mode : not implemented, probably direct tweaking of lines
-     - Standard mode : simple i2c transaction of type
-         S Addr R/W A Data A Data ... T
-     - Standard sub mode : combined 8 bit subaddr write with data read
-         S Addr R/W A SubAddr A Data A Data ... T
-     - Combined mode : Subaddress and Data sequences appended with no stop
-         S Addr R/W A SubAddr S Addr R/W A Data A Data ... T
-
-    Currently, this driver uses only Standard mode for i2c xfer, and
-    smbus byte & quick transfers ; and uses StandardSub mode for
-    other smbus transfers instead of combined as we need that for the
-    sound driver to be happy
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pmac_low_i2c.h>
-
-#include "i2c-keywest.h"
-
-#undef POLLED_MODE
-
-/* Some debug macros */
-#define WRONG_STATE(name) do {\
-               pr_debug("KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
-                        name, __kw_state_names[iface->state], isr);    \
-       } while(0)
-
-#ifdef DEBUG
-static const char *__kw_state_names[] = {
-       "state_idle",
-       "state_addr",
-       "state_read",
-       "state_write",
-       "state_stop",
-       "state_dead"
-};
-#endif /* DEBUG */
-
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
-MODULE_LICENSE("GPL");
-
-#ifdef POLLED_MODE
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8
-wait_interrupt(struct keywest_iface* iface)
-{
-       int i;
-       u8 isr;
-       
-       for (i = 0; i < 200000; i++) {
-               isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK;
-               if (isr != 0)
-                       return isr;
-               udelay(10);
-       }
-       return isr;
-}
-#endif /* POLLED_MODE */
-
-static void
-do_stop(struct keywest_iface* iface, int result)
-{
-       write_reg(reg_control, KW_I2C_CTL_STOP);
-       iface->state = state_stop;
-       iface->result = result;
-}
-
-/* Main state machine for standard & standard sub mode */
-static void
-handle_interrupt(struct keywest_iface *iface, u8 isr)
-{
-       int ack;
-       
-       if (isr == 0) {
-               if (iface->state != state_stop) {
-                       pr_debug("KW: Timeout !\n");
-                       do_stop(iface, -EIO);
-               }
-               if (iface->state == state_stop) {
-                       ack = read_reg(reg_status);
-                       if (!(ack & KW_I2C_STAT_BUSY)) {
-                               iface->state = state_idle;
-                               write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
-                               complete(&iface->complete);
-#endif /* POLLED_MODE */
-                       }
-               }
-               return;
-       }
-
-       if (isr & KW_I2C_IRQ_ADDR) {
-               ack = read_reg(reg_status);
-               if (iface->state != state_addr) {
-                       write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-                       WRONG_STATE("KW_I2C_IRQ_ADDR"); 
-                       do_stop(iface, -EIO);
-                       return;
-               }
-               if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-                       iface->state = state_stop;                   
-                       iface->result = -ENODEV;
-                       pr_debug("KW: NAK on address\n");
-               } else {
-                       /* Handle rw "quick" mode */
-                       if (iface->datalen == 0) {
-                               do_stop(iface, 0);
-                       } else if (iface->read_write == I2C_SMBUS_READ) {
-                               iface->state = state_read;
-                               if (iface->datalen > 1)
-                                       write_reg(reg_control, KW_I2C_CTL_AAK);
-                       } else {
-                               iface->state = state_write;
-                               write_reg(reg_data, *(iface->data++));
-                               iface->datalen--;
-                       }
-               }
-               write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-       }
-
-       if (isr & KW_I2C_IRQ_DATA) {
-               if (iface->state == state_read) {
-                       *(iface->data++) = read_reg(reg_data);
-                       write_reg(reg_isr, KW_I2C_IRQ_DATA);
-                       iface->datalen--;
-                       if (iface->datalen == 0)
-                               iface->state = state_stop;
-                       else if (iface->datalen == 1)
-                               write_reg(reg_control, 0);
-               } else if (iface->state == state_write) {
-                       /* Check ack status */
-                       ack = read_reg(reg_status);
-                       if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-                               pr_debug("KW: nack on data write (%x): %x\n",
-                                   iface->data[-1], ack);
-                               do_stop(iface, -EIO);
-                       } else if (iface->datalen) {
-                               write_reg(reg_data, *(iface->data++));
-                               iface->datalen--;
-                       } else {
-                               write_reg(reg_control, KW_I2C_CTL_STOP);
-                               iface->state = state_stop;
-                               iface->result = 0;
-                       }
-                       write_reg(reg_isr, KW_I2C_IRQ_DATA);
-               } else {
-                       write_reg(reg_isr, KW_I2C_IRQ_DATA);
-                       WRONG_STATE("KW_I2C_IRQ_DATA"); 
-                       if (iface->state != state_stop)
-                               do_stop(iface, -EIO);
-               }
-       }
-
-       if (isr & KW_I2C_IRQ_STOP) {
-               write_reg(reg_isr, KW_I2C_IRQ_STOP);
-               if (iface->state != state_stop) {
-                       WRONG_STATE("KW_I2C_IRQ_STOP");
-                       iface->result = -EIO;
-               }
-               iface->state = state_idle;
-               write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
-               complete(&iface->complete);
-#endif /* POLLED_MODE */                       
-       }
-
-       if (isr & KW_I2C_IRQ_START)
-               write_reg(reg_isr, KW_I2C_IRQ_START);
-}
-
-#ifndef POLLED_MODE
-
-/* Interrupt handler */
-static irqreturn_t
-keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-       struct keywest_iface *iface = (struct keywest_iface *)dev_id;
-       unsigned long flags;
-
-       spin_lock_irqsave(&iface->lock, flags);
-       del_timer(&iface->timeout_timer);
-       handle_interrupt(iface, read_reg(reg_isr));
-       if (iface->state != state_idle) {
-               iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-               add_timer(&iface->timeout_timer);
-       }
-       spin_unlock_irqrestore(&iface->lock, flags);
-       return IRQ_HANDLED;
-}
-
-static void
-keywest_timeout(unsigned long data)
-{
-       struct keywest_iface *iface = (struct keywest_iface *)data;
-       unsigned long flags;
-
-       pr_debug("timeout !\n");
-       spin_lock_irqsave(&iface->lock, flags);
-       handle_interrupt(iface, read_reg(reg_isr));
-       if (iface->state != state_idle) {
-               iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-               add_timer(&iface->timeout_timer);
-       }
-       spin_unlock_irqrestore(&iface->lock, flags);
-}
-
-#endif /* POLLED_MODE */
-
-/*
- * SMBUS-type transfer entrypoint
- */
-static s32
-keywest_smbus_xfer(    struct i2c_adapter*     adap,
-                       u16                     addr,
-                       unsigned short          flags,
-                       char                    read_write,
-                       u8                      command,
-                       int                     size,
-                       union i2c_smbus_data*   data)
-{
-       struct keywest_chan* chan = i2c_get_adapdata(adap);
-       struct keywest_iface* iface = chan->iface;
-       int len;
-       u8* buffer;
-       u16 cur_word;
-       int rc = 0;
-
-       if (iface->state == state_dead)
-               return -ENXIO;
-               
-       /* Prepare datas & select mode */
-       iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
-       switch (size) {
-        case I2C_SMBUS_QUICK:
-               len = 0;
-               buffer = NULL;
-               iface->cur_mode |= KW_I2C_MODE_STANDARD;
-               break;
-        case I2C_SMBUS_BYTE:
-               len = 1;
-               buffer = &data->byte;
-               iface->cur_mode |= KW_I2C_MODE_STANDARD;
-               break;
-        case I2C_SMBUS_BYTE_DATA:
-               len = 1;
-               buffer = &data->byte;
-               iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
-               break;
-        case I2C_SMBUS_WORD_DATA:
-               len = 2;
-               cur_word = cpu_to_le16(data->word);
-               buffer = (u8 *)&cur_word;
-               iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
-               break;
-        case I2C_SMBUS_BLOCK_DATA:
-               len = data->block[0];
-               buffer = &data->block[1];
-               iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
-               break;
-        default:
-               return -1;
-       }
-
-       /* Turn a standardsub read into a combined mode access */
-       if (read_write == I2C_SMBUS_READ
-           && (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB) {
-               iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
-               iface->cur_mode |= KW_I2C_MODE_COMBINED;
-       }
-
-       /* Original driver had this limitation */
-       if (len > 32)
-               len = 32;
-
-       if (pmac_low_i2c_lock(iface->node))
-               return -ENXIO;
-
-       pr_debug("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n",
-               chan->chan_no, addr, len, read_write == I2C_SMBUS_READ);
-
-       iface->data = buffer;
-       iface->datalen = len;
-       iface->state = state_addr;
-       iface->result = 0;
-       iface->read_write = read_write;
-       
-       /* Setup channel & clear pending irqs */
-       write_reg(reg_isr, read_reg(reg_isr));
-       write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
-       write_reg(reg_status, 0);
-
-       /* Set up address and r/w bit */
-       write_reg(reg_addr,
-               (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
-       /* Set up the sub address */
-       if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
-           || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
-               write_reg(reg_subaddr, command);
-
-#ifndef POLLED_MODE
-       /* Arm timeout */
-       iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-       add_timer(&iface->timeout_timer);
-#endif
-
-       /* Start sending address & enable interrupt*/
-       write_reg(reg_control, KW_I2C_CTL_XADDR);
-       write_reg(reg_ier, KW_I2C_IRQ_MASK);
-
-#ifdef POLLED_MODE
-       pr_debug("using polled mode...\n");
-       /* State machine, to turn into an interrupt handler */
-       while(iface->state != state_idle) {
-               unsigned long flags;
-
-               u8 isr = wait_interrupt(iface);
-               spin_lock_irqsave(&iface->lock, flags);
-               handle_interrupt(iface, isr);
-               spin_unlock_irqrestore(&iface->lock, flags);
-       }
-#else /* POLLED_MODE */
-       pr_debug("using interrupt mode...\n");
-       wait_for_completion(&iface->complete);  
-#endif /* POLLED_MODE */       
-
-       rc = iface->result;     
-       pr_debug("transfer done, result: %d\n", rc);
-
-       if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ)
-               data->word = le16_to_cpu(cur_word);
-       
-       /* Release sem */
-       pmac_low_i2c_unlock(iface->node);
-       
-       return rc;
-}
-
-/*
- * Generic i2c master transfer entrypoint
- */
-static int
-keywest_xfer(  struct i2c_adapter *adap,
-               struct i2c_msg *msgs, 
-               int num)
-{
-       struct keywest_chan* chan = i2c_get_adapdata(adap);
-       struct keywest_iface* iface = chan->iface;
-       struct i2c_msg *pmsg;
-       int i, completed;
-       int rc = 0;
-
-       if (iface->state == state_dead)
-               return -ENXIO;
-
-       if (pmac_low_i2c_lock(iface->node))
-               return -ENXIO;
-
-       /* Set adapter to standard mode */
-       iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
-       iface->cur_mode |= KW_I2C_MODE_STANDARD;
-
-       completed = 0;
-       for (i = 0; rc >= 0 && i < num;) {
-               u8 addr;
-               
-               pmsg = &msgs[i++];
-               addr = pmsg->addr;
-               if (pmsg->flags & I2C_M_TEN) {
-                       printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n");
-                       rc = -EINVAL;
-                       break;
-               }
-               pr_debug("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n",
-                    chan->chan_no,
-                    pmsg->flags & I2C_M_RD ? "read" : "write",
-                     pmsg->len, addr, i, num);
-    
-               /* Setup channel & clear pending irqs */
-               write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
-               write_reg(reg_isr, read_reg(reg_isr));
-               write_reg(reg_status, 0);
-               
-               iface->data = pmsg->buf;
-               iface->datalen = pmsg->len;
-               iface->state = state_addr;
-               iface->result = 0;
-               if (pmsg->flags & I2C_M_RD)
-                       iface->read_write = I2C_SMBUS_READ;
-               else
-                       iface->read_write = I2C_SMBUS_WRITE;
-
-               /* Set up address and r/w bit */
-               if (pmsg->flags & I2C_M_REV_DIR_ADDR)
-                       addr ^= 1;              
-               write_reg(reg_addr,
-                       (addr << 1) |
-                       ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
-#ifndef POLLED_MODE
-               /* Arm timeout */
-               iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-               add_timer(&iface->timeout_timer);
-#endif
-
-               /* Start sending address & enable interrupt*/
-               write_reg(reg_ier, KW_I2C_IRQ_MASK);
-               write_reg(reg_control, KW_I2C_CTL_XADDR);
-
-#ifdef POLLED_MODE
-               pr_debug("using polled mode...\n");
-               /* State machine, to turn into an interrupt handler */
-               while(iface->state != state_idle) {
-                       u8 isr = wait_interrupt(iface);
-                       handle_interrupt(iface, isr);
-               }
-#else /* POLLED_MODE */
-               pr_debug("using interrupt mode...\n");
-               wait_for_completion(&iface->complete);  
-#endif /* POLLED_MODE */       
-
-               rc = iface->result;
-               if (rc == 0)
-                       completed++;
-               pr_debug("transfer done, result: %d\n", rc);
-       }
-
-       /* Release sem */
-       pmac_low_i2c_unlock(iface->node);
-
-       return completed;
-}
-
-static u32
-keywest_func(struct i2c_adapter * adapter)
-{
-       return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-              I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-              I2C_FUNC_SMBUS_BLOCK_DATA;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm keywest_algorithm = {
-       .smbus_xfer     = keywest_smbus_xfer,
-       .master_xfer    = keywest_xfer,
-       .functionality  = keywest_func,
-};
-
-
-static int
-create_iface(struct device_node *np, struct device *dev)
-{
-       unsigned long steps;
-       unsigned bsteps, tsize, i, nchan, addroffset;
-       struct keywest_iface* iface;
-       u32 *psteps, *prate;
-       int rc;
-
-       if (np->n_intrs < 1 || np->n_addrs < 1) {
-               printk(KERN_ERR "%s: Missing interrupt or address !\n",
-                      np->full_name);
-               return -ENODEV;
-       }
-       if (pmac_low_i2c_lock(np))
-               return -ENODEV;
-
-       psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
-       steps = psteps ? (*psteps) : 0x10;
-
-       /* Hrm... maybe we can be smarter here */
-       for (bsteps = 0; (steps & 0x01) == 0; bsteps++)
-               steps >>= 1;
-
-       if (np->parent->name[0] == 'u') {
-               nchan = 2;
-               addroffset = 3;
-       } else {
-               addroffset = 0;
-               nchan = 1;
-       }
-
-       tsize = sizeof(struct keywest_iface) +
-               (sizeof(struct keywest_chan) + 4) * nchan;
-       iface = kzalloc(tsize, GFP_KERNEL);
-       if (iface == NULL) {
-               printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n");
-               pmac_low_i2c_unlock(np);
-               return -ENOMEM;
-       }
-       spin_lock_init(&iface->lock);
-       init_completion(&iface->complete);
-       iface->node = of_node_get(np);
-       iface->bsteps = bsteps;
-       iface->chan_count = nchan;
-       iface->state = state_idle;
-       iface->irq = np->intrs[0].line;
-       iface->channels = (struct keywest_chan *)
-               (((unsigned long)(iface + 1) + 3UL) & ~3UL);
-       iface->base = ioremap(np->addrs[0].address + addroffset,
-                                               np->addrs[0].size);
-       if (!iface->base) {
-               printk(KERN_ERR "i2c-keywest: can't map inteface !\n");
-               kfree(iface);
-               pmac_low_i2c_unlock(np);
-               return -ENOMEM;
-       }
-
-#ifndef POLLED_MODE
-       init_timer(&iface->timeout_timer);
-       iface->timeout_timer.function = keywest_timeout;
-       iface->timeout_timer.data = (unsigned long)iface;
-#endif
-
-       /* Select interface rate */
-       iface->cur_mode = KW_I2C_MODE_100KHZ;
-       prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
-       if (prate) switch(*prate) {
-       case 100:
-               iface->cur_mode = KW_I2C_MODE_100KHZ;
-               break;
-       case 50:
-               iface->cur_mode = KW_I2C_MODE_50KHZ;
-               break;
-       case 25:
-               iface->cur_mode = KW_I2C_MODE_25KHZ;
-               break;
-       default:
-               printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n",
-                      (long)*prate);
-       }
-       
-       /* Select standard mode by default */
-       iface->cur_mode |= KW_I2C_MODE_STANDARD;
-       
-       /* Write mode */
-       write_reg(reg_mode, iface->cur_mode);
-       
-       /* Switch interrupts off & clear them*/
-       write_reg(reg_ier, 0x00);
-       write_reg(reg_isr, KW_I2C_IRQ_MASK);
-
-#ifndef POLLED_MODE
-       /* Request chip interrupt */    
-       rc = request_irq(iface->irq, keywest_irq, SA_INTERRUPT, "keywest i2c", iface);
-       if (rc) {
-               printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq);
-               iounmap(iface->base);
-               kfree(iface);
-               pmac_low_i2c_unlock(np);
-               return -ENODEV;
-       }
-#endif /* POLLED_MODE */
-
-       pmac_low_i2c_unlock(np);
-       dev_set_drvdata(dev, iface);
-       
-       for (i=0; i<nchan; i++) {
-               struct keywest_chan* chan = &iface->channels[i];
-               
-               sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
-               chan->iface = iface;
-               chan->chan_no = i;
-               chan->adapter.algo = &keywest_algorithm;
-               chan->adapter.algo_data = NULL;
-               chan->adapter.client_register = NULL;
-               chan->adapter.client_unregister = NULL;
-               i2c_set_adapdata(&chan->adapter, chan);
-               chan->adapter.dev.parent = dev;
-
-               rc = i2c_add_adapter(&chan->adapter);
-               if (rc) {
-                       printk("i2c-keywest.c: Adapter %s registration failed\n",
-                               chan->adapter.name);
-                       i2c_set_adapdata(&chan->adapter, NULL);
-               }
-       }
-
-       printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
-               np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps);
-               
-       return 0;
-}
-
-static int
-dispose_iface(struct device *dev)
-{
-       struct keywest_iface *iface = dev_get_drvdata(dev);
-       int i, rc;
-       
-       /* Make sure we stop all activity */
-       if (pmac_low_i2c_lock(iface->node))
-               return -ENODEV;
-
-#ifndef POLLED_MODE
-       spin_lock_irq(&iface->lock);
-       while (iface->state != state_idle) {
-               spin_unlock_irq(&iface->lock);
-               msleep(100);
-               spin_lock_irq(&iface->lock);
-       }
-#endif /* POLLED_MODE */
-       iface->state = state_dead;
-#ifndef POLLED_MODE
-       spin_unlock_irq(&iface->lock);
-       free_irq(iface->irq, iface);
-#endif /* POLLED_MODE */
-
-       pmac_low_i2c_unlock(iface->node);
-
-       /* Release all channels */
-       for (i=0; i<iface->chan_count; i++) {
-               struct keywest_chan* chan = &iface->channels[i];
-               if (i2c_get_adapdata(&chan->adapter) == NULL)
-                       continue;
-               rc = i2c_del_adapter(&chan->adapter);
-               i2c_set_adapdata(&chan->adapter, NULL);
-               /* We aren't that prepared to deal with this... */
-               if (rc)
-                       printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n");
-       }
-       iounmap(iface->base);
-       dev_set_drvdata(dev, NULL);
-       of_node_put(iface->node);
-       kfree(iface);
-
-       return 0;
-}
-
-static int
-create_iface_macio(struct macio_dev* dev, const struct of_device_id *match)
-{
-       return create_iface(dev->ofdev.node, &dev->ofdev.dev);
-}
-
-static int
-dispose_iface_macio(struct macio_dev* dev)
-{
-       return dispose_iface(&dev->ofdev.dev);
-}
-
-static int
-create_iface_of_platform(struct of_device* dev, const struct of_device_id *match)
-{
-       return create_iface(dev->node, &dev->dev);
-}
-
-static int
-dispose_iface_of_platform(struct of_device* dev)
-{
-       return dispose_iface(&dev->dev);
-}
-
-static struct of_device_id i2c_keywest_match[] = 
-{
-       {
-       .type           = "i2c",
-       .compatible     = "keywest"
-       },
-       {},
-};
-
-static struct macio_driver i2c_keywest_macio_driver = 
-{
-       .owner          = THIS_MODULE,
-       .name           = "i2c-keywest",
-       .match_table    = i2c_keywest_match,
-       .probe          = create_iface_macio,
-       .remove         = dispose_iface_macio
-};
-
-static struct of_platform_driver i2c_keywest_of_platform_driver = 
-{
-       .owner          = THIS_MODULE,
-       .name           = "i2c-keywest",
-       .match_table    = i2c_keywest_match,
-       .probe          = create_iface_of_platform,
-       .remove         = dispose_iface_of_platform
-};
-
-static int __init
-i2c_keywest_init(void)
-{
-       of_register_driver(&i2c_keywest_of_platform_driver);
-       macio_register_driver(&i2c_keywest_macio_driver);
-
-       return 0;
-}
-
-static void __exit
-i2c_keywest_cleanup(void)
-{
-       of_unregister_driver(&i2c_keywest_of_platform_driver);
-       macio_unregister_driver(&i2c_keywest_macio_driver);
-}
-
-module_init(i2c_keywest_init);
-module_exit(i2c_keywest_cleanup);
diff --git a/drivers/i2c/busses/i2c-keywest.h b/drivers/i2c/busses/i2c-keywest.h
deleted file mode 100644 (file)
index c5022e1..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef __I2C_KEYWEST_H__
-#define __I2C_KEYWEST_H__
-
-/* The Tumbler audio equalizer can be really slow sometimes */
-#define POLL_TIMEOUT           (2*HZ)
-
-/* Register indices */
-typedef enum {
-       reg_mode = 0,
-       reg_control,
-       reg_status,
-       reg_isr,
-       reg_ier,
-       reg_addr,
-       reg_subaddr,
-       reg_data
-} reg_t;
-
-
-/* Mode register */
-#define KW_I2C_MODE_100KHZ     0x00
-#define KW_I2C_MODE_50KHZ      0x01
-#define KW_I2C_MODE_25KHZ      0x02
-#define KW_I2C_MODE_DUMB       0x00
-#define KW_I2C_MODE_STANDARD   0x04
-#define KW_I2C_MODE_STANDARDSUB        0x08
-#define KW_I2C_MODE_COMBINED   0x0C
-#define KW_I2C_MODE_MODE_MASK  0x0C
-#define KW_I2C_MODE_CHAN_MASK  0xF0
-
-/* Control register */
-#define KW_I2C_CTL_AAK         0x01
-#define KW_I2C_CTL_XADDR       0x02
-#define KW_I2C_CTL_STOP                0x04
-#define KW_I2C_CTL_START       0x08
-
-/* Status register */
-#define KW_I2C_STAT_BUSY       0x01
-#define KW_I2C_STAT_LAST_AAK   0x02
-#define KW_I2C_STAT_LAST_RW    0x04
-#define KW_I2C_STAT_SDA                0x08
-#define KW_I2C_STAT_SCL                0x10
-
-/* IER & ISR registers */
-#define KW_I2C_IRQ_DATA                0x01
-#define KW_I2C_IRQ_ADDR                0x02
-#define KW_I2C_IRQ_STOP                0x04
-#define KW_I2C_IRQ_START       0x08
-#define KW_I2C_IRQ_MASK                0x0F
-
-/* Physical interface */
-struct keywest_iface
-{
-       struct device_node      *node;
-       void __iomem *          base;
-       unsigned                bsteps;
-       int                     irq;
-       spinlock_t              lock;
-       struct keywest_chan     *channels;
-       unsigned                chan_count;
-       u8                      cur_mode;
-       char                    read_write;
-       u8                      *data;
-       unsigned                datalen;
-       int                     state;
-       int                     result;
-       struct timer_list       timeout_timer;
-       struct completion       complete;
-};
-
-enum {
-       state_idle,
-       state_addr,
-       state_read,
-       state_write,
-       state_stop,
-       state_dead
-};
-
-/* Channel on an interface */
-struct keywest_chan
-{
-       struct i2c_adapter      adapter;
-       struct keywest_iface*   iface;
-       unsigned                chan_no;
-};
-
-/* Register access */
-
-static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg)
-{
-       return in_8(iface->base
-               + (((unsigned)reg) << iface->bsteps));
-}
-
-static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val)
-{
-       out_8(iface->base
-               + (((unsigned)reg) << iface->bsteps), val);
-       (void)__read_reg(iface, reg_subaddr);
-}
-
-#define write_reg(reg, val)    __write_reg(iface, reg, val) 
-#define read_reg(reg)          __read_reg(iface, reg) 
-
-
-
-#endif /* __I2C_KEYWEST_H__ */
diff --git a/drivers/i2c/busses/i2c-pmac-smu.c b/drivers/i2c/busses/i2c-pmac-smu.c
deleted file mode 100644 (file)
index bfefe7f..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
-    i2c Support for Apple SMU Controller
-
-    Copyright (c) 2005 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.
-
-    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/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/smu.h>
-
-static int probe;
-
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("I2C driver for Apple's SMU");
-MODULE_LICENSE("GPL");
-module_param(probe, bool, 0);
-
-
-/* Physical interface */
-struct smu_iface
-{
-       struct i2c_adapter      adapter;
-       struct completion       complete;
-       u32                     busid;
-};
-
-static void smu_i2c_done(struct smu_i2c_cmd *cmd, void *misc)
-{
-       struct smu_iface        *iface = misc;
-       complete(&iface->complete);
-}
-
-/*
- * SMBUS-type transfer entrypoint
- */
-static s32 smu_smbus_xfer(     struct i2c_adapter*     adap,
-                               u16                     addr,
-                               unsigned short          flags,
-                               char                    read_write,
-                               u8                      command,
-                               int                     size,
-                               union i2c_smbus_data*   data)
-{
-       struct smu_iface        *iface = i2c_get_adapdata(adap);
-       struct smu_i2c_cmd      cmd;
-       int                     rc = 0;
-       int                     read = (read_write == I2C_SMBUS_READ);
-
-       cmd.info.bus = iface->busid;
-       cmd.info.devaddr = (addr << 1) | (read ? 0x01 : 0x00);
-
-       /* Prepare datas & select mode */
-       switch (size) {
-        case I2C_SMBUS_QUICK:
-               cmd.info.type = SMU_I2C_TRANSFER_SIMPLE;
-               cmd.info.datalen = 0;
-               break;
-        case I2C_SMBUS_BYTE:
-               cmd.info.type = SMU_I2C_TRANSFER_SIMPLE;
-               cmd.info.datalen = 1;
-               if (!read)
-                       cmd.info.data[0] = data->byte;
-               break;
-        case I2C_SMBUS_BYTE_DATA:
-               cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
-               cmd.info.datalen = 1;
-               cmd.info.sublen = 1;
-               cmd.info.subaddr[0] = command;
-               cmd.info.subaddr[1] = 0;
-               cmd.info.subaddr[2] = 0;
-               if (!read)
-                       cmd.info.data[0] = data->byte;
-               break;
-        case I2C_SMBUS_WORD_DATA:
-               cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
-               cmd.info.datalen = 2;
-               cmd.info.sublen = 1;
-               cmd.info.subaddr[0] = command;
-               cmd.info.subaddr[1] = 0;
-               cmd.info.subaddr[2] = 0;
-               if (!read) {
-                       cmd.info.data[0] = data->byte & 0xff;
-                       cmd.info.data[1] = (data->byte >> 8) & 0xff;
-               }
-               break;
-       /* Note that these are broken vs. the expected smbus API where
-        * on reads, the lenght is actually returned from the function,
-        * but I think the current API makes no sense and I don't want
-        * any driver that I haven't verified for correctness to go
-        * anywhere near a pmac i2c bus anyway ...
-        */
-        case I2C_SMBUS_BLOCK_DATA:
-               cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
-               cmd.info.datalen = data->block[0] + 1;
-               if (cmd.info.datalen > 6)
-                       return -EINVAL;
-               if (!read)
-                       memcpy(cmd.info.data, data->block, cmd.info.datalen);
-               cmd.info.sublen = 1;
-               cmd.info.subaddr[0] = command;
-               cmd.info.subaddr[1] = 0;
-               cmd.info.subaddr[2] = 0;
-               break;
-       case I2C_SMBUS_I2C_BLOCK_DATA:
-               cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
-               cmd.info.datalen = data->block[0];
-               if (cmd.info.datalen > 7)
-                       return -EINVAL;
-               if (!read)
-                       memcpy(cmd.info.data, &data->block[1],
-                              cmd.info.datalen);
-               cmd.info.sublen = 1;
-               cmd.info.subaddr[0] = command;
-               cmd.info.subaddr[1] = 0;
-               cmd.info.subaddr[2] = 0;
-               break;
-
-        default:
-               return -EINVAL;
-       }
-
-       /* Turn a standardsub read into a combined mode access */
-       if (read_write == I2C_SMBUS_READ &&
-           cmd.info.type == SMU_I2C_TRANSFER_STDSUB)
-               cmd.info.type = SMU_I2C_TRANSFER_COMBINED;
-
-       /* Finish filling command and submit it */
-       cmd.done = smu_i2c_done;
-       cmd.misc = iface;
-       rc = smu_queue_i2c(&cmd);
-       if (rc < 0)
-               return rc;
-       wait_for_completion(&iface->complete);
-       rc = cmd.status;
-
-       if (!read || rc < 0)
-               return rc;
-
-       switch (size) {
-        case I2C_SMBUS_BYTE:
-        case I2C_SMBUS_BYTE_DATA:
-               data->byte = cmd.info.data[0];
-               break;
-        case I2C_SMBUS_WORD_DATA:
-               data->word = ((u16)cmd.info.data[1]) << 8;
-               data->word |= cmd.info.data[0];
-               break;
-       /* Note that these are broken vs. the expected smbus API where
-        * on reads, the lenght is actually returned from the function,
-        * but I think the current API makes no sense and I don't want
-        * any driver that I haven't verified for correctness to go
-        * anywhere near a pmac i2c bus anyway ...
-        */
-        case I2C_SMBUS_BLOCK_DATA:
-       case I2C_SMBUS_I2C_BLOCK_DATA:
-               memcpy(&data->block[0], cmd.info.data, cmd.info.datalen);
-               break;
-       }
-
-       return rc;
-}
-
-static u32
-smu_smbus_func(struct i2c_adapter * adapter)
-{
-       return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-              I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-              I2C_FUNC_SMBUS_BLOCK_DATA;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm smu_algorithm = {
-       .smbus_xfer     = smu_smbus_xfer,
-       .functionality  = smu_smbus_func,
-};
-
-static int create_iface(struct device_node *np, struct device *dev)
-{
-       struct smu_iface* iface;
-       u32 *reg, busid;
-       int rc;
-
-       reg = (u32 *)get_property(np, "reg", NULL);
-       if (reg == NULL) {
-               printk(KERN_ERR "i2c-pmac-smu: can't find bus number !\n");
-               return -ENXIO;
-       }
-       busid = *reg;
-
-       iface = kzalloc(sizeof(struct smu_iface), GFP_KERNEL);
-       if (iface == NULL) {
-               printk(KERN_ERR "i2c-pmac-smu: can't allocate inteface !\n");
-               return -ENOMEM;
-       }
-       init_completion(&iface->complete);
-       iface->busid = busid;
-
-       dev_set_drvdata(dev, iface);
-
-       sprintf(iface->adapter.name, "smu-i2c-%02x", busid);
-       iface->adapter.algo = &smu_algorithm;
-       iface->adapter.algo_data = NULL;
-       iface->adapter.client_register = NULL;
-       iface->adapter.client_unregister = NULL;
-       i2c_set_adapdata(&iface->adapter, iface);
-       iface->adapter.dev.parent = dev;
-
-       rc = i2c_add_adapter(&iface->adapter);
-       if (rc) {
-               printk(KERN_ERR "i2c-pamc-smu.c: Adapter %s registration "
-                      "failed\n", iface->adapter.name);
-               i2c_set_adapdata(&iface->adapter, NULL);
-       }
-
-       if (probe) {
-               unsigned char addr;
-               printk("Probe: ");
-               for (addr = 0x00; addr <= 0x7f; addr++) {
-                       if (i2c_smbus_xfer(&iface->adapter,addr,
-                                          0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
-                               printk("%02x ", addr);
-               }
-               printk("\n");
-       }
-
-       printk(KERN_INFO "SMU i2c bus %x registered\n", busid);
-
-       return 0;
-}
-
-static int dispose_iface(struct device *dev)
-{
-       struct smu_iface *iface = dev_get_drvdata(dev);
-       int rc;
-
-       rc = i2c_del_adapter(&iface->adapter);
-       i2c_set_adapdata(&iface->adapter, NULL);
-       /* We aren't that prepared to deal with this... */
-       if (rc)
-               printk("i2c-pmac-smu.c: Failed to remove bus %s !\n",
-                      iface->adapter.name);
-       dev_set_drvdata(dev, NULL);
-       kfree(iface);
-
-       return 0;
-}
-
-
-static int create_iface_of_platform(struct of_device* dev,
-                                   const struct of_device_id *match)
-{
-       return create_iface(dev->node, &dev->dev);
-}
-
-
-static int dispose_iface_of_platform(struct of_device* dev)
-{
-       return dispose_iface(&dev->dev);
-}
-
-
-static struct of_device_id i2c_smu_match[] =
-{
-       {
-               .compatible     = "smu-i2c",
-       },
-       {},
-};
-static struct of_platform_driver i2c_smu_of_platform_driver =
-{
-       .name           = "i2c-smu",
-       .match_table    = i2c_smu_match,
-       .probe          = create_iface_of_platform,
-       .remove         = dispose_iface_of_platform
-};
-
-
-static int __init i2c_pmac_smu_init(void)
-{
-       of_register_driver(&i2c_smu_of_platform_driver);
-       return 0;
-}
-
-
-static void __exit i2c_pmac_smu_cleanup(void)
-{
-       of_unregister_driver(&i2c_smu_of_platform_driver);
-}
-
-module_init(i2c_pmac_smu_init);
-module_exit(i2c_pmac_smu_cleanup);
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
new file mode 100644 (file)
index 0000000..df786eb
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+    i2c Support for Apple SMU Controller
+
+    Copyright (c) 2005 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.
+
+    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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/pmac_low_i2c.h>
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("I2C driver for Apple PowerMac");
+MODULE_LICENSE("GPL");
+
+/*
+ * SMBUS-type transfer entrypoint
+ */
+static s32 i2c_powermac_smbus_xfer(    struct i2c_adapter*     adap,
+                                       u16                     addr,
+                                       unsigned short          flags,
+                                       char                    read_write,
+                                       u8                      command,
+                                       int                     size,
+                                       union i2c_smbus_data*   data)
+{
+       struct pmac_i2c_bus     *bus = i2c_get_adapdata(adap);
+       int                     rc = 0;
+       int                     read = (read_write == I2C_SMBUS_READ);
+       int                     addrdir = (addr << 1) | read;
+       u8                      local[2];
+
+       rc = pmac_i2c_open(bus, 0);
+       if (rc)
+               return rc;
+
+       switch (size) {
+        case I2C_SMBUS_QUICK:
+               rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+               if (rc)
+                       goto bail;
+               rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
+               break;
+        case I2C_SMBUS_BYTE:
+               rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+               if (rc)
+                       goto bail;
+               rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
+               break;
+        case I2C_SMBUS_BYTE_DATA:
+               rc = pmac_i2c_setmode(bus, read ?
+                                     pmac_i2c_mode_combined :
+                                     pmac_i2c_mode_stdsub);
+               if (rc)
+                       goto bail;
+               rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
+               break;
+        case I2C_SMBUS_WORD_DATA:
+               rc = pmac_i2c_setmode(bus, read ?
+                                     pmac_i2c_mode_combined :
+                                     pmac_i2c_mode_stdsub);
+               if (rc)
+                       goto bail;
+               if (!read) {
+                       local[0] = data->word & 0xff;
+                       local[1] = (data->word >> 8) & 0xff;
+               }
+               rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2);
+               if (rc == 0 && read) {
+                       data->word = ((u16)local[1]) << 8;
+                       data->word |= local[0];
+               }
+               break;
+
+       /* Note that these are broken vs. the expected smbus API where
+        * on reads, the lenght is actually returned from the function,
+        * but I think the current API makes no sense and I don't want
+        * any driver that I haven't verified for correctness to go
+        * anywhere near a pmac i2c bus anyway ...
+        *
+        * I'm also not completely sure what kind of phases to do between
+        * the actual command and the data (what I am _supposed_ to do that
+        * is). For now, I assume writes are a single stream and reads have
+        * a repeat start/addr phase (but not stop in between)
+        */
+        case I2C_SMBUS_BLOCK_DATA:
+               rc = pmac_i2c_setmode(bus, read ?
+                                     pmac_i2c_mode_combined :
+                                     pmac_i2c_mode_stdsub);
+               if (rc)
+                       goto bail;
+               rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
+                                  data->block[0] + 1);
+
+               break;
+       case I2C_SMBUS_I2C_BLOCK_DATA:
+               rc = pmac_i2c_setmode(bus, read ?
+                                     pmac_i2c_mode_combined :
+                                     pmac_i2c_mode_stdsub);
+               if (rc)
+                       goto bail;
+               rc = pmac_i2c_xfer(bus, addrdir, 1, command,
+                                  read ? data->block : &data->block[1],
+                                  data->block[0]);
+               break;
+
+        default:
+               rc = -EINVAL;
+       }
+ bail:
+       pmac_i2c_close(bus);
+       return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint. This driver only support single
+ * messages (for "lame i2c" transfers). Anything else should use the smbus
+ * entry point
+ */
+static int i2c_powermac_master_xfer(   struct i2c_adapter *adap,
+                                       struct i2c_msg *msgs,
+                                       int num)
+{
+       struct pmac_i2c_bus     *bus = i2c_get_adapdata(adap);
+       int                     rc = 0;
+       int                     read;
+       int                     addrdir;
+
+       if (num != 1)
+               return -EINVAL;
+       if (msgs->flags & I2C_M_TEN)
+               return -EINVAL;
+       read = (msgs->flags & I2C_M_RD) != 0;
+       addrdir = (msgs->addr << 1) | read;
+       if (msgs->flags & I2C_M_REV_DIR_ADDR)
+               addrdir ^= 1;
+
+       rc = pmac_i2c_open(bus, 0);
+       if (rc)
+               return rc;
+       rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+       if (rc)
+               goto bail;
+       rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+ bail:
+       pmac_i2c_close(bus);
+       return rc < 0 ? rc : msgs->len;
+}
+
+static u32 i2c_powermac_func(struct i2c_adapter * adapter)
+{
+       return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+               I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;
+}
+
+/* For now, we only handle smbus */
+static struct i2c_algorithm i2c_powermac_algorithm = {
+       .smbus_xfer     = i2c_powermac_smbus_xfer,
+       .master_xfer    = i2c_powermac_master_xfer,
+       .functionality  = i2c_powermac_func,
+};
+
+
+static int i2c_powermac_remove(struct device *dev)
+{
+       struct i2c_adapter      *adapter = dev_get_drvdata(dev);
+       struct pmac_i2c_bus     *bus = i2c_get_adapdata(adapter);
+       int                     rc;
+
+       rc = i2c_del_adapter(adapter);
+       pmac_i2c_detach_adapter(bus, adapter);
+       i2c_set_adapdata(adapter, NULL);
+       /* We aren't that prepared to deal with this... */
+       if (rc)
+               printk("i2c-powermac.c: Failed to remove bus %s !\n",
+                      adapter->name);
+       dev_set_drvdata(dev, NULL);
+       kfree(adapter);
+
+       return 0;
+}
+
+
+static int i2c_powermac_probe(struct device *dev)
+{
+       struct pmac_i2c_bus *bus = dev->platform_data;
+       struct device_node *parent = NULL;
+       struct i2c_adapter *adapter;
+       char name[32], *basename;
+       int rc;
+
+       if (bus == NULL)
+               return -EINVAL;
+
+       /* Ok, now we need to make up a name for the interface that will
+        * match what we used to do in the past, that is basically the
+        * controller's parent device node for keywest. PMU didn't have a
+        * naming convention and SMU has a different one
+        */
+       switch(pmac_i2c_get_type(bus)) {
+       case pmac_i2c_bus_keywest:
+               parent = of_get_parent(pmac_i2c_get_controller(bus));
+               if (parent == NULL)
+                       return -EINVAL;
+               basename = parent->name;
+               break;
+       case pmac_i2c_bus_pmu:
+               basename = "pmu";
+               break;
+       case pmac_i2c_bus_smu:
+               /* This is not what we used to do but I'm fixing drivers at
+                * the same time as this change
+                */
+               basename = "smu";
+               break;
+       default:
+               return -EINVAL;
+       }
+       snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus));
+       of_node_put(parent);
+
+       adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+       if (adapter == NULL) {
+               printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
+               return -ENOMEM;
+       }
+       dev_set_drvdata(dev, adapter);
+       strcpy(adapter->name, name);
+       adapter->algo = &i2c_powermac_algorithm;
+       i2c_set_adapdata(adapter, bus);
+       adapter->dev.parent = dev;
+       pmac_i2c_attach_adapter(bus, adapter);
+       rc = i2c_add_adapter(adapter);
+       if (rc) {
+               printk(KERN_ERR "i2c-powermac: Adapter %s registration "
+                      "failed\n", name);
+               i2c_set_adapdata(adapter, NULL);
+               pmac_i2c_detach_adapter(bus, adapter);
+       }
+
+       printk(KERN_INFO "PowerMac i2c bus %s registered\n", name);
+       return rc;
+}
+
+
+static struct device_driver i2c_powermac_driver = {
+       .name = "i2c-powermac",
+       .bus = &platform_bus_type,
+       .probe = i2c_powermac_probe,
+       .remove = i2c_powermac_remove,
+};
+
+static int __init i2c_powermac_init(void)
+{
+       driver_register(&i2c_powermac_driver);
+       return 0;
+}
+
+
+static void __exit i2c_powermac_cleanup(void)
+{
+       driver_unregister(&i2c_powermac_driver);
+}
+
+module_init(i2c_powermac_init);
+module_exit(i2c_powermac_cleanup);
index e70b3db69eddd66bf82565bbb32c2141ec1ee13e..1af3dfbb808686146b324c3ce60fcee67d0e7100 100644 (file)
@@ -494,6 +494,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
 {
        struct tps65010         *tps;
        int                     status;
+       unsigned long           irqflags;
 
        if (the_tps) {
                dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME);
@@ -520,13 +521,14 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
        }
 
 #ifdef CONFIG_ARM
+       irqflags = SA_SAMPLE_RANDOM | SA_TRIGGER_LOW;
        if (machine_is_omap_h2()) {
                tps->model = TPS65010;
                omap_cfg_reg(W4_GPIO58);
                tps->irq = OMAP_GPIO_IRQ(58);
                omap_request_gpio(58);
                omap_set_gpio_direction(58, 1);
-               set_irq_type(tps->irq, IRQT_FALLING);
+               irqflags |= SA_TRIGGER_FALLING;
        }
        if (machine_is_omap_osk()) {
                tps->model = TPS65010;
@@ -534,7 +536,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
                tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1));
                omap_request_gpio(OMAP_MPUIO(1));
                omap_set_gpio_direction(OMAP_MPUIO(1), 1);
-               set_irq_type(tps->irq, IRQT_FALLING);
+               irqflags |= SA_TRIGGER_FALLING;
        }
        if (machine_is_omap_h3()) {
                tps->model = TPS65013;
@@ -542,13 +544,12 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
                // FIXME set up this board's IRQ ...
        }
 #else
-#define set_irq_type(num,trigger)      do{}while(0)
+       irqflags = SA_SAMPLE_RANDOM;
 #endif
 
        if (tps->irq > 0) {
-               set_irq_type(tps->irq, IRQT_LOW);
                status = request_irq(tps->irq, tps65010_irq,
-                       SA_SAMPLE_RANDOM, DRIVER_NAME, tps);
+                       irqflags, DRIVER_NAME, tps);
                if (status < 0) {
                        dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n",
                                        tps->irq, status);
index d31117eb95aacfe75b42c44f05861961640d4c3f..e4d55ad32d2f49da3e2e14b0a457566f4679570c 100644 (file)
@@ -1332,8 +1332,6 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
        if (cdrom_read_from_buffer(drive))
                return ide_stopped;
 
-       blk_attempt_remerge(drive->queue, rq);
-
        /* Clear the local sector buffer. */
        info->nsectors_buffered = 0;
 
@@ -1874,14 +1872,6 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
                return ide_stopped;
        }
 
-       /*
-        * for dvd-ram and such media, it's a really big deal to get
-        * big writes all the time. so scour the queue and attempt to
-        * remerge requests, often the plugging will not have had time
-        * to do this properly
-        */
-       blk_attempt_remerge(drive->queue, rq);
-
        info->nsectors_buffered = 0;
 
        /* use dma, if possible. we don't need to check more, since we
index 4b441720b6ba94cf07599511c73ba0bbc4ff82ad..cab362ea03360a1bc4586ebec338cf2cadf74418 100644 (file)
@@ -1130,6 +1130,17 @@ static int idedisk_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
+       ide_drive_t *drive = idkp->drive;
+
+       geo->heads = drive->bios_head;
+       geo->sectors = drive->bios_sect;
+       geo->cylinders = (u16)drive->bios_cyl; /* truncate */
+       return 0;
+}
+
 static int idedisk_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
@@ -1164,6 +1175,7 @@ static struct block_device_operations idedisk_ops = {
        .open           = idedisk_open,
        .release        = idedisk_release,
        .ioctl          = idedisk_ioctl,
+       .getgeo         = idedisk_getgeo,
        .media_changed  = idedisk_media_changed,
        .revalidate_disk= idedisk_revalidate_disk
 };
index fba3fffc2d6635561e4157e311145d916053247c..5945f551aaaad493d22c05e358f2df30b06f110c 100644 (file)
@@ -2031,6 +2031,17 @@ static int idefloppy_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
+       ide_drive_t *drive = floppy->drive;
+
+       geo->heads = drive->bios_head;
+       geo->sectors = drive->bios_sect;
+       geo->cylinders = (u16)drive->bios_cyl; /* truncate */
+       return 0;
+}
+
 static int idefloppy_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
@@ -2120,6 +2131,7 @@ static struct block_device_operations idefloppy_ops = {
        .open           = idefloppy_open,
        .release        = idefloppy_release,
        .ioctl          = idefloppy_ioctl,
+       .getgeo         = idefloppy_getgeo,
        .media_changed  = idefloppy_media_changed,
        .revalidate_disk= idefloppy_revalidate_disk
 };
index b5dc6df8e67ddc8858527b95a875a2429392eee4..dea2d4dcc6981848222eb97ea0b47478dcc9df4c 100644 (file)
 #include <asm/io.h>
 #include <asm/bitops.h>
 
+void ide_softirq_done(struct request *rq)
+{
+       request_queue_t *q = rq->q;
+
+       add_disk_randomness(rq->rq_disk);
+       end_that_request_chunk(rq, rq->errors, rq->data_len);
+
+       spin_lock_irq(q->queue_lock);
+       end_that_request_last(rq, rq->errors);
+       spin_unlock_irq(q->queue_lock);
+}
+
 int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
                      int nr_sectors)
 {
+       unsigned int nbytes;
        int ret = 1;
 
        BUG_ON(!(rq->flags & REQ_STARTED));
@@ -81,17 +94,28 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
                HWGROUP(drive)->hwif->ide_dma_on(drive);
        }
 
-       if (!end_that_request_first(rq, uptodate, nr_sectors)) {
-               add_disk_randomness(rq->rq_disk);
-
-               if (blk_rq_tagged(rq))
-                       blk_queue_end_tag(drive->queue, rq);
-
+       /*
+        * For partial completions (or non fs/pc requests), use the regular
+        * direct completion path.
+        */
+       nbytes = nr_sectors << 9;
+       if (rq_all_done(rq, nbytes)) {
+               rq->errors = uptodate;
+               rq->data_len = nbytes;
                blkdev_dequeue_request(rq);
                HWGROUP(drive)->rq = NULL;
-               end_that_request_last(rq, uptodate);
+               blk_complete_request(rq);
                ret = 0;
+       } else {
+               if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+                       add_disk_randomness(rq->rq_disk);
+                       blkdev_dequeue_request(rq);
+                       HWGROUP(drive)->rq = NULL;
+                       end_that_request_last(rq, uptodate);
+                       ret = 0;
+               }
        }
+
        return ret;
 }
 EXPORT_SYMBOL(__ide_end_request);
@@ -113,6 +137,10 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
        unsigned long flags;
        int ret = 1;
 
+       /*
+        * room for locking improvements here, the calls below don't
+        * need the queue lock held at all
+        */
        spin_lock_irqsave(&ide_lock, flags);
        rq = HWGROUP(drive)->rq;
 
index 02167a5b751dbe40a0b1be304766903fceb43c52..1ddaa71a8f45c7dbd525035c017a99c2469d23f3 100644 (file)
@@ -1011,6 +1011,8 @@ static int ide_init_queue(ide_drive_t *drive)
        blk_queue_max_hw_segments(q, max_sg_entries);
        blk_queue_max_phys_segments(q, max_sg_entries);
 
+       blk_queue_softirq_done(q, ide_softirq_done);
+
        /* assign drive queue */
        drive->queue = q;
 
index 4b524f6b3ecd3e57e15bc161b013bf6b40aa33e9..b069b13b75a760ec58dc8e6c6fe7dbcbdc844452 100644 (file)
@@ -1278,19 +1278,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
        up(&ide_setting_sem);
 
        switch (cmd) {
-               case HDIO_GETGEO:
-               {
-                       struct hd_geometry geom;
-                       if (!p || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-                       geom.heads = drive->bios_head;
-                       geom.sectors = drive->bios_sect;
-                       geom.cylinders = (u16)drive->bios_cyl; /* truncate */
-                       geom.start = get_start_sect(bdev);
-                       if (copy_to_user(p, &geom, sizeof(struct hd_geometry)))
-                               return -EFAULT;
-                       return 0;
-               }
-
                case HDIO_OBSOLETE_IDENTITY:
                case HDIO_GET_IDENTITY:
                        if (bdev != bdev->bd_contains)
index 242029c9c0ca9a5e9e61b64011a3cd9dce7c31fd..6439dec66881619fc26d678a5bab544e18e06182 100644 (file)
@@ -658,22 +658,14 @@ static void do_hd_request (request_queue_t * q)
        enable_irq(HD_IRQ);
 }
 
-static int hd_ioctl(struct inode * inode, struct file * file,
-       unsigned int cmd, unsigned long arg)
+static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data;
-       struct hd_geometry __user *loc = (struct hd_geometry __user *) arg;
-       struct hd_geometry g; 
-
-       if (cmd != HDIO_GETGEO)
-               return -EINVAL;
-       if (!loc)
-               return -EINVAL;
-       g.heads = disk->head;
-       g.sectors = disk->sect;
-       g.cylinders = disk->cyl;
-       g.start = get_start_sect(inode->i_bdev);
-       return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+       struct hd_i_struct *disk = bdev->bd_disk->private_data;
+
+       geo->heads = disk->head;
+       geo->sectors = disk->sect;
+       geo->cylinders = disk->cyl;
+       return 0;
 }
 
 /*
@@ -695,7 +687,7 @@ static irqreturn_t hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 }
 
 static struct block_device_operations hd_fops = {
-       .ioctl =        hd_ioctl,
+       .getgeo =       hd_getgeo,
 };
 
 /*
index ff2e217a8c84f883b85399faca8787b099c7a492..0d3073f4eab4e3d8e55f6c34af0fadd9f262e659 100644 (file)
@@ -69,7 +69,7 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
 static u8 svwks_ratemask (ide_drive_t *drive)
 {
        struct pci_dev *dev     = HWIF(drive)->pci_dev;
-       u8 mode;
+       u8 mode = 0;
 
        if (!svwks_revision)
                pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
index 16b28357885b38e4a534ea8664dce97e7535615a..5013b1285e2242e24f8a8cf0215104c226bdffaf 100644 (file)
@@ -1271,7 +1271,7 @@ static int
 pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 {
        struct device_node *np = pmif->node;
-       int *bidp, i;
+       int *bidp;
 
        pmif->cable_80 = 0;
        pmif->broken_dma = pmif->broken_dma_warn = 0;
@@ -1430,7 +1430,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
        pmif = &pmac_ide[i];
        hwif = &ide_hwifs[i];
 
-       if (mdev->ofdev.node->n_addrs == 0) {
+       if (macio_resource_count(mdev) == 0) {
                printk(KERN_WARNING "ide%d: no address for %s\n",
                       i, mdev->ofdev.node->full_name);
                return -ENXIO;
@@ -1686,7 +1686,7 @@ pmac_ide_probe(void)
 #else
        macio_register_driver(&pmac_ide_macio_driver);
        pci_register_driver(&pmac_ide_pci_driver);
-#endif 
+#endif
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
index 02110e00d145bdf09c6f706914ed24571ecb65ec..3a611fe5497e06c0b9e2de2cc9eaf75d2abf0caa 100644 (file)
@@ -308,10 +308,11 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv)
 {
        unsigned long flags;
        int ret;
+       static int next_id;
 
        do {
                spin_lock_irqsave(&cm.lock, flags);
-               ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, 1,
+               ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id++,
                                        (__force int *) &cm_id_priv->id.local_id);
                spin_unlock_irqrestore(&cm.lock, flags);
        } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );
@@ -684,6 +685,13 @@ retest:
                cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT);
                break;
        case IB_CM_REQ_SENT:
+               ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+               ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,
+                              &cm_id_priv->av.port->cm_dev->ca_guid,
+                              sizeof cm_id_priv->av.port->cm_dev->ca_guid,
+                              NULL, 0);
+               break;
        case IB_CM_MRA_REQ_RCVD:
        case IB_CM_REP_SENT:
        case IB_CM_MRA_REP_RCVD:
@@ -694,10 +702,8 @@ retest:
        case IB_CM_REP_RCVD:
        case IB_CM_MRA_REP_SENT:
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,
-                              &cm_id_priv->av.port->cm_dev->ca_guid,
-                              sizeof cm_id_priv->av.port->cm_dev->ca_guid,
-                              NULL, 0);
+               ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
+                              NULL, 0, NULL, 0);
                break;
        case IB_CM_ESTABLISHED:
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
index eb7f52537ccc9c41faa51d787ecd9b0a73cec894..c908de8db5a9b1201e825684039dca3bd75dd55f 100644 (file)
@@ -197,8 +197,8 @@ static void send_handler(struct ib_mad_agent *agent,
                memcpy(timeout->mad.data, packet->mad.data,
                       sizeof (struct ib_mad_hdr));
 
-               if (!queue_packet(file, agent, timeout))
-                               return;
+               if (queue_packet(file, agent, timeout))
+                       kfree(timeout);
        }
 out:
        kfree(packet);
index a57d021d435ae2d4f0a694c134d643d2836582c7..a02c5a05c984f7931310de1fca427265efc3e05b 100644 (file)
@@ -489,6 +489,7 @@ err_idr:
 
 err_unreg:
        ib_dereg_mr(mr);
+       atomic_dec(&pd->usecnt);
 
 err_up:
        up(&ib_uverbs_idr_mutex);
@@ -593,13 +594,18 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
        if (cmd.comp_vector >= file->device->num_comp_vectors)
                return -EINVAL;
 
-       if (cmd.comp_channel >= 0)
-               ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel);
-
        uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
        if (!uobj)
                return -ENOMEM;
 
+       if (cmd.comp_channel >= 0) {
+               ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel);
+               if (!ev_file) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+
        uobj->uobject.user_handle   = cmd.user_handle;
        uobj->uobject.context       = file->ucontext;
        uobj->uverbs_file           = file;
@@ -663,6 +669,8 @@ err_up:
        ib_destroy_cq(cq);
 
 err:
+       if (ev_file)
+               ib_uverbs_release_ucq(file, ev_file, uobj);
        kfree(uobj);
        return ret;
 }
@@ -935,6 +943,11 @@ err_idr:
 
 err_destroy:
        ib_destroy_qp(qp);
+       atomic_dec(&pd->usecnt);
+       atomic_dec(&attr.send_cq->usecnt);
+       atomic_dec(&attr.recv_cq->usecnt);
+       if (attr.srq)
+               atomic_dec(&attr.srq->usecnt);
 
 err_up:
        up(&ib_uverbs_idr_mutex);
@@ -1448,6 +1461,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
        attr.sl                = cmd.attr.sl;
        attr.src_path_bits     = cmd.attr.src_path_bits;
        attr.static_rate       = cmd.attr.static_rate;
+       attr.ah_flags          = cmd.attr.is_global ? IB_AH_GRH : 0;
        attr.port_num          = cmd.attr.port_num;
        attr.grh.flow_label    = cmd.attr.grh.flow_label;
        attr.grh.sgid_index    = cmd.attr.grh.sgid_index;
@@ -1729,6 +1743,7 @@ err_idr:
 
 err_destroy:
        ib_destroy_srq(srq);
+       atomic_dec(&pd->usecnt);
 
 err_up:
        up(&ib_uverbs_idr_mutex);
index 4c15e112736ca13408bfc1c7472258c1bb955ca6..c857361be4490d805a811f81bf95b3a21052148a 100644 (file)
@@ -107,9 +107,9 @@ struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc,
 
        if (wc->wc_flags & IB_WC_GRH) {
                ah_attr.ah_flags = IB_AH_GRH;
-               ah_attr.grh.dgid = grh->dgid;
+               ah_attr.grh.dgid = grh->sgid;
 
-               ret = ib_find_cached_gid(pd->device, &grh->sgid, &port_num,
+               ret = ib_find_cached_gid(pd->device, &grh->dgid, &port_num,
                                         &gid_index);
                if (ret)
                        return ERR_PTR(ret);
index 9ed34587fc5c636ee080eaea3d48968e0cdba9b1..22ac72bc20c388860df359ade45c8842d6fbc0e5 100644 (file)
@@ -937,10 +937,6 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
        if (err)
                goto out;
 
-       MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET);
-       dev_lim->max_srq_sz = (1 << field) - 1;
-       MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET);
-       dev_lim->max_qp_sz = (1 << field) - 1;
        MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_QP_OFFSET);
        dev_lim->reserved_qps = 1 << (field & 0xf);
        MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_OFFSET);
@@ -1056,6 +1052,10 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
        mthca_dbg(dev, "Flags: %08x\n", dev_lim->flags);
 
        if (mthca_is_memfree(dev)) {
+               MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET);
+               dev_lim->max_srq_sz = 1 << field;
+               MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET);
+               dev_lim->max_qp_sz = 1 << field;
                MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSZ_SRQ_OFFSET);
                dev_lim->hca.arbel.resize_srq = field & 1;
                MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET);
@@ -1087,6 +1087,10 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
                mthca_dbg(dev, "Max ICM size %lld MB\n",
                          (unsigned long long) dev_lim->hca.arbel.max_icm_sz >> 20);
        } else {
+               MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET);
+               dev_lim->max_srq_sz = (1 << field) - 1;
+               MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET);
+               dev_lim->max_qp_sz = (1 << field) - 1;
                MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_AV_OFFSET);
                dev_lim->hca.tavor.max_avs = 1 << (field & 0x3f);
                dev_lim->mpt_entry_sz = MTHCA_MPT_ENTRY_SIZE;
index 4a8adcef2079cd5c118c41c40f6a87a94ab98ffe..96f1a86bf04950f54df57b36522ae008bfff00d5 100644 (file)
@@ -128,12 +128,12 @@ struct mthca_err_cqe {
        __be32 my_qpn;
        u32    reserved1[3];
        u8     syndrome;
-       u8     reserved2;
+       u8     vendor_err;
        __be16 db_cnt;
-       u32    reserved3;
+       u32    reserved2;
        __be32 wqe;
        u8     opcode;
-       u8     reserved4[2];
+       u8     reserved3[2];
        u8     owner;
 };
 
@@ -253,6 +253,15 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn,
                wake_up(&cq->wait);
 }
 
+static inline int is_recv_cqe(struct mthca_cqe *cqe)
+{
+       if ((cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
+           MTHCA_ERROR_CQE_OPCODE_MASK)
+               return !(cqe->opcode & 0x01);
+       else
+               return !(cqe->is_send & 0x80);
+}
+
 void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
                    struct mthca_srq *srq)
 {
@@ -296,7 +305,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
        while ((int) --prod_index - (int) cq->cons_index >= 0) {
                cqe = get_cqe(cq, prod_index & cq->ibcq.cqe);
                if (cqe->my_qpn == cpu_to_be32(qpn)) {
-                       if (srq)
+                       if (srq && is_recv_cqe(cqe))
                                mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe));
                        ++nfreed;
                } else if (nfreed)
@@ -333,8 +342,8 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
        }
 
        /*
-        * For completions in error, only work request ID, status (and
-        * freed resource count for RD) have to be set.
+        * For completions in error, only work request ID, status, vendor error
+        * (and freed resource count for RD) have to be set.
         */
        switch (cqe->syndrome) {
        case SYNDROME_LOCAL_LENGTH_ERR:
@@ -396,6 +405,8 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
                break;
        }
 
+       entry->vendor_err = cqe->vendor_err;
+
        /*
         * Mem-free HCAs always generate one CQE per WQE, even in the
         * error case, so we don't have to check the doorbell count, etc.
index 497ff794ef6a4b7063d0f1a96c8ca9ed51cb8dc9..795b379260bfeb6eb5cc77c023b0bf103c5210fd 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <linux/timer.h>
 #include <asm/semaphore.h>
 
 #include "mthca_provider.h"
index 34d68e5a72d863723b0de968591d9e302a395142..e8a948f087c06835cacf604c34188ce785ec02b7 100644 (file)
@@ -484,8 +484,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
                                     u8 intr,
                                     struct mthca_eq *eq)
 {
-       int npages = (nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
-               PAGE_SIZE;
+       int npages;
        u64 *dma_list = NULL;
        dma_addr_t t;
        struct mthca_mailbox *mailbox;
@@ -496,6 +495,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 
        eq->dev  = dev;
        eq->nent = roundup_pow_of_two(max(nent, 2));
+       npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
 
        eq->page_list = kmalloc(npages * sizeof *eq->page_list,
                                GFP_KERNEL);
index 6f94b25f3acd2ec15fda43cb337164ecb0ea7ccd..8b00d9a0f6f4b3d580f187edddb4bea4cddadcc5 100644 (file)
@@ -261,6 +261,10 @@ static int __devinit mthca_init_tavor(struct mthca_dev *mdev)
        }
 
        err = mthca_dev_lim(mdev, &dev_lim);
+       if (err) {
+               mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n");
+               goto err_disable;
+       }
 
        profile = default_profile;
        profile.num_uar   = dev_lim.uar_size / PAGE_SIZE;
index 2fc449da418d280e534472cebe9ea8797ed7504c..77bc6c746f43ac2783c837194b2b29ffd82c416c 100644 (file)
@@ -111,7 +111,8 @@ static int find_mgm(struct mthca_dev *dev,
                        goto out;
                if (status) {
                        mthca_err(dev, "READ_MGM returned status %02x\n", status);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto out;
                }
 
                if (!memcmp(mgm->gid, zero_gid, 16)) {
@@ -126,7 +127,7 @@ static int find_mgm(struct mthca_dev *dev,
                        goto out;
 
                *prev = *index;
-               *index = be32_to_cpu(mgm->next_gid_index) >> 5;
+               *index = be32_to_cpu(mgm->next_gid_index) >> 6;
        } while (*index);
 
        *index = -1;
@@ -153,8 +154,10 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                return PTR_ERR(mailbox);
        mgm = mailbox->buf;
 
-       if (down_interruptible(&dev->mcg_table.sem))
-               return -EINTR;
+       if (down_interruptible(&dev->mcg_table.sem)) {
+               err = -EINTR;
+               goto err_sem;
+       }
 
        err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
        if (err)
@@ -181,9 +184,8 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        err = -EINVAL;
                        goto out;
                }
-
+               memset(mgm, 0, sizeof *mgm);
                memcpy(mgm->gid, gid->raw, 16);
-               mgm->next_gid_index = 0;
        }
 
        for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
@@ -209,6 +211,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        if (status) {
                mthca_err(dev, "WRITE_MGM returned status %02x\n", status);
                err = -EINVAL;
+               goto out;
        }
 
        if (!link)
@@ -223,7 +226,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                goto out;
        }
 
-       mgm->next_gid_index = cpu_to_be32(index << 5);
+       mgm->next_gid_index = cpu_to_be32(index << 6);
 
        err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
        if (err)
@@ -234,7 +237,12 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        }
 
  out:
+       if (err && link && index != -1) {
+               BUG_ON(index < dev->limits.num_mgms);
+               mthca_free(&dev->mcg_table.alloc, index);
+       }
        up(&dev->mcg_table.sem);
+ err_sem:
        mthca_free_mailbox(dev, mailbox);
        return err;
 }
@@ -255,8 +263,10 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                return PTR_ERR(mailbox);
        mgm = mailbox->buf;
 
-       if (down_interruptible(&dev->mcg_table.sem))
-               return -EINTR;
+       if (down_interruptible(&dev->mcg_table.sem)) {
+               err = -EINTR;
+               goto err_sem;
+       }
 
        err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
        if (err)
@@ -305,13 +315,11 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        if (i != 1)
                goto out;
 
-       goto out;
-
        if (prev == -1) {
                /* Remove entry from MGM */
-               if (be32_to_cpu(mgm->next_gid_index) >> 5) {
-                       err = mthca_READ_MGM(dev,
-                                            be32_to_cpu(mgm->next_gid_index) >> 5,
+               int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6;
+               if (amgm_index_to_free) {
+                       err = mthca_READ_MGM(dev, amgm_index_to_free,
                                             mailbox, &status);
                        if (err)
                                goto out;
@@ -332,9 +340,13 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        err = -EINVAL;
                        goto out;
                }
+               if (amgm_index_to_free) {
+                       BUG_ON(amgm_index_to_free < dev->limits.num_mgms);
+                       mthca_free(&dev->mcg_table.alloc, amgm_index_to_free);
+               }
        } else {
                /* Remove entry from AMGM */
-               index = be32_to_cpu(mgm->next_gid_index) >> 5;
+               int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
                err = mthca_READ_MGM(dev, prev, mailbox, &status);
                if (err)
                        goto out;
@@ -344,7 +356,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        goto out;
                }
 
-               mgm->next_gid_index = cpu_to_be32(index << 5);
+               mgm->next_gid_index = cpu_to_be32(curr_next_index << 6);
 
                err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
                if (err)
@@ -354,10 +366,13 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        err = -EINVAL;
                        goto out;
                }
+               BUG_ON(index < dev->limits.num_mgms);
+               mthca_free(&dev->mcg_table.alloc, index);
        }
 
  out:
        up(&dev->mcg_table.sem);
+ err_sem:
        mthca_free_mailbox(dev, mailbox);
        return err;
 }
@@ -365,11 +380,12 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 int __devinit mthca_init_mcg_table(struct mthca_dev *dev)
 {
        int err;
+       int table_size = dev->limits.num_mgms + dev->limits.num_amgms;
 
        err = mthca_alloc_init(&dev->mcg_table.alloc,
-                              dev->limits.num_amgms,
-                              dev->limits.num_amgms - 1,
-                              0);
+                              table_size,
+                              table_size - 1,
+                              dev->limits.num_mgms);
        if (err)
                return err;
 
index d72fe95cba08852c10b9321c261fd8d64d286e27..9fb985a016e902d6ed6f977e18bdb78ee6ce7984 100644 (file)
@@ -233,7 +233,7 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj)
                for (i = 0; i < chunk->npages; ++i) {
                        if (chunk->mem[i].length >= offset) {
                                page = chunk->mem[i].page;
-                               break;
+                               goto out;
                        }
                        offset -= chunk->mem[i].length;
                }
@@ -485,6 +485,8 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
                        put_page(db_tab->page[i].mem.page);
                }
        }
+
+       kfree(db_tab);
 }
 
 int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type,
index 7450550db736260bdd06228e66348b26a6eb8b19..564b6d51c394ae8c38e407cac17a8b51983d5889 100644 (file)
@@ -383,12 +383,10 @@ static const struct {
                                [UC]  = (IB_QP_CUR_STATE             |
                                         IB_QP_ALT_PATH              |
                                         IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_PKEY_INDEX            |
                                         IB_QP_PATH_MIG_STATE),
                                [RC]  = (IB_QP_CUR_STATE             |
                                         IB_QP_ALT_PATH              |
                                         IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_PKEY_INDEX            |
                                         IB_QP_MIN_RNR_TIMER         |
                                         IB_QP_PATH_MIG_STATE),
                                [MLX] = (IB_QP_CUR_STATE             |
@@ -476,9 +474,8 @@ static const struct {
                        .opt_param = {
                                [UD]  = (IB_QP_CUR_STATE             |
                                         IB_QP_QKEY),
-                               [UC]  = IB_QP_CUR_STATE,
-                               [RC]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_MIN_RNR_TIMER),
+                               [UC]  = (IB_QP_CUR_STATE             |
+                                        IB_QP_ACCESS_FLAGS),
                                [MLX] = (IB_QP_CUR_STATE             |
                                         IB_QP_QKEY),
                        }
@@ -522,6 +519,55 @@ static void init_port(struct mthca_dev *dev, int port)
                mthca_warn(dev, "INIT_IB returned status %02x.\n", status);
 }
 
+static __be32 get_hw_access_flags(struct mthca_qp *qp, struct ib_qp_attr *attr,
+                                 int attr_mask)
+{
+       u8 dest_rd_atomic;
+       u32 access_flags;
+       u32 hw_access_flags = 0;
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               dest_rd_atomic = attr->max_dest_rd_atomic;
+       else
+               dest_rd_atomic = qp->resp_depth;
+
+       if (attr_mask & IB_QP_ACCESS_FLAGS)
+               access_flags = attr->qp_access_flags;
+       else
+               access_flags = qp->atomic_rd_en;
+
+       if (!dest_rd_atomic)
+               access_flags &= IB_ACCESS_REMOTE_WRITE;
+
+       if (access_flags & IB_ACCESS_REMOTE_READ)
+               hw_access_flags |= MTHCA_QP_BIT_RRE;
+       if (access_flags & IB_ACCESS_REMOTE_ATOMIC)
+               hw_access_flags |= MTHCA_QP_BIT_RAE;
+       if (access_flags & IB_ACCESS_REMOTE_WRITE)
+               hw_access_flags |= MTHCA_QP_BIT_RWE;
+
+       return cpu_to_be32(hw_access_flags);
+}
+
+static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path)
+{
+       path->g_mylmc     = ah->src_path_bits & 0x7f;
+       path->rlid        = cpu_to_be16(ah->dlid);
+       path->static_rate = !!ah->static_rate;
+
+       if (ah->ah_flags & IB_AH_GRH) {
+               path->g_mylmc   |= 1 << 7;
+               path->mgid_index = ah->grh.sgid_index;
+               path->hop_limit  = ah->grh.hop_limit;
+               path->sl_tclass_flowlabel = 
+                       cpu_to_be32((ah->sl << 28)                |
+                                   (ah->grh.traffic_class << 20) | 
+                                   (ah->grh.flow_label));
+               memcpy(path->rgid, ah->grh.dgid.raw, 16);
+       } else
+               path->sl_tclass_flowlabel = cpu_to_be32(ah->sl << 28);
+}
+
 int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 {
        struct mthca_dev *dev = to_mdev(ibqp->device);
@@ -591,6 +637,26 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                return -EINVAL;
        }
 
+       if ((attr_mask & IB_QP_PORT) &&
+           (attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) {
+               mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num);
+               return -EINVAL;
+       }
+
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
+           attr->max_rd_atomic > dev->limits.max_qp_init_rdma) {
+               mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n",
+                         attr->max_rd_atomic, dev->limits.max_qp_init_rdma);
+               return -EINVAL;
+       }
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
+           attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) {
+               mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n",
+                         attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift);
+               return -EINVAL;
+       }
+
        mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
        if (IS_ERR(mailbox))
                return PTR_ERR(mailbox);
@@ -665,28 +731,14 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        }
 
        if (attr_mask & IB_QP_RNR_RETRY) {
-               qp_context->pri_path.rnr_retry = attr->rnr_retry << 5;
-               qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY);
+               qp_context->alt_path.rnr_retry = qp_context->pri_path.rnr_retry =
+                       attr->rnr_retry << 5;
+               qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY | 
+                                                       MTHCA_QP_OPTPAR_ALT_RNR_RETRY);
        }
 
        if (attr_mask & IB_QP_AV) {
-               qp_context->pri_path.g_mylmc     = attr->ah_attr.src_path_bits & 0x7f;
-               qp_context->pri_path.rlid        = cpu_to_be16(attr->ah_attr.dlid);
-               qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate;
-               if (attr->ah_attr.ah_flags & IB_AH_GRH) {
-                       qp_context->pri_path.g_mylmc |= 1 << 7;
-                       qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index;
-                       qp_context->pri_path.hop_limit = attr->ah_attr.grh.hop_limit;
-                       qp_context->pri_path.sl_tclass_flowlabel =
-                               cpu_to_be32((attr->ah_attr.sl << 28)                |
-                                           (attr->ah_attr.grh.traffic_class << 20) |
-                                           (attr->ah_attr.grh.flow_label));
-                       memcpy(qp_context->pri_path.rgid,
-                              attr->ah_attr.grh.dgid.raw, 16);
-               } else {
-                       qp_context->pri_path.sl_tclass_flowlabel =
-                               cpu_to_be32(attr->ah_attr.sl << 28);
-               }
+               mthca_path_set(&attr->ah_attr, &qp_context->pri_path);
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH);
        }
 
@@ -695,7 +747,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT);
        }
 
-       /* XXX alt_path */
+       if (attr_mask & IB_QP_ALT_PATH) {
+               if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) {
+                       mthca_dbg(dev, "Alternate port number (%u) is invalid\n", 
+                               attr->alt_port_num);
+                       return -EINVAL;
+               }
+
+               mthca_path_set(&attr->alt_ah_attr, &qp_context->alt_path);
+               qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | 
+                                                             attr->alt_port_num << 24);
+               qp_context->alt_path.ackto = attr->alt_timeout << 3;
+               qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ALT_ADDR_PATH);
+       }
 
        /* leave rdd as 0 */
        qp_context->pd         = cpu_to_be32(to_mpd(ibqp->pd)->pd_num);
@@ -703,9 +767,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        qp_context->wqe_lkey   = cpu_to_be32(qp->mr.ibmr.lkey);
        qp_context->params1    = cpu_to_be32((MTHCA_ACK_REQ_FREQ << 28) |
                                             (MTHCA_FLIGHT_LIMIT << 24) |
-                                            MTHCA_QP_BIT_SRE           |
-                                            MTHCA_QP_BIT_SWE           |
-                                            MTHCA_QP_BIT_SAE);
+                                            MTHCA_QP_BIT_SWE);
        if (qp->sq_policy == IB_SIGNAL_ALL_WR)
                qp_context->params1 |= cpu_to_be32(MTHCA_QP_BIT_SSC);
        if (attr_mask & IB_QP_RETRY_CNT) {
@@ -714,9 +776,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        }
 
        if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
-               qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ?
-                                                      ffs(attr->max_rd_atomic) - 1 : 0,
-                                                      7) << 21);
+               if (attr->max_rd_atomic) {
+                       qp_context->params1 |=
+                               cpu_to_be32(MTHCA_QP_BIT_SRE |
+                                           MTHCA_QP_BIT_SAE);
+                       qp_context->params1 |=
+                               cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21);
+               }
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX);
        }
 
@@ -729,71 +795,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                qp_context->snd_db_index   = cpu_to_be32(qp->sq.db_index);
        }
 
-       if (attr_mask & IB_QP_ACCESS_FLAGS) {
-               qp_context->params2 |=
-                       cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE ?
-                                   MTHCA_QP_BIT_RWE : 0);
-
-               /*
-                * Only enable RDMA reads and atomics if we have
-                * responder resources set to a non-zero value.
-                */
-               if (qp->resp_depth) {
-                       qp_context->params2 |=
-                               cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_READ ?
-                                           MTHCA_QP_BIT_RRE : 0);
-                       qp_context->params2 |=
-                               cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC ?
-                                           MTHCA_QP_BIT_RAE : 0);
-               }
-
-               qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RWE |
-                                                       MTHCA_QP_OPTPAR_RRE |
-                                                       MTHCA_QP_OPTPAR_RAE);
-
-               qp->atomic_rd_en = attr->qp_access_flags;
-       }
-
        if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
-               u8 rra_max;
-
-               if (qp->resp_depth && !attr->max_dest_rd_atomic) {
-                       /*
-                        * Lowering our responder resources to zero.
-                        * Turn off reads RDMA and atomics as responder.
-                        * (RRE/RAE in params2 already zero)
-                        */
-                       qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRE |
-                                                               MTHCA_QP_OPTPAR_RAE);
-               }
-
-               if (!qp->resp_depth && attr->max_dest_rd_atomic) {
-                       /*
-                        * Increasing our responder resources from
-                        * zero.  Turn on RDMA reads and atomics as
-                        * appropriate.
-                        */
+               if (attr->max_dest_rd_atomic)
                        qp_context->params2 |=
-                               cpu_to_be32(qp->atomic_rd_en & IB_ACCESS_REMOTE_READ ?
-                                           MTHCA_QP_BIT_RRE : 0);
-                       qp_context->params2 |=
-                               cpu_to_be32(qp->atomic_rd_en & IB_ACCESS_REMOTE_ATOMIC ?
-                                           MTHCA_QP_BIT_RAE : 0);
-
-                       qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRE |
-                                                               MTHCA_QP_OPTPAR_RAE);
-               }
+                               cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21);
 
-               for (rra_max = 0;
-                    1 << rra_max < attr->max_dest_rd_atomic &&
-                            rra_max < dev->qp_table.rdb_shift;
-                    ++rra_max)
-                       ; /* nothing */
-
-               qp_context->params2      |= cpu_to_be32(rra_max << 21);
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX);
+       }
 
-               qp->resp_depth = attr->max_dest_rd_atomic;
+       if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) {
+               qp_context->params2      |= get_hw_access_flags(qp, attr, attr_mask);
+               qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RWE |
+                                                       MTHCA_QP_OPTPAR_RRE |
+                                                       MTHCA_QP_OPTPAR_RAE);
        }
 
        qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
@@ -835,8 +849,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                err = -EINVAL;
        }
 
-       if (!err)
+       if (!err) {
                qp->state = new_state;
+               if (attr_mask & IB_QP_ACCESS_FLAGS)
+                       qp->atomic_rd_en = attr->qp_access_flags;
+               if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+                       qp->resp_depth = attr->max_dest_rd_atomic;
+       }
 
        mthca_free_mailbox(dev, mailbox);
 
@@ -885,18 +904,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        return err;
 }
 
-static void mthca_adjust_qp_caps(struct mthca_dev *dev,
-                                struct mthca_pd *pd,
-                                struct mthca_qp *qp)
+static int mthca_max_data_size(struct mthca_dev *dev, struct mthca_qp *qp, int desc_sz)
 {
-       int max_data_size;
-
        /*
         * Calculate the maximum size of WQE s/g segments, excluding
         * the next segment and other non-data segments.
         */
-       max_data_size = min(dev->limits.max_desc_sz, 1 << qp->sq.wqe_shift) -
-               sizeof (struct mthca_next_seg);
+       int max_data_size = desc_sz - sizeof (struct mthca_next_seg);
 
        switch (qp->transport) {
        case MLX:
@@ -915,11 +929,24 @@ static void mthca_adjust_qp_caps(struct mthca_dev *dev,
                break;
        }
 
+       return max_data_size;
+}
+
+static inline int mthca_max_inline_data(struct mthca_pd *pd, int max_data_size)
+{
        /* We don't support inline data for kernel QPs (yet). */
-       if (!pd->ibpd.uobject)
-               qp->max_inline_data = 0;
-        else
-               qp->max_inline_data = max_data_size - MTHCA_INLINE_HEADER_SIZE;
+       return pd->ibpd.uobject ? max_data_size - MTHCA_INLINE_HEADER_SIZE : 0;
+}
+
+static void mthca_adjust_qp_caps(struct mthca_dev *dev,
+                                struct mthca_pd *pd,
+                                struct mthca_qp *qp)
+{
+       int max_data_size = mthca_max_data_size(dev, qp,
+                                               min(dev->limits.max_desc_sz,
+                                                   1 << qp->sq.wqe_shift));
+
+       qp->max_inline_data = mthca_max_inline_data(pd, max_data_size);
 
        qp->sq.max_gs = min_t(int, dev->limits.max_sg,
                              max_data_size / sizeof (struct mthca_data_seg));
@@ -1186,13 +1213,23 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
 }
 
 static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap,
-                            struct mthca_qp *qp)
+                            struct mthca_pd *pd, struct mthca_qp *qp)
 {
+       int max_data_size = mthca_max_data_size(dev, qp, dev->limits.max_desc_sz);
+
        /* Sanity check QP size before proceeding */
-       if (cap->max_send_wr  > dev->limits.max_wqes ||
-           cap->max_recv_wr  > dev->limits.max_wqes ||
-           cap->max_send_sge > dev->limits.max_sg   ||
-           cap->max_recv_sge > dev->limits.max_sg)
+       if (cap->max_send_wr     > dev->limits.max_wqes ||
+           cap->max_recv_wr     > dev->limits.max_wqes ||
+           cap->max_send_sge    > dev->limits.max_sg   ||
+           cap->max_recv_sge    > dev->limits.max_sg   ||
+           cap->max_inline_data > mthca_max_inline_data(pd, max_data_size))
+               return -EINVAL;
+
+       /*
+        * For MLX transport we need 2 extra S/G entries:
+        * one for the header and one for the checksum at the end
+        */
+       if (qp->transport == MLX && cap->max_recv_sge + 2 > dev->limits.max_sg)
                return -EINVAL;
 
        if (mthca_is_memfree(dev)) {
@@ -1211,14 +1248,6 @@ static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap,
                                    MTHCA_INLINE_CHUNK_SIZE) /
                              sizeof (struct mthca_data_seg));
 
-       /*
-        * For MLX transport we need 2 extra S/G entries:
-        * one for the header and one for the checksum at the end
-        */
-       if ((qp->transport == MLX && qp->sq.max_gs + 2 > dev->limits.max_sg) ||
-           qp->sq.max_gs > dev->limits.max_sg || qp->rq.max_gs > dev->limits.max_sg)
-               return -EINVAL;
-
        return 0;
 }
 
@@ -1233,7 +1262,7 @@ int mthca_alloc_qp(struct mthca_dev *dev,
 {
        int err;
 
-       err = mthca_set_qp_size(dev, cap, qp);
+       err = mthca_set_qp_size(dev, cap, pd, qp);
        if (err)
                return err;
 
@@ -1276,7 +1305,7 @@ int mthca_alloc_sqp(struct mthca_dev *dev,
        u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1;
        int err;
 
-       err = mthca_set_qp_size(dev, cap, &sqp->qp);
+       err = mthca_set_qp_size(dev, cap, pd, &sqp->qp);
        if (err)
                return err;
 
index f7d234295efe3fa8c2fe0fa7eefa243f746391a0..e7e153d9c4c6d0f9b6c90d90ae301a0aa491ee10 100644 (file)
@@ -201,7 +201,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
        if (mthca_is_memfree(dev))
                srq->max = roundup_pow_of_two(srq->max + 1);
 
-       ds = min(64UL,
+       ds = max(64UL,
                 roundup_pow_of_two(sizeof (struct mthca_next_seg) +
                                    srq->max_gs * sizeof (struct mthca_data_seg)));
        srq->wqe_shift = long_log2(ds);
index ee9fe226ae994408f50b1180632c8c4b9ba7d7db..dd488d3cffa93c9b11316765750fe28005a6e148 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/string.h>
 #include <linux/parser.h>
 #include <linux/random.h>
+#include <linux/jiffies.h>
 
 #include <asm/atomic.h>
 
index 64672d491222a99e62f48849f9b7c3139e72a06e..e301ee4ca264e6a5b1315a81a88fdda6880da112 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <asm/irq.h>
 
 #include <asm/arch/corgi.h>
 #include <asm/arch/hardware.h>
@@ -343,10 +342,9 @@ static int __init corgikbd_probe(struct platform_device *pdev)
        for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) {
                pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN);
                if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt,
-                                               SA_INTERRUPT, "corgikbd", corgikbd))
+                               SA_INTERRUPT | SA_TRIGGER_RISING,
+                               "corgikbd", corgikbd))
                        printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i);
-               else
-                       set_irq_type(CORGI_IRQ_GPIO_KEY_SENSE(i),IRQT_RISING);
        }
 
        /* Set Strobe lines as outputs - set high */
index 6a15fe3bc527071e683fa12c0eb4944a4a6e5251..83999d5831225e20ffa0bc000c326673596089f2 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <asm/irq.h>
 
 #include <asm/arch/spitz.h>
 #include <asm/arch/hardware.h>
@@ -407,10 +406,9 @@ static int __init spitzkbd_probe(struct platform_device *dev)
        for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) {
                pxa_gpio_mode(spitz_senses[i] | GPIO_IN);
                if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt,
-                                               SA_INTERRUPT, "Spitzkbd Sense", spitzkbd))
+                               SA_INTERRUPT|SA_TRIGGER_RISING,
+                               "Spitzkbd Sense", spitzkbd))
                        printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i);
-               else
-                       set_irq_type(IRQ_GPIO(spitz_senses[i]),IRQT_RISING);
        }
 
        /* Set Strobe lines as outputs - set high */
@@ -422,15 +420,18 @@ static int __init spitzkbd_probe(struct platform_device *dev)
        pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN);
        pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN);
 
-       request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd Sync", spitzkbd);
-       request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd PwrOn", spitzkbd);
-       request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWA", spitzkbd);
-       request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWB", spitzkbd);
-
-       set_irq_type(SPITZ_IRQ_GPIO_SYNC, IRQT_BOTHEDGE);
-       set_irq_type(SPITZ_IRQ_GPIO_ON_KEY, IRQT_BOTHEDGE);
-       set_irq_type(SPITZ_IRQ_GPIO_SWA, IRQT_BOTHEDGE);
-       set_irq_type(SPITZ_IRQ_GPIO_SWB, IRQT_BOTHEDGE);
+       request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt,
+                   SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+                   "Spitzkbd Sync", spitzkbd);
+       request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt,
+                   SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+                   "Spitzkbd PwrOn", spitzkbd);
+       request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr,
+                   SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+                   "Spitzkbd SWA", spitzkbd);
+       request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr,
+                   SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+                   "Spitzkbd SWB", spitzkbd);
 
        printk(KERN_INFO "input: Spitz Keyboard Registered\n");
 
index 1cd7657f7e42439bf5471c7772737ea13bc5ffba..1be963961c15734bfd923c07c589ab6a1a8f2a47 100644 (file)
@@ -60,8 +60,6 @@ static struct fasync_struct *hp_sdc_rtc_async_queue;
 
 static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait);
 
-static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin);
-
 static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
                               size_t count, loff_t *ppos);
 
@@ -387,11 +385,6 @@ static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd)
        return 0;
 }
 
-static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin)
-{
-        return -ESPIPE;
-}
-
 static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
                               size_t count, loff_t *ppos) {
        ssize_t retval;
@@ -679,7 +672,7 @@ static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
 
 static struct file_operations hp_sdc_rtc_fops = {
         .owner =       THIS_MODULE,
-        .llseek =      hp_sdc_rtc_llseek,
+        .llseek =      no_llseek,
         .read =                hp_sdc_rtc_read,
         .poll =                hp_sdc_rtc_poll,
         .ioctl =       hp_sdc_rtc_ioctl,
index b091d1a54125ce38f32977b7eb416562ab8ee675..d4c50512a1ffc038795acb06248e1b245f63f3a5 100644 (file)
@@ -181,17 +181,17 @@ typedef struct act2000_card {
        char regname[35];               /* Name used for request_region     */
 } act2000_card;
 
-extern __inline__ void act2000_schedule_tx(act2000_card *card)
+static inline void act2000_schedule_tx(act2000_card *card)
 {
         schedule_work(&card->snd_tq);
 }
 
-extern __inline__ void act2000_schedule_rx(act2000_card *card)
+static inline void act2000_schedule_rx(act2000_card *card)
 {
         schedule_work(&card->rcv_tq);
 }
 
-extern __inline__ void act2000_schedule_poll(act2000_card *card)
+static inline void act2000_schedule_poll(act2000_card *card)
 {
         schedule_work(&card->poll_tq);
 }
index f6d5f530b86be8e3d434ca17244ff2b9591b2623..49f453c53c64d9de0c1784df30b65e171c6792f1 100644 (file)
@@ -78,29 +78,29 @@ typedef union  actcapi_infoel {              /* info element                 */
 typedef struct actcapi_msn {
        __u8 eaz;
        __u8 len;                            /* Length of MSN                */
-       __u8 msn[15] __attribute__ ((packed));
-} actcapi_msn;
+       __u8 msn[15];
+}  __attribute__((packed)) actcapi_msn;
 
 typedef struct actcapi_dlpd {
        __u8 len;                            /* Length of structure          */
-       __u16 dlen __attribute__ ((packed)); /* Data Length                  */
-       __u8 laa __attribute__ ((packed));   /* Link Address A               */
+       __u16 dlen;                          /* Data Length                  */
+       __u8 laa;                            /* Link Address A               */
        __u8 lab;                            /* Link Address B               */
        __u8 modulo;                         /* Modulo Mode                  */
        __u8 win;                            /* Window size                  */
        __u8 xid[100];                       /* XID Information              */
-} actcapi_dlpd;
+} __attribute__((packed)) actcapi_dlpd;
 
 typedef struct actcapi_ncpd {
        __u8   len;                          /* Length of structure          */
-       __u16  lic __attribute__ ((packed));
-       __u16  hic __attribute__ ((packed));
-       __u16  ltc __attribute__ ((packed));
-       __u16  htc __attribute__ ((packed));
-       __u16  loc __attribute__ ((packed));
-       __u16  hoc __attribute__ ((packed));
-       __u8   modulo __attribute__ ((packed));
-} actcapi_ncpd;
+       __u16  lic;
+       __u16  hic;
+       __u16  ltc;
+       __u16  htc;
+       __u16  loc;
+       __u16  hoc;
+       __u8   modulo;
+} __attribute__((packed)) actcapi_ncpd;
 #define actcapi_ncpi actcapi_ncpd
 
 /*
@@ -168,19 +168,19 @@ typedef struct actcapi_msg {
                        __u16 manuf_msg;
                        __u16 controller;
                        actcapi_msn msnmap;
-               } manufacturer_req_msn;
+               } __attribute ((packed)) manufacturer_req_msn;
                /* TODO: TraceInit-req/conf/ind/resp and
                 *       TraceDump-req/conf/ind/resp
                 */
                struct connect_req {
                        __u8  controller;
                        __u8  bchan;
-                       __u32 infomask __attribute__ ((packed));
+                       __u32 infomask;
                        __u8  si1;
                        __u8  si2;
                        __u8  eaz;
                        actcapi_addr addr;
-               } connect_req;
+               } __attribute__ ((packed)) connect_req;
                struct connect_conf {
                        __u16 plci;
                        __u16 info;
@@ -192,7 +192,7 @@ typedef struct actcapi_msg {
                        __u8  si2;
                        __u8  eaz;
                        actcapi_addr addr;
-               } connect_ind;
+               } __attribute__ ((packed)) connect_ind;
                struct connect_resp {
                        __u16 plci;
                        __u8  rejectcause;
@@ -200,14 +200,14 @@ typedef struct actcapi_msg {
                struct connect_active_ind {
                        __u16 plci;
                        actcapi_addr addr;
-               } connect_active_ind;
+               } __attribute__ ((packed)) connect_active_ind;
                struct connect_active_resp {
                        __u16 plci;
                } connect_active_resp;
                struct connect_b3_req {
                        __u16 plci;
                        actcapi_ncpi ncpi;
-               } connect_b3_req;
+               } __attribute__ ((packed)) connect_b3_req;
                struct connect_b3_conf {
                        __u16 plci;
                        __u16 ncci;
@@ -217,12 +217,12 @@ typedef struct actcapi_msg {
                        __u16 ncci;
                        __u16 plci;
                        actcapi_ncpi ncpi;
-               } connect_b3_ind;
+               } __attribute__ ((packed)) connect_b3_ind;
                struct connect_b3_resp {
                        __u16 ncci;
                        __u8  rejectcause;
-                       actcapi_ncpi ncpi __attribute__ ((packed));
-               } connect_b3_resp;
+                       actcapi_ncpi ncpi;
+               } __attribute__ ((packed)) connect_b3_resp;
                struct disconnect_req {
                        __u16 plci;
                        __u8  cause;
@@ -241,14 +241,14 @@ typedef struct actcapi_msg {
                struct connect_b3_active_ind {
                        __u16 ncci;
                        actcapi_ncpi ncpi;
-               } connect_b3_active_ind;
+               } __attribute__ ((packed)) connect_b3_active_ind;
                struct connect_b3_active_resp {
                        __u16 ncci;
                } connect_b3_active_resp;
                struct disconnect_b3_req {
                        __u16 ncci;
                        actcapi_ncpi ncpi;
-               } disconnect_b3_req;
+               } __attribute__ ((packed)) disconnect_b3_req;
                struct disconnect_b3_conf {
                        __u16 ncci;
                        __u16 info;
@@ -257,7 +257,7 @@ typedef struct actcapi_msg {
                        __u16 ncci;
                        __u16 info;
                        actcapi_ncpi ncpi;
-               } disconnect_b3_ind;
+               } __attribute__ ((packed)) disconnect_b3_ind;
                struct disconnect_b3_resp {
                        __u16 ncci;
                } disconnect_b3_resp;
@@ -265,7 +265,7 @@ typedef struct actcapi_msg {
                        __u16 plci;
                        actcapi_infonr nr;
                        actcapi_infoel el;
-               } info_ind;
+               } __attribute__ ((packed)) info_ind;
                struct info_resp {
                        __u16 plci;
                } info_resp;
@@ -279,8 +279,8 @@ typedef struct actcapi_msg {
                struct select_b2_protocol_req {
                        __u16 plci;
                        __u8  protocol;
-                       actcapi_dlpd dlpd __attribute__ ((packed));
-               } select_b2_protocol_req;
+                       actcapi_dlpd dlpd;
+               } __attribute__ ((packed)) select_b2_protocol_req;
                struct select_b2_protocol_conf {
                        __u16 plci;
                        __u16 info;
@@ -288,49 +288,49 @@ typedef struct actcapi_msg {
                struct select_b3_protocol_req {
                        __u16 plci;
                        __u8  protocol;
-                       actcapi_ncpd ncpd __attribute__ ((packed));
-               } select_b3_protocol_req;
+                       actcapi_ncpd ncpd;
+               } __attribute__ ((packed)) select_b3_protocol_req;
                struct select_b3_protocol_conf {
                        __u16 plci;
                        __u16 info;
                } select_b3_protocol_conf;
                struct listen_req {
                        __u8  controller;
-                       __u32 infomask __attribute__ ((packed));  
-                       __u16 eazmask __attribute__ ((packed));
-                       __u16 simask __attribute__ ((packed));
-               } listen_req;
+                       __u32 infomask;
+                       __u16 eazmask;
+                       __u16 simask;
+               } __attribute__ ((packed)) listen_req;
                struct listen_conf {
                        __u8  controller;
-                       __u16 info __attribute__ ((packed));
-               } listen_conf;
+                       __u16 info;
+               } __attribute__ ((packed)) listen_conf;
                struct data_b3_req {
                        __u16 fakencci;
                        __u16 datalen;
                        __u32 unused;
                        __u8  blocknr;
-                       __u16 flags __attribute__ ((packed));
-               } data_b3_req;
+                       __u16 flags;
+               } __attribute ((packed)) data_b3_req;
                struct data_b3_ind {
                        __u16 fakencci;
                        __u16 datalen;
                        __u32 unused;
                        __u8  blocknr;
-                       __u16 flags __attribute__ ((packed));
-               } data_b3_ind;
+                       __u16 flags;
+               } __attribute__ ((packed)) data_b3_ind;
                struct data_b3_resp {
                        __u16 ncci;
                        __u8  blocknr;
-               } data_b3_resp;
+               } __attribute__ ((packed)) data_b3_resp;
                struct data_b3_conf {
                        __u16 ncci;
                        __u8  blocknr;
-                       __u16 info __attribute__ ((packed));
-               } data_b3_conf;
+                       __u16 info;
+               } __attribute__ ((packed)) data_b3_conf;
        } msg;
-} actcapi_msg;
+} __attribute__ ((packed)) actcapi_msg;
 
-extern __inline__ unsigned short
+static inline unsigned short
 actcapi_nextsmsg(act2000_card *card)
 {
        unsigned long flags;
index 7b564c0dd996cb305232922ef06d76c4996e1f08..207cae366256a68be114d2d8e48196c5fe3fe12e 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/ctype.h>
 #include <linux/sched.h>       /* current */
 
+#include "capifs.h"
+
 MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem");
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
index cccfabc1117dbee8ee8d35fec4466bcdd380ab81..11e6f937c1e479c477798f49533d0629c0707f73 100644 (file)
@@ -16,6 +16,7 @@
 #include "diva_pci.h"
 #include "mi_pc.h"
 #include "dsrv4bri.h"
+#include "helpers.h"
 
 static void *diva_xdiLoadFileFile = NULL;
 static dword diva_xdiLoadFileLength = 0;
@@ -815,7 +816,7 @@ diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
        return (ret);
 }
 
-void *xdiLoadFile(char *FileName, unsigned long *FileLength,
+void *xdiLoadFile(char *FileName, dword *FileLength,
                  unsigned long lim)
 {
        void *ret = diva_xdiLoadFileFile;
index 4cc44a5dd1dbe63aa39881b217f5b2c72c5d8db8..f31bba5b16ffa7ae2afd25c52c6ece5b188e9a33 100644 (file)
@@ -16,6 +16,7 @@
 #include "diva_pci.h"
 #include "mi_pc.h"
 #include "pc_maint.h"
+#include "dsrv_bri.h"
 
 /*
 **  IMPORTS
index 8ac207f75e54e925c80b875c3fb0a368d06c116d..a296a846f296c840f794eea7f182cae5af6abc16 100644 (file)
@@ -18,6 +18,7 @@
 #include "pc_maint.h"
 #include "dsp_tst.h"
 #include "diva_dma.h"
+#include "dsrv_pri.h"
 
 /* --------------------------------------------------------------------------
    OS Dependent part of XDI driver for DIVA PRI Adapter
index c82105920d7187e6c46a3487fa90b6de94b82c94..0ef560144be3f7ef09dce53dda6c03b3dd67ebfb 100644 (file)
@@ -110,7 +110,7 @@ config HISAX_16_3
 
 config HISAX_TELESPCI
        bool "Teles PCI"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
        help
          This enables HiSax support for the Teles PCI.
          See <file:Documentation/isdn/README.HiSax> on how to configure it.
@@ -238,7 +238,7 @@ config HISAX_MIC
 
 config HISAX_NETJET
        bool "NETjet card"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
        help
          This enables HiSax support for the NetJet from Traverse
          Technologies.
@@ -249,7 +249,7 @@ config HISAX_NETJET
 
 config HISAX_NETJET_U
        bool "NETspider U card"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
        help
          This enables HiSax support for the Netspider U interface ISDN card
          from Traverse Technologies.
@@ -317,7 +317,7 @@ config HISAX_GAZEL
 
 config HISAX_HFC_PCI
        bool "HFC PCI-Bus cards"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
        help
          This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
 
@@ -344,7 +344,7 @@ config HISAX_HFC_SX
 
 config HISAX_ENTERNOW_PCI
        bool "Formula-n enter:now PCI card"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
        help
          This enables HiSax support for the Formula-n enter:now PCI
          ISDN card.
index 26c545fa223be8672a5e3cace0e4377b04af48a2..1b85ce166af8c48b13fe74930d45a66555b7ca63 100644 (file)
@@ -396,17 +396,17 @@ struct isar_hw {
 
 struct hdlc_stat_reg {
 #ifdef __BIG_ENDIAN
-       u_char fill __attribute__((packed));
-       u_char mode __attribute__((packed));
-       u_char xml  __attribute__((packed));
-       u_char cmd  __attribute__((packed));
+       u_char fill;
+       u_char mode;
+       u_char xml;
+       u_char cmd;
 #else
-       u_char cmd  __attribute__((packed));
-       u_char xml  __attribute__((packed));
-       u_char mode __attribute__((packed));
-       u_char fill __attribute__((packed));
+       u_char cmd;
+       u_char xml;
+       u_char mode;
+       u_char fill;
 #endif
-};
+} __attribute__((packed));
 
 struct hdlc_hw {
        union {
index bd8a22e4d6a2ffc5534442b2b7c0e7410fc46392..21fbcedf3a9410a7b35a1dfd964405234c8e77b6 100644 (file)
@@ -12,17 +12,17 @@ enum {
 
 struct hdlc_stat_reg {
 #ifdef __BIG_ENDIAN
-       u_char fill __attribute__((packed));
-       u_char mode __attribute__((packed));
-       u_char xml  __attribute__((packed));
-       u_char cmd  __attribute__((packed));
+       u_char fill;
+       u_char mode;
+       u_char xml;
+       u_char cmd;
 #else
-       u_char cmd  __attribute__((packed));
-       u_char xml  __attribute__((packed));
-       u_char mode __attribute__((packed));
-       u_char fill __attribute__((packed));
+       u_char cmd;
+       u_char xml;
+       u_char mode;
+       u_char fill;
 #endif
-};
+} __attribute__((packed));
 
 struct fritz_bcs {
        struct hisax_b_if b_if;
index 19f2fcf0ae4a2f579eabac0e9b5720eec8b9f209..b4b24335f7165b0e5de378a637ca98ab7697d702 100644 (file)
@@ -43,7 +43,6 @@ extern int send_and_receive(int, unsigned int, unsigned char, unsigned char,
                 RspMessage *, int);
 extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
                 unsigned int, unsigned int, unsigned int, unsigned int *);
-extern inline void pullphone(char *, char *);
 
 #ifdef DEBUG
 /*
index a0ea44c3e8b10ec9ca68689718c3da6423961e3b..7d4a0ac28c065c2145d4f707c2a339c9ddb7caf4 100644 (file)
@@ -149,14 +149,14 @@ config MAC_EMUMOUSEBTN
 
 config THERM_WINDTUNNEL
        tristate "Support for thermal management on Windtunnel G4s"
-       depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
+       depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
        help
          This driver provides some thermostat and fan control for the desktop
          G4 "Windtunnel"
 
 config THERM_ADT746X
        tristate "Support for thermal mgmnt on laptops with ADT 746x chipset"
-       depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
+       depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
        help
          This driver provides some thermostat and fan control for the
           iBook G4, and the ATI based aluminium PowerBooks, allowing slighlty
@@ -164,7 +164,7 @@ config THERM_ADT746X
 
 config THERM_PM72
        tristate "Support for thermal management on PowerMac G5"
-       depends on I2C && I2C_KEYWEST && PPC_PMAC64
+       depends on I2C && I2C_POWERMAC && PPC_PMAC64
        help
          This driver provides thermostat and fan control for the desktop
          G5 machines. 
@@ -175,14 +175,14 @@ config WINDFARM
 config WINDFARM_PM81
        tristate "Support for thermal management on iMac G5"
        depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
-       select I2C_PMAC_SMU
+       select I2C_POWERMAC
        help
          This driver provides thermal control for the iMacG5
 
 config WINDFARM_PM91
        tristate "Support for thermal management on PowerMac9,1"
        depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
-       select I2C_PMAC_SMU
+       select I2C_POWERMAC
        help
          This driver provides thermal control for the PowerMac9,1
           which is the recent (SMU based) single CPU desktop G5
index 228e1852a836593af8503ae1075b59e3a7d79e33..2a545ceb523b05cfb57fdf20b8c79e1ca1f5ca2e 100644 (file)
@@ -3,6 +3,13 @@
  * a MacIO ASIC. Interface to new driver model mostly
  * stolen from the PCI version.
  * 
+ *  Copyright (C) 2005 Ben. Herrenschmidt (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.
+ *
  * TODO:
  * 
  *  - Don't probe below media bay by default, but instead provide
@@ -218,12 +225,14 @@ postcore_initcall(macio_bus_driver_init);
 
 
 /**
- * macio_release_dev - free a macio device structure when all users of it are finished.
+ * macio_release_dev - free a macio 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 macio device are
- * done. This currently means never as we don't hot remove any macio device yet,
- * though that will happen with mediabay based devices in a later implementation.
+ * Will be called only by the device core when all users of this macio device
+ * are done. This currently means never as we don't hot remove any macio
+ * device yet, though that will happen with mediabay based devices in a later
+ * implementation.
  */
 static void macio_release_dev(struct device *dev)
 {
@@ -242,49 +251,114 @@ static void macio_release_dev(struct device *dev)
  * If this routine returns non-null, then the resource is completely
  * skipped.
  */
-static int macio_resource_quirks(struct device_node *np, struct resource *res, int index)
+static int macio_resource_quirks(struct device_node *np, struct resource *res,
+                                int index)
 {
        if (res->flags & IORESOURCE_MEM) {
                /* Grand Central has too large resource 0 on some machines */
-               if (index == 0 && !strcmp(np->name, "gc")) {
-                       np->addrs[0].size = 0x20000;
+               if (index == 0 && !strcmp(np->name, "gc"))
                        res->end = res->start + 0x1ffff;
-               }
+
                /* Airport has bogus resource 2 */
                if (index >= 2 && !strcmp(np->name, "radio"))
                        return 1;
+
+#ifndef CONFIG_PPC64
                /* DBDMAs may have bogus sizes */
-               if ((res->start & 0x0001f000) == 0x00008000) {
-                       np->addrs[index].size = 0x100;
+               if ((res->start & 0x0001f000) == 0x00008000)
                        res->end = res->start + 0xff;
-               }
-               /* ESCC parent eats child resources. We could have added a level of hierarchy,
-                * but I don't really feel the need for it */
+#endif /* CONFIG_PPC64 */
+
+               /* ESCC parent eats child resources. We could have added a
+                * level of hierarchy, but I don't really feel the need
+                * for it
+                */
                if (!strcmp(np->name, "escc"))
                        return 1;
+
                /* ESCC has bogus resources >= 3 */
-               if (index >= 3 && !(strcmp(np->name, "ch-a") && strcmp(np->name, "ch-b")))
+               if (index >= 3 && !(strcmp(np->name, "ch-a") &&
+                                   strcmp(np->name, "ch-b")))
                        return 1;
+
                /* Media bay has too many resources, keep only first one */
                if (index > 0 && !strcmp(np->name, "media-bay"))
                        return 1;
+
                /* Some older IDE resources have bogus sizes */
                if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
                      strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
-                       if (index == 0 && np->addrs[0].size > 0x1000) {
-                               np->addrs[0].size = 0x1000;
+                       if (index == 0 && (res->end - res->start) > 0xfff)
                                res->end = res->start + 0xfff;
-                       }
-                       if (index == 1 && np->addrs[1].size > 0x100) {
-                               np->addrs[1].size = 0x100;
+                       if (index == 1 && (res->end - res->start) > 0xff)
                                res->end = res->start + 0xff;
-                       }
                }
        }
        return 0;
 }
 
 
+static void macio_setup_interrupts(struct macio_dev *dev)
+{
+       struct device_node *np = dev->ofdev.node;
+       int i,j;
+
+       /* For now, we use pre-parsed entries in the device-tree for
+        * interrupt routing and addresses, but we should change that
+        * to dynamically parsed entries and so get rid of most of the
+        * clutter in struct device_node
+        */
+       for (i = j = 0; i < np->n_intrs; i++) {
+               struct resource *res = &dev->interrupt[j];
+
+               if (j >= MACIO_DEV_COUNT_IRQS)
+                       break;
+               res->start = np->intrs[i].line;
+               res->flags = IORESOURCE_IO;
+               if (np->intrs[j].sense)
+                       res->flags |= IORESOURCE_IRQ_LOWLEVEL;
+               else
+                       res->flags |= IORESOURCE_IRQ_HIGHEDGE;
+               res->name = dev->ofdev.dev.bus_id;
+               if (macio_resource_quirks(np, res, i))
+                       memset(res, 0, sizeof(struct resource));
+               else
+                       j++;
+       }
+       dev->n_interrupts = j;
+}
+
+static void macio_setup_resources(struct macio_dev *dev,
+                                 struct resource *parent_res)
+{
+       struct device_node *np = dev->ofdev.node;
+       struct resource r;
+       int index;
+
+       for (index = 0; of_address_to_resource(np, index, &r) == 0; index++) {
+               struct resource *res = &dev->resource[index];
+               if (index >= MACIO_DEV_COUNT_RESOURCES)
+                       break;
+               *res = r;
+               res->name = dev->ofdev.dev.bus_id;
+
+               if (macio_resource_quirks(np, res, index)) {
+                       memset(res, 0, sizeof(struct resource));
+                       continue;
+               }
+               /* Currently, we consider failure as harmless, this may
+                * change in the future, once I've found all the device
+                * tree bugs in older machines & worked around them
+                */
+               if (insert_resource(parent_res, res)) {
+                       printk(KERN_WARNING "Can't request resource "
+                              "%d for MacIO device %s\n",
+                              index, dev->ofdev.dev.bus_id);
+               }
+       }
+       dev->n_resources = index;
+}
+
 /**
  * macio_add_one_device - Add one device from OF node to the device tree
  * @chip: pointer to the macio_chip holding the device
@@ -294,12 +368,13 @@ static int macio_resource_quirks(struct device_node *np, struct resource *res, i
  * When media-bay is changed to hotswap drivers, this function will
  * be exposed to the bay driver some way...
  */
-static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct device *parent,
-                                              struct device_node *np, struct macio_dev *in_bay,
+static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
+                                              struct device *parent,
+                                              struct device_node *np,
+                                              struct macio_dev *in_bay,
                                               struct resource *parent_res)
 {
        struct macio_dev *dev;
-       int i, j;
        u32 *reg;
        
        if (np == NULL)
@@ -326,7 +401,8 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct d
 
        /* MacIO itself has a different reg, we use it's PCI base */
        if (np == chip->of_node) {
-               sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s", chip->lbus.index,
+               sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s",
+                       chip->lbus.index,
 #ifdef CONFIG_PCI
                        pci_resource_start(chip->lbus.pdev, 0),
 #else
@@ -335,57 +411,16 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct d
                        MAX_NODE_NAME_SIZE, np->name);
        } else {
                reg = (u32 *)get_property(np, "reg", NULL);
-               sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", chip->lbus.index,
+               sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
+                       chip->lbus.index,
                        reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
        }
 
-       /* For now, we use pre-parsed entries in the device-tree for
-        * interrupt routing and addresses, but we should change that
-        * to dynamically parsed entries and so get rid of most of the
-        * clutter in struct device_node
-        */
-       for (i = j = 0; i < np->n_intrs; i++) {
-               struct resource *res = &dev->interrupt[j];
-
-               if (j >= MACIO_DEV_COUNT_IRQS)
-                       break;
-               res->start = np->intrs[i].line;
-               res->flags = IORESOURCE_IO;
-               if (np->intrs[j].sense)
-                       res->flags |= IORESOURCE_IRQ_LOWLEVEL;
-               else
-                       res->flags |= IORESOURCE_IRQ_HIGHEDGE;
-               res->name = dev->ofdev.dev.bus_id;
-               if (macio_resource_quirks(np, res, i))
-                       memset(res, 0, sizeof(struct resource));
-               else
-                       j++;
-       }
-       dev->n_interrupts = j;
-       for (i = j = 0; i < np->n_addrs; i++) {
-               struct resource *res = &dev->resource[j];
-               
-               if (j >= MACIO_DEV_COUNT_RESOURCES)
-                       break;
-               res->start = np->addrs[i].address;
-               res->end = np->addrs[i].address + np->addrs[i].size - 1;
-               res->flags = IORESOURCE_MEM;
-               res->name = dev->ofdev.dev.bus_id;
-               if (macio_resource_quirks(np, res, i))
-                       memset(res, 0, sizeof(struct resource));
-               else {
-                       j++;
-                       /* Currently, we consider failure as harmless, this may
-                        * change in the future, once I've found all the device
-                        * tree bugs in older machines & worked around them
-                        */
-                       if (insert_resource(parent_res, res))
-                                       printk(KERN_WARNING "Can't request resource %d for MacIO"
-                                      " device %s\n", i, dev->ofdev.dev.bus_id);
-               }
-       }
-       dev->n_resources = j;
+       /* Setup interrupts & resources */
+       macio_setup_interrupts(dev);
+       macio_setup_resources(dev, parent_res);
 
+       /* Register with core */
        if (of_device_register(&dev->ofdev) != 0) {
                printk(KERN_DEBUG"macio: device registration error for %s!\n",
                       dev->ofdev.dev.bus_id);
@@ -442,36 +477,42 @@ static void macio_pci_add_devices(struct macio_chip *chip)
 
        /* First scan 1st level */
        for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
-               if (!macio_skip_device(np)) {
-                       of_node_get(np);
-                       mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL, root_res);
-                       if (mdev == NULL)
-                               of_node_put(np);
-                       else if (strncmp(np->name, "media-bay", 9) == 0)
-                               mbdev = mdev;
-                       else if (strncmp(np->name, "escc", 4) == 0)
-                               sdev = mdev;
-               }
+               if (macio_skip_device(np))
+                       continue;
+               of_node_get(np);
+               mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL,
+                                           root_res);
+               if (mdev == NULL)
+                       of_node_put(np);
+               else if (strncmp(np->name, "media-bay", 9) == 0)
+                       mbdev = mdev;
+               else if (strncmp(np->name, "escc", 4) == 0)
+                       sdev = mdev;
        }
 
        /* Add media bay devices if any */
        if (mbdev)
-               for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np)) != NULL;)
-                       if (!macio_skip_device(np)) {
-                               of_node_get(np);
-                               if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev,
-                                                        root_res) == NULL)
-                                       of_node_put(np);
-                       }
+               for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np))
+                            != NULL;) {
+                       if (macio_skip_device(np))
+                               continue;
+                       of_node_get(np);
+                       if (macio_add_one_device(chip, &mbdev->ofdev.dev, np,
+                                                mbdev,  root_res) == NULL)
+                               of_node_put(np);
+               }
+
        /* Add serial ports if any */
        if (sdev) {
-               for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np)) != NULL;)
-                       if (!macio_skip_device(np)) {
-                               of_node_get(np);
-                               if (macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL,
-                                                        root_res) == NULL)
-                                       of_node_put(np);
-                       }
+               for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np))
+                            != NULL;) {
+                       if (macio_skip_device(np))
+                               continue;
+                       of_node_get(np);
+                       if (macio_add_one_device(chip, &sdev->ofdev.dev, np,
+                                                NULL, root_res) == NULL)
+                               of_node_put(np);
+               }
        }
 }
 
@@ -519,7 +560,8 @@ void macio_unregister_driver(struct macio_driver *drv)
  *     Returns 0 on success, or %EBUSY on error.  A warning
  *     message is also printed on failure.
  */
-int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name)
+int macio_request_resource(struct macio_dev *dev, int resource_no,
+                          const char *name)
 {
        if (macio_resource_len(dev, resource_no) == 0)
                return 0;
@@ -606,20 +648,20 @@ static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_devi
        if (ent->vendor != PCI_VENDOR_ID_APPLE)
                return -ENODEV;
 
-       /* Note regarding refcounting: We assume pci_device_to_OF_node() is ported
-        * to new OF APIs and returns a node with refcount incremented. This isn't
-        * the case today, but on the other hand ppc32 doesn't do refcounting. This
-        * will have to be fixed when going to ppc64. --BenH.
+       /* Note regarding refcounting: We assume pci_device_to_OF_node() is
+        * ported to new OF APIs and returns a node with refcount incremented.
         */
        np = pci_device_to_OF_node(pdev);
        if (np == NULL)
                return -ENODEV;
 
-       /* This assumption is wrong, fix that here for now until I fix the arch */
+       /* The above assumption is wrong !!!
+        * fix that here for now until I fix the arch code
+        */
        of_node_get(np);
 
-       /* We also assume that pmac_feature will have done a get() on nodes stored
-        * in the macio chips array
+       /* We also assume that pmac_feature will have done a get() on nodes
+        * stored in the macio chips array
         */
        chip = macio_find(np, macio_unknown);
                of_node_put(np);
@@ -639,9 +681,9 @@ static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_devi
 
        /*
         * HACK ALERT: The WallStreet PowerBook and some OHare based machines
-        * have 2 macio ASICs. I must probe the "main" one first or IDE ordering
-        * will be incorrect. So I put on "hold" the second one since it seem to
-        * appear first on PCI
+        * have 2 macio ASICs. I must probe the "main" one first or IDE
+        * ordering will be incorrect. So I put on "hold" the second one since
+        * it seem to appear first on PCI
         */
        if (chip->type == macio_gatwick || chip->type == macio_ohareII)
                if (macio_chips[0].lbus.pdev == NULL) {
index b856bb67169cf9dcaef51e2c5a4c700b28b7f001..8dbf2852bae03f8b3c4a780effbef97397f123f2 100644 (file)
@@ -647,6 +647,7 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de
        struct media_bay_info* bay;
        u32 __iomem *regbase;
        struct device_node *ofnode;
+       unsigned long base;
        int i;
 
        ofnode = mdev->ofdev.node;
@@ -656,10 +657,11 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de
        if (macio_request_resources(mdev, "media-bay"))
                return -EBUSY;
        /* Media bay registers are located at the beginning of the
-         * mac-io chip, we get the parent address for now (hrm...)
+         * mac-io chip, for now, we trick and align down the first
+        * resource passed in
          */
-       regbase = (u32 __iomem *)
-               ioremap(ofnode->parent->addrs[0].address, 0x100);
+       base = macio_resource_start(mdev, 0) & 0xffff0000u;
+       regbase = (u32 __iomem *)ioremap(base, 0x100);
        if (regbase == NULL) {
                macio_release_resources(mdev);
                return -ENOMEM;
index e8378274d710f02f0d93facd8de2fa050ec6e4f4..db2ae71d07ef08511f480c5f6b7978b68772daaa 100644 (file)
@@ -53,7 +53,7 @@
 #undef DEBUG_SMU
 
 #ifdef DEBUG_SMU
-#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0)
+#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0)
 #else
 #define DPRINTK(fmt, args...) do { } while (0)
 #endif
@@ -94,6 +94,8 @@ struct smu_device {
 static struct smu_device       *smu;
 static DECLARE_MUTEX(smu_part_access);
 
+static void smu_i2c_retry(unsigned long data);
+
 /*
  * SMU driver low level stuff
  */
@@ -469,7 +471,6 @@ int __init smu_init (void)
        smu->of_node = np;
        smu->db_irq = NO_IRQ;
        smu->msg_irq = NO_IRQ;
-       init_timer(&smu->i2c_timer);
 
        /* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a
         * 32 bits value safely
@@ -544,6 +545,10 @@ static int smu_late_init(void)
        if (!smu)
                return 0;
 
+       init_timer(&smu->i2c_timer);
+       smu->i2c_timer.function = smu_i2c_retry;
+       smu->i2c_timer.data = (unsigned long)smu;
+
        /*
         * Try to request the interrupts
         */
@@ -570,7 +575,10 @@ static int smu_late_init(void)
 
        return 0;
 }
-arch_initcall(smu_late_init);
+/* This has to be before arch_initcall as the low i2c stuff relies on the
+ * above having been done before we reach arch_initcalls
+ */
+core_initcall(smu_late_init);
 
 /*
  * sysfs visibility
@@ -580,20 +588,10 @@ static void smu_expose_childs(void *unused)
 {
        struct device_node *np;
 
-       for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) {
-               if (device_is_compatible(np, "smu-i2c")) {
-                       char name[32];
-                       u32 *reg = (u32 *)get_property(np, "reg", NULL);
-
-                       if (reg == NULL)
-                               continue;
-                       sprintf(name, "smu-i2c-%02x", *reg);
-                       of_platform_device_create(np, name, &smu->of_dev->dev);
-               }
+       for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;)
                if (device_is_compatible(np, "smu-sensors"))
-                       of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev);
-       }
-
+                       of_platform_device_create(np, "smu-sensors",
+                                                 &smu->of_dev->dev);
 }
 
 static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs, NULL);
@@ -712,13 +710,13 @@ static void smu_i2c_complete_command(struct smu_i2c_cmd *cmd, int fail)
 
 static void smu_i2c_retry(unsigned long data)
 {
-       struct smu_i2c_cmd      *cmd = (struct smu_i2c_cmd *)data;
+       struct smu_i2c_cmd      *cmd = smu->cmd_i2c_cur;
 
        DPRINTK("SMU: i2c failure, requeuing...\n");
 
        /* requeue command simply by resetting reply_len */
        cmd->pdata[0] = 0xff;
-       cmd->scmd.reply_len = 0x10;
+       cmd->scmd.reply_len = sizeof(cmd->pdata);
        smu_queue_cmd(&cmd->scmd);
 }
 
@@ -747,10 +745,8 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
         */
        if (fail && --cmd->retries > 0) {
                DPRINTK("SMU: i2c failure, starting timer...\n");
-               smu->i2c_timer.function = smu_i2c_retry;
-               smu->i2c_timer.data = (unsigned long)cmd;
-               smu->i2c_timer.expires = jiffies + msecs_to_jiffies(5);
-               add_timer(&smu->i2c_timer);
+               BUG_ON(cmd != smu->cmd_i2c_cur);
+               mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5));
                return;
        }
 
@@ -764,7 +760,7 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
 
        /* Ok, initial command complete, now poll status */
        scmd->reply_buf = cmd->pdata;
-       scmd->reply_len = 0x10;
+       scmd->reply_len = sizeof(cmd->pdata);
        scmd->data_buf = cmd->pdata;
        scmd->data_len = 1;
        cmd->pdata[0] = 0;
@@ -786,7 +782,7 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
        cmd->scmd.done = smu_i2c_low_completion;
        cmd->scmd.misc = cmd;
        cmd->scmd.reply_buf = cmd->pdata;
-       cmd->scmd.reply_len = 0x10;
+       cmd->scmd.reply_len = sizeof(cmd->pdata);
        cmd->scmd.data_buf = (u8 *)(char *)&cmd->info;
        cmd->scmd.status = 1;
        cmd->stage = 0;
@@ -909,10 +905,13 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
        struct property *prop;
 
        /* First query the partition info */
+       DPRINTK("SMU: Query partition infos ... (irq=%d)\n", smu->db_irq);
        smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
                         smu_done_complete, &comp,
                         SMU_CMD_PARTITION_LATEST, id);
        wait_for_completion(&comp);
+       DPRINTK("SMU: done, status: %d, reply_len: %d\n",
+               cmd.cmd.status, cmd.cmd.reply_len);
 
        /* Partition doesn't exist (or other error) */
        if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
@@ -975,6 +974,8 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
 
        sprintf(pname, "sdb-partition-%02x", id);
 
+       DPRINTK("smu_get_sdb_partition(%02x)\n", id);
+
        if (interruptible) {
                int rc;
                rc = down_interruptible(&smu_part_access);
@@ -986,6 +987,7 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
        part = (struct smu_sdbp_header *)get_property(smu->of_node,
                                                      pname, size);
        if (part == NULL) {
+               DPRINTK("trying to extract from SMU ...\n");
                part = smu_create_sdb_partition(id);
                if (part != NULL && size)
                        *size = part->len << 2;
index d843a6c9c6df8d44ec7ec0c979835cb23591a37b..2d9d79150403b17996f034a8165a45ea28a687b5 100644 (file)
@@ -127,39 +127,34 @@ struct adb_driver via_cuda_driver = {
 #endif /* CONFIG_ADB */
 
 #ifdef CONFIG_PPC
-int __init
-find_via_cuda(void)
+int __init find_via_cuda(void)
 {
-    int err;
     struct adb_request req;
+    phys_addr_t taddr;
+    u32 *reg;
+    int err;
 
     if (vias != 0)
        return 1;
-    vias = find_devices("via-cuda");
+    vias = of_find_node_by_name(NULL, "via-cuda");
     if (vias == 0)
        return 0;
-    if (vias->next != 0)
-       printk(KERN_WARNING "Warning: only using 1st via-cuda\n");
-
-#if 0
-    { int i;
-
-    printk("find_via_cuda: node = %p, addrs =", vias->node);
-    for (i = 0; i < vias->n_addrs; ++i)
-       printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
-    printk(", intrs =");
-    for (i = 0; i < vias->n_intrs; ++i)
-       printk(" %x", vias->intrs[i].line);
-    printk("\n"); }
-#endif
 
-    if (vias->n_addrs != 1 || vias->n_intrs != 1) {
-       printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n",
-              vias->n_addrs, vias->n_intrs);
-       if (vias->n_addrs < 1 || vias->n_intrs < 1)
-           return 0;
+    reg = (u32 *)get_property(vias, "reg", NULL);
+    if (reg == NULL) {
+           printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
+           goto fail;
+    }
+    taddr = of_translate_address(vias, reg);
+    if (taddr == 0) {
+           printk(KERN_ERR "via-cuda: Can't translate address !\n");
+           goto fail;
+    }
+    via = ioremap(taddr, 0x2000);
+    if (via == NULL) {
+           printk(KERN_ERR "via-cuda: Can't map address !\n");
+           goto fail;
     }
-    via = ioremap(vias->addrs->address, 0x2000);
 
     cuda_state = idle;
     sys_ctrler = SYS_CTRLER_CUDA;
@@ -185,6 +180,11 @@ find_via_cuda(void)
        cuda_poll();
 
     return 1;
+
+ fail:
+    of_node_put(vias);
+    vias = NULL;
+    return 0;
 }
 #endif /* CONFIG_PPC */
 
@@ -193,10 +193,6 @@ static int __init via_cuda_start(void)
     if (via == NULL)
        return -ENODEV;
 
-#ifdef CONFIG_PPC
-    request_OF_resource(vias, 0, NULL);
-#endif
-
     if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
        printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
        return -EAGAIN;
index 5640435085694fdbefddf0e7c1a18bef2e221b75..6eb93e45fcd3f624005714b5c27dc7205e703c12 100644 (file)
@@ -55,6 +55,8 @@
 #include <asm/sections.h>
 #include <asm/irq.h>
 #include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+#include <asm/pmac_low_i2c.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/cputable.h>
@@ -147,6 +149,7 @@ static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
 static int pmu_has_adb;
+static struct device_node *gpio_node;
 static unsigned char __iomem *gpio_reg = NULL;
 static int gpio_irq = -1;
 static int gpio_irq_enabled = -1;
@@ -157,8 +160,8 @@ static int pmu_version;
 static int drop_interrupts;
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 static int option_lid_wakeup = 1;
-static int sleep_in_progress;
 #endif /* CONFIG_PM && CONFIG_PPC32 */
+static int sleep_in_progress;
 static unsigned long async_req_locks;
 static unsigned int pmu_irq_stats[11];
 
@@ -196,7 +199,6 @@ static int pmu_adb_reset_bus(void);
 #endif /* CONFIG_ADB */
 
 static int init_pmu(void);
-static int pmu_queue_request(struct adb_request *req);
 static void pmu_start(void);
 static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
 static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
@@ -295,22 +297,26 @@ static struct backlight_controller pmu_backlight_controller = {
 };
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
-int
-find_via_pmu(void)
+int __init find_via_pmu(void)
 {
+       u64 taddr;
+       u32 *reg;
+
        if (via != 0)
                return 1;
-       vias = find_devices("via-pmu");
-       if (vias == 0)
+       vias = of_find_node_by_name(NULL, "via-pmu");
+       if (vias == NULL)
                return 0;
-       if (vias->next != 0)
-               printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
 
-       if (vias->n_addrs < 1 || vias->n_intrs < 1) {
-               printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
-                      vias->n_addrs, vias->n_intrs);
-               if (vias->n_addrs < 1 || vias->n_intrs < 1)
-                       return 0;
+       reg = (u32 *)get_property(vias, "reg", NULL);
+       if (reg == NULL) {
+               printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
+               goto fail;
+       }
+       taddr = of_translate_address(vias, reg);
+       if (taddr == OF_BAD_ADDR) {
+               printk(KERN_ERR "via-pmu: Can't translate address !\n");
+               goto fail;
        }
 
        spin_lock_init(&pmu_lock);
@@ -331,7 +337,8 @@ find_via_pmu(void)
                pmu_kind = PMU_HEATHROW_BASED;
        else if (device_is_compatible(vias->parent, "Keylargo")
                 || device_is_compatible(vias->parent, "K2-Keylargo")) {
-               struct device_node *gpio, *gpiop;
+               struct device_node *gpiop;
+               u64 gaddr = OF_BAD_ADDR;
 
                pmu_kind = PMU_KEYLARGO_BASED;
                pmu_has_adb = (find_type_devices("adb") != NULL);
@@ -341,19 +348,24 @@ find_via_pmu(void)
                                PMU_INT_TICK |
                                PMU_INT_ENVIRONMENT;
                
-               gpiop = find_devices("gpio");
-               if (gpiop && gpiop->n_addrs) {
-                       gpio_reg = ioremap(gpiop->addrs->address, 0x10);
-                       gpio = find_devices("extint-gpio1");
-                       if (gpio == NULL)
-                               gpio = find_devices("pmu-interrupt");
-                       if (gpio && gpio->parent == gpiop && gpio->n_intrs)
-                               gpio_irq = gpio->intrs[0].line;
+               gpiop = of_find_node_by_name(NULL, "gpio");
+               if (gpiop) {
+                       reg = (u32 *)get_property(gpiop, "reg", NULL);
+                       if (reg)
+                               gaddr = of_translate_address(gpiop, reg);
+                       if (gaddr != OF_BAD_ADDR)
+                               gpio_reg = ioremap(gaddr, 0x10);
                }
+               if (gpio_reg == NULL)
+                       printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n");
        } else
                pmu_kind = PMU_UNKNOWN;
 
-       via = ioremap(vias->addrs->address, 0x2000);
+       via = ioremap(taddr, 0x2000);
+       if (via == NULL) {
+               printk(KERN_ERR "via-pmu: Can't map address !\n");
+               goto fail;
+       }
        
        out_8(&via[IER], IER_CLR | 0x7f);       /* disable all intrs */
        out_8(&via[IFR], 0x7f);                 /* clear IFR */
@@ -365,23 +377,25 @@ find_via_pmu(void)
                return 0;
        }
 
-       printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n",
+       printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
               PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
               
        sys_ctrler = SYS_CTRLER_PMU;
        
        return 1;
+ fail:
+       of_node_put(vias);
+       vias = NULL;
+       return 0;
 }
 
 #ifdef CONFIG_ADB
-static int
-pmu_probe(void)
+static int pmu_probe(void)
 {
        return vias == NULL? -ENODEV: 0;
 }
 
-static int __init
-pmu_init(void)
+static int __init pmu_init(void)
 {
        if (vias == NULL)
                return -ENODEV;
@@ -405,7 +419,7 @@ static int __init via_pmu_start(void)
        bright_req_2.complete = 1;
        batt_req.complete = 1;
 
-#if defined(CONFIG_PPC32) && !defined(CONFIG_PPC_MERGE)
+#ifndef CONFIG_PPC_MERGE
        if (pmu_kind == PMU_KEYLARGO_BASED)
                openpic_set_irq_priority(vias->intrs[0].line,
                                         OPENPIC_PRIORITY_DEFAULT + 1);
@@ -418,10 +432,22 @@ static int __init via_pmu_start(void)
                return -EAGAIN;
        }
 
-       if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {
-               if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1 ADB", (void *)0))
-                       printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);
-               gpio_irq_enabled = 1;
+       if (pmu_kind == PMU_KEYLARGO_BASED) {
+               gpio_node = of_find_node_by_name(NULL, "extint-gpio1");
+               if (gpio_node == NULL)
+                       gpio_node = of_find_node_by_name(NULL,
+                                                        "pmu-interrupt");
+               if (gpio_node && gpio_node->n_intrs > 0)
+                       gpio_irq = gpio_node->intrs[0].line;
+
+               if (gpio_irq != -1) {
+                       if (request_irq(gpio_irq, gpio1_interrupt, 0,
+                                       "GPIO1 ADB", (void *)0))
+                               printk(KERN_ERR "pmu: can't get irq %d"
+                                      " (GPIO1)\n", gpio_irq);
+                       else
+                               gpio_irq_enabled = 1;
+               }
        }
 
        /* Enable interrupts */
@@ -454,9 +480,6 @@ static int __init via_pmu_dev_init(void)
        if (vias == NULL)
                return -ENODEV;
 
-#ifndef CONFIG_PPC64
-       request_OF_resource(vias, 0, NULL);
-#endif
 #ifdef CONFIG_PMAC_BACKLIGHT
        /* Enable backlight */
        register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
@@ -1371,7 +1394,6 @@ next:
                        }
                        pmu_done(req);
                } else {
-#if defined(CONFIG_XMON) && !defined(CONFIG_PPC64)
                        if (len == 4 && data[1] == 0x2c) {
                                extern int xmon_wants_key, xmon_adb_keycode;
                                if (xmon_wants_key) {
@@ -1379,7 +1401,6 @@ next:
                                        return;
                                }
                        }
-#endif /* defined(CONFIG_XMON) && !defined(CONFIG_PPC64) */
 #ifdef CONFIG_ADB
                        /*
                         * XXX On the [23]400 the PMU gives us an up
@@ -1782,258 +1803,6 @@ pmu_present(void)
        return via != 0;
 }
 
-struct pmu_i2c_hdr {
-       u8      bus;
-       u8      mode;
-       u8      bus2;
-       u8      address;
-       u8      sub_addr;
-       u8      comb_addr;
-       u8      count;
-};
-
-int
-pmu_i2c_combined_read(int bus, int addr, int subaddr,  u8* data, int len)
-{
-       struct adb_request      req;
-       struct pmu_i2c_hdr      *hdr = (struct pmu_i2c_hdr *)&req.data[1];
-       int retry;
-       int rc;
-
-       for (retry=0; retry<16; retry++) {
-               memset(&req, 0, sizeof(req));
-
-               hdr->bus = bus;
-               hdr->address = addr & 0xfe;
-               hdr->mode = PMU_I2C_MODE_COMBINED;
-               hdr->bus2 = 0;
-               hdr->sub_addr = subaddr;
-               hdr->comb_addr = addr | 1;
-               hdr->count = len;
-               
-               req.nbytes = sizeof(struct pmu_i2c_hdr) + 1;
-               req.reply_expected = 0;
-               req.reply_len = 0;
-               req.data[0] = PMU_I2C_CMD;
-               req.reply[0] = 0xff;
-               rc = pmu_queue_request(&req);
-               if (rc)
-                       return rc;
-               while(!req.complete)
-                       pmu_poll();
-               if (req.reply[0] == PMU_I2C_STATUS_OK)
-                       break;
-               mdelay(15);
-       }
-       if (req.reply[0] != PMU_I2C_STATUS_OK)
-               return -1;
-
-       for (retry=0; retry<16; retry++) {
-               memset(&req, 0, sizeof(req));
-
-               mdelay(15);
-
-               hdr->bus = PMU_I2C_BUS_STATUS;
-               req.reply[0] = 0xff;
-               
-               req.nbytes = 2;
-               req.reply_expected = 0;
-               req.reply_len = 0;
-               req.data[0] = PMU_I2C_CMD;
-               rc = pmu_queue_request(&req);
-               if (rc)
-                       return rc;
-               while(!req.complete)
-                       pmu_poll();
-               if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) {
-                       memcpy(data, &req.reply[1], req.reply_len - 1);
-                       return req.reply_len - 1;
-               }
-       }
-       return -1;
-}
-
-int
-pmu_i2c_stdsub_write(int bus, int addr, int subaddr,  u8* data, int len)
-{
-       struct adb_request      req;
-       struct pmu_i2c_hdr      *hdr = (struct pmu_i2c_hdr *)&req.data[1];
-       int retry;
-       int rc;
-
-       for (retry=0; retry<16; retry++) {
-               memset(&req, 0, sizeof(req));
-
-               hdr->bus = bus;
-               hdr->address = addr & 0xfe;
-               hdr->mode = PMU_I2C_MODE_STDSUB;
-               hdr->bus2 = 0;
-               hdr->sub_addr = subaddr;
-               hdr->comb_addr = addr & 0xfe;
-               hdr->count = len;
-
-               req.data[0] = PMU_I2C_CMD;
-               memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len);
-               req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1;
-               req.reply_expected = 0;
-               req.reply_len = 0;
-               req.reply[0] = 0xff;
-               rc = pmu_queue_request(&req);
-               if (rc)
-                       return rc;
-               while(!req.complete)
-                       pmu_poll();
-               if (req.reply[0] == PMU_I2C_STATUS_OK)
-                       break;
-               mdelay(15);
-       }
-       if (req.reply[0] != PMU_I2C_STATUS_OK)
-               return -1;
-
-       for (retry=0; retry<16; retry++) {
-               memset(&req, 0, sizeof(req));
-
-               mdelay(15);
-
-               hdr->bus = PMU_I2C_BUS_STATUS;
-               req.reply[0] = 0xff;
-               
-               req.nbytes = 2;
-               req.reply_expected = 0;
-               req.reply_len = 0;
-               req.data[0] = PMU_I2C_CMD;
-               rc = pmu_queue_request(&req);
-               if (rc)
-                       return rc;
-               while(!req.complete)
-                       pmu_poll();
-               if (req.reply[0] == PMU_I2C_STATUS_OK)
-                       return len;
-       }
-       return -1;
-}
-
-int
-pmu_i2c_simple_read(int bus, int addr,  u8* data, int len)
-{
-       struct adb_request      req;
-       struct pmu_i2c_hdr      *hdr = (struct pmu_i2c_hdr *)&req.data[1];
-       int retry;
-       int rc;
-
-       for (retry=0; retry<16; retry++) {
-               memset(&req, 0, sizeof(req));
-
-               hdr->bus = bus;
-               hdr->address = addr | 1;
-               hdr->mode = PMU_I2C_MODE_SIMPLE;
-               hdr->bus2 = 0;
-               hdr->sub_addr = 0;
-               hdr->comb_addr = 0;
-               hdr->count = len;
-
-               req.data[0] = PMU_I2C_CMD;
-               req.nbytes = sizeof(struct pmu_i2c_hdr) + 1;
-               req.reply_expected = 0;
-               req.reply_len = 0;
-               req.reply[0] = 0xff;
-               rc = pmu_queue_request(&req);
-               if (rc)
-                       return rc;
-               while(!req.complete)
-                       pmu_poll();
-               if (req.reply[0] == PMU_I2C_STATUS_OK)
-                       break;
-               mdelay(15);
-       }
-       if (req.reply[0] != PMU_I2C_STATUS_OK)
-               return -1;
-
-       for (retry=0; retry<16; retry++) {
-               memset(&req, 0, sizeof(req));
-
-               mdelay(15);
-
-               hdr->bus = PMU_I2C_BUS_STATUS;
-               req.reply[0] = 0xff;
-               
-               req.nbytes = 2;
-               req.reply_expected = 0;
-               req.reply_len = 0;
-               req.data[0] = PMU_I2C_CMD;
-               rc = pmu_queue_request(&req);
-               if (rc)
-                       return rc;
-               while(!req.complete)
-                       pmu_poll();
-               if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) {
-                       memcpy(data, &req.reply[1], req.reply_len - 1);
-                       return req.reply_len - 1;
-               }
-       }
-       return -1;
-}
-
-int
-pmu_i2c_simple_write(int bus, int addr,  u8* data, int len)
-{
-       struct adb_request      req;
-       struct pmu_i2c_hdr      *hdr = (struct pmu_i2c_hdr *)&req.data[1];
-       int retry;
-       int rc;
-
-       for (retry=0; retry<16; retry++) {
-               memset(&req, 0, sizeof(req));
-
-               hdr->bus = bus;
-               hdr->address = addr & 0xfe;
-               hdr->mode = PMU_I2C_MODE_SIMPLE;
-               hdr->bus2 = 0;
-               hdr->sub_addr = 0;
-               hdr->comb_addr = 0;
-               hdr->count = len;
-
-               req.data[0] = PMU_I2C_CMD;
-               memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len);
-               req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1;
-               req.reply_expected = 0;
-               req.reply_len = 0;
-               req.reply[0] = 0xff;
-               rc = pmu_queue_request(&req);
-               if (rc)
-                       return rc;
-               while(!req.complete)
-                       pmu_poll();
-               if (req.reply[0] == PMU_I2C_STATUS_OK)
-                       break;
-               mdelay(15);
-       }
-       if (req.reply[0] != PMU_I2C_STATUS_OK)
-               return -1;
-
-       for (retry=0; retry<16; retry++) {
-               memset(&req, 0, sizeof(req));
-
-               mdelay(15);
-
-               hdr->bus = PMU_I2C_BUS_STATUS;
-               req.reply[0] = 0xff;
-               
-               req.nbytes = 2;
-               req.reply_expected = 0;
-               req.reply_len = 0;
-               req.data[0] = PMU_I2C_CMD;
-               rc = pmu_queue_request(&req);
-               if (rc)
-                       return rc;
-               while(!req.complete)
-                       pmu_poll();
-               if (req.reply[0] == PMU_I2C_STATUS_OK)
-                       return len;
-       }
-       return -1;
-}
-
 #ifdef CONFIG_PM
 
 static LIST_HEAD(sleep_notifiers);
@@ -2338,8 +2107,9 @@ pmac_suspend_devices(void)
                return -EBUSY;
        }
 
-       /* Disable clock spreading on some machines */
-       pmac_tweak_clock_spreading(0);
+       /* Call platform functions marked "on sleep" */
+       pmac_pfunc_i2c_suspend();
+       pmac_pfunc_base_suspend();
 
        /* Stop preemption */
        preempt_disable();
@@ -2411,8 +2181,9 @@ pmac_wakeup_devices(void)
        mdelay(10);
        preempt_enable();
 
-       /* Re-enable clock spreading on some machines */
-       pmac_tweak_clock_spreading(1);
+       /* Call platform functions marked "on wake" */
+       pmac_pfunc_base_resume();
+       pmac_pfunc_i2c_resume();
 
        /* Resume devices */
        device_resume();
@@ -3130,16 +2901,13 @@ static int __init init_pmu_sysfs(void)
 subsys_initcall(init_pmu_sysfs);
 
 EXPORT_SYMBOL(pmu_request);
+EXPORT_SYMBOL(pmu_queue_request);
 EXPORT_SYMBOL(pmu_poll);
 EXPORT_SYMBOL(pmu_poll_adb);
 EXPORT_SYMBOL(pmu_wait_complete);
 EXPORT_SYMBOL(pmu_suspend);
 EXPORT_SYMBOL(pmu_resume);
 EXPORT_SYMBOL(pmu_unlock);
-EXPORT_SYMBOL(pmu_i2c_combined_read);
-EXPORT_SYMBOL(pmu_i2c_stdsub_write);
-EXPORT_SYMBOL(pmu_i2c_simple_read);
-EXPORT_SYMBOL(pmu_i2c_simple_write);
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 EXPORT_SYMBOL(pmu_enable_irled);
 EXPORT_SYMBOL(pmu_battery_count);
index 57460e46c89f2152d9df180b020a7379bf2c7f25..906d3ecae6e69e043a31835963c17695a61fdc4c 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/sections.h>
+#include <asm/pmac_low_i2c.h>
 
 #include "windfarm.h"
 
@@ -157,53 +158,21 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
 
 static int wf_lm75_attach(struct i2c_adapter *adapter)
 {
-       u8 bus_id;
-       struct device_node *smu, *bus, *dev;
-
-       /* We currently only deal with LM75's hanging off the SMU
-        * i2c busses. If we extend that driver to other/older
-        * machines, we should split this function into SMU-i2c,
-        * keywest-i2c, PMU-i2c, ...
-        */
+       struct device_node *busnode, *dev;
+       struct pmac_i2c_bus *bus;
 
        DBG("wf_lm75: adapter %s detected\n", adapter->name);
 
-       if (strncmp(adapter->name, "smu-i2c-", 8) != 0)
-               return 0;
-       smu = of_find_node_by_type(NULL, "smu");
-       if (smu == NULL)
-               return 0;
-
-       /* Look for the bus in the device-tree */
-       bus_id = (u8)simple_strtoul(adapter->name + 8, NULL, 16);
-
-       DBG("wf_lm75: bus ID is %x\n", bus_id);
-
-       /* Look for sensors subdir */
-       for (bus = NULL;
-            (bus = of_get_next_child(smu, bus)) != NULL;) {
-               u32 *reg;
-
-               if (strcmp(bus->name, "i2c"))
-                       continue;
-               reg = (u32 *)get_property(bus, "reg", NULL);
-               if (reg == NULL)
-                       continue;
-               if (bus_id == *reg)
-                       break;
-       }
-       of_node_put(smu);
-       if (bus == NULL) {
-               printk(KERN_WARNING "windfarm: SMU i2c bus 0x%x not found"
-                      " in device-tree !\n", bus_id);
-               return 0;
-       }
+       bus = pmac_i2c_adapter_to_bus(adapter);
+       if (bus == NULL)
+               return -ENODEV;
+       busnode = pmac_i2c_get_bus_node(bus);
 
        DBG("wf_lm75: bus found, looking for device...\n");
 
        /* Now look for lm75(s) in there */
        for (dev = NULL;
-            (dev = of_get_next_child(bus, dev)) != NULL;) {
+            (dev = of_get_next_child(busnode, dev)) != NULL;) {
                const char *loc =
                        get_property(dev, "hwsensor-location", NULL);
                u32 *reg = (u32 *)get_property(dev, "reg", NULL);
@@ -217,9 +186,6 @@ static int wf_lm75_attach(struct i2c_adapter *adapter)
                else if (device_is_compatible(dev, "ds1775"))
                        wf_lm75_create(adapter, *reg, 1, loc);
        }
-
-       of_node_put(bus);
-
        return 0;
 }
 
index 2c3158c81ff24b38e10d7d915a02a33eed1d8b5d..4d811600bdab471a16d924f241fd4bd3adfe602f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/wait.h>
+#include <linux/completion.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
index b558cc209d4930394c05006719929469b11b2ca8..1a00d9c75a233cb267c55863cf0c90b4207bf35b 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/wait.h>
+#include <linux/completion.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
index 1b76fb29fb7065b1ac52aaa1db009515e16e46ca..e423a16ba3c95c6778c0051bd5bc0a4f6b056c2e 100644 (file)
@@ -3598,12 +3598,21 @@ static int set_disk_faulty(mddev_t *mddev, dev_t dev)
        return 0;
 }
 
+static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       mddev_t *mddev = bdev->bd_disk->private_data;
+
+       geo->heads = 2;
+       geo->sectors = 4;
+       geo->cylinders = get_capacity(mddev->gendisk) / 8;
+       return 0;
+}
+
 static int md_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
        int err = 0;
        void __user *argp = (void __user *)arg;
-       struct hd_geometry __user *loc = argp;
        mddev_t *mddev = NULL;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -3765,24 +3774,6 @@ static int md_ioctl(struct inode *inode, struct file *file,
         * 4 sectors (with a BIG number of cylinders...). This drives
         * dosfs just mad... ;-)
         */
-               case HDIO_GETGEO:
-                       if (!loc) {
-                               err = -EINVAL;
-                               goto abort_unlock;
-                       }
-                       err = put_user (2, (char __user *) &loc->heads);
-                       if (err)
-                               goto abort_unlock;
-                       err = put_user (4, (char __user *) &loc->sectors);
-                       if (err)
-                               goto abort_unlock;
-                       err = put_user(get_capacity(mddev->gendisk)/8,
-                                       (short __user *) &loc->cylinders);
-                       if (err)
-                               goto abort_unlock;
-                       err = put_user (get_start_sect(inode->i_bdev),
-                                               (long __user *) &loc->start);
-                       goto done_unlock;
        }
 
        /*
@@ -3911,6 +3902,7 @@ static struct block_device_operations md_fops =
        .open           = md_open,
        .release        = md_release,
        .ioctl          = md_ioctl,
+       .getgeo         = md_getgeo,
        .media_changed  = md_media_changed,
        .revalidate_disk= md_revalidate,
 };
index abbca150202b4263cf6f573da3988803d1c3980d..d03f99cf4b7dfa936af326eef8ceb0586709fd5a 100644 (file)
@@ -306,9 +306,6 @@ static int raid0_run (mddev_t *mddev)
        printk("raid0 : conf->hash_spacing is %llu blocks.\n",
                (unsigned long long)conf->hash_spacing);
        {
-#if __GNUC__ < 3
-               volatile
-#endif
                sector_t s = mddev->array_size;
                sector_t space = conf->hash_spacing;
                int round;
@@ -439,9 +436,6 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio)
  
 
        {
-#if __GNUC__ < 3
-               volatile
-#endif
                sector_t x = block >> conf->preshift;
                sector_div(x, (u32)conf->hash_spacing);
                zone = conf->hash_table[x];
index 09ec964dec5c07742e4afa923c80f7f360762a07..b614612be7b439252c97451ced9e9de34a93609e 100644 (file)
@@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file)
 
        if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                DEB_S(("initializing vbi...\n"));
-               result = saa7146_vbi_uops.open(dev,file);
+               if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       result = saa7146_vbi_uops.open(dev,file);
+               if (dev->ext_vv_data->vbi_fops.open)
+                       dev->ext_vv_data->vbi_fops.open(inode, file);
        } else {
                DEB_S(("initializing video...\n"));
                result = saa7146_video_uops.open(dev,file);
@@ -289,7 +292,10 @@ static int fops_release(struct inode *inode, struct file *file)
                return -ERESTARTSYS;
 
        if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               saa7146_vbi_uops.release(dev,file);
+               if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       saa7146_vbi_uops.release(dev,file);
+               if (dev->ext_vv_data->vbi_fops.release)
+                       dev->ext_vv_data->vbi_fops.release(inode, file);
        } else {
                saa7146_video_uops.release(dev,file);
        }
@@ -332,6 +338,7 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
                BUG();
                return 0;
        }
+
        return videobuf_mmap_mapper(q,vma);
 }
 
@@ -381,7 +388,10 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
                }
        case V4L2_BUF_TYPE_VBI_CAPTURE: {
 //             DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
-               return saa7146_vbi_uops.read(file,data,count,ppos);
+               if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       return saa7146_vbi_uops.read(file,data,count,ppos);
+               else
+                       return -EINVAL;
                }
                break;
        default:
@@ -390,12 +400,31 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
        }
 }
 
+static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+       struct saa7146_fh *fh = file->private_data;
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return -EINVAL;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (fh->dev->ext_vv_data->vbi_fops.write)
+                       return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
+               else
+                       return -EINVAL;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+}
+
 static struct file_operations video_fops =
 {
        .owner          = THIS_MODULE,
        .open           = fops_open,
        .release        = fops_release,
        .read           = fops_read,
+       .write          = fops_write,
        .poll           = fops_poll,
        .mmap           = fops_mmap,
        .ioctl          = fops_ioctl,
@@ -467,7 +496,8 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
        memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
 
        saa7146_video_uops.init(dev,vv);
-       saa7146_vbi_uops.init(dev,vv);
+       if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+               saa7146_vbi_uops.init(dev,vv);
 
        dev->vv_data = vv;
        dev->vv_callback = &vv_callback;
index ec52dff8cb695a35fb72687b1aa508c5196b1b97..33bec8a6843b49bdc05ec9345326bad23a316a11 100644 (file)
@@ -562,19 +562,26 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int
 
        int b_depth = vv->ov_fmt->depth;
        int b_bpl = vv->ov_fb.fmt.bytesperline;
-       u32 base = (u32)vv->ov_fb.base;
+       /* The unsigned long cast is to remove a 64-bit compile warning since
+          it looks like a 64-bit address is cast to a 32-bit value, even
+          though the base pointer is really a 32-bit physical address that
+          goes into a 32-bit DMA register.
+          FIXME: might not work on some 64-bit platforms, but see the FIXME
+          in struct v4l2_framebuffer (videodev2.h) for that.
+        */
+       u32 base = (u32)(unsigned long)vv->ov_fb.base;
 
        struct  saa7146_video_dma vdma1;
 
        /* calculate memory offsets for picture, look if we shall top-down-flip */
        vdma1.pitch     = 2*b_bpl;
        if ( 0 == vv->vflip ) {
-               vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+               vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
                vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);
                vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
        }
        else {
-               vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+               vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
                vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);
                vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
        }
index 063986ec16b51752868cf1d8440875202327aac7..468d3c9590755bfa44bc7ec7fdcf2d20b3756071 100644 (file)
@@ -500,9 +500,9 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
 }
 
 struct saa7146_use_ops saa7146_vbi_uops = {
-       .init           = vbi_init,
-       .open           = vbi_open,
+       .init           = vbi_init,
+       .open           = vbi_open,
        .release        = vbi_close,
        .irq_done       = vbi_irq_done,
-       .read           = vbi_read,
+       .read           = vbi_read,
 };
index 1d961023b837c973852225cc0ba621205d4651ed..7ebac7949df3789aa165ba472a26d6fc319a9651 100644 (file)
@@ -151,8 +151,8 @@ static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
 
        if (V4L2_FIELD_ANY == field) {
                field = (win->w.height > maxh/2)
-                       ? V4L2_FIELD_INTERLACED
-                       : V4L2_FIELD_TOP;
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_TOP;
                }
        switch (field) {
        case V4L2_FIELD_TOP:
@@ -1114,10 +1114,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                return 0;
        }
        case VIDIOC_OVERLAY:
-
-
-
-
        {
                int on = *(int *)arg;
                int err = 0;
@@ -1359,7 +1355,6 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
        saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
 }
 
-
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        struct file *file = q->priv_data;
index 21a9045b3ef6f1358cea5d823ed86dfb7553ba05..0b940e152b7973ceb6db8f504fd7e8f36782b013 100644 (file)
@@ -298,7 +298,7 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
 }
 
 static int lgdt3303_pll_set(struct dvb_frontend* fe,
-                           struct dvb_frontend_parameters* params)
+                           struct dvb_frontend_parameters* params)
 {
        struct flexcop_device *fc = fe->dvb->priv;
        u8 buf[4];
@@ -485,12 +485,16 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
 /* try to figure out the frontend, each card/box can have on of the following list */
 int flexcop_frontend_init(struct flexcop_device *fc)
 {
+       struct dvb_frontend_ops *ops;
+
        /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
        if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
-               fc->fe->ops->set_voltage = flexcop_set_voltage;
+               ops = fc->fe->ops;
+
+               ops->set_voltage = flexcop_set_voltage;
 
-               fc->fe_sleep             = fc->fe->ops->sleep;
-               fc->fe->ops->sleep       = flexcop_sleep;
+               fc->fe_sleep             = ops->sleep;
+               ops->sleep               = flexcop_sleep;
 
                fc->dev_type          = FC_SKY;
                info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
@@ -522,15 +526,17 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        } else
        /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
        if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
-               fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
-               fc->fe->ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
-               fc->fe->ops->set_tone               = flexcop_set_tone;
-               fc->fe->ops->set_voltage            = flexcop_set_voltage;
+               ops = fc->fe->ops;
+
+               ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+               ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+               ops->set_tone               = flexcop_set_tone;
+               ops->set_voltage            = flexcop_set_voltage;
 
-               fc->fe_sleep                        = fc->fe->ops->sleep;
-               fc->fe->ops->sleep                  = flexcop_sleep;
+               fc->fe_sleep                ops->sleep;
+               ops->sleep                  = flexcop_sleep;
 
-               fc->dev_type                        = FC_SKY_OLD;
+               fc->dev_type                = FC_SKY_OLD;
                info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
        }
 
@@ -540,8 +546,9 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        } else {
                if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
                        err("frontend registration failed!");
-                       if (fc->fe->ops->release != NULL)
-                               fc->fe->ops->release(fc->fe);
+                       ops = fc->fe->ops;
+                       if (ops->release != NULL)
+                               ops->release(fc->fe);
                        fc->fe = NULL;
                        return -EINVAL;
                }
index 23cc6431e2b819fc70ae92ea51b93af856ebd64c..3153f9513c6319386eeadb753befc05fb48e544a 100644 (file)
@@ -39,11 +39,13 @@ extern const char *flexcop_device_names[];
 /* FlexCop IBI Registers */
 #if defined(__LITTLE_ENDIAN)
        #include "flexcop_ibi_value_le.h"
-#elif defined(__BIG_ENDIAN)
+#else
+#if defined(__BIG_ENDIAN)
        #include "flexcop_ibi_value_be.h"
 #else
        #error no endian defined
 #endif
+#endif
 
 #define fc_data_Tag_ID_DVB  0x3e
 #define fc_data_Tag_ID_ATSC 0x3f
index 8977c7a313df5aadb4bf66ab0722b6f0e1a69aa8..3a2ff1cc24b709eb70fad464b0deb36ac9744fbe 100644 (file)
@@ -1341,30 +1341,40 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
        return 0;
 }
 
-static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dst_set_frontend(struct dvb_frontend* fe,
+                           struct dvb_frontend_parameters* p,
+                           unsigned int mode_flags,
+                           int *delay,
+                           fe_status_t *status)
 {
        struct dst_state *state = fe->demodulator_priv;
 
-       dst_set_freq(state, p->frequency);
-       dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+       if (p != NULL) {
+               dst_set_freq(state, p->frequency);
+               dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
 
-       if (state->dst_type == DST_TYPE_IS_SAT) {
-               if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
-                       dst_set_inversion(state, p->inversion);
-               dst_set_fec(state, p->u.qpsk.fec_inner);
-               dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
-               dst_set_polarization(state);
-               dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
-
-       } else if (state->dst_type == DST_TYPE_IS_TERR)
-               dst_set_bandwidth(state, p->u.ofdm.bandwidth);
-       else if (state->dst_type == DST_TYPE_IS_CABLE) {
-               dst_set_fec(state, p->u.qam.fec_inner);
-               dst_set_symbolrate(state, p->u.qam.symbol_rate);
-               dst_set_modulation(state, p->u.qam.modulation);
+               if (state->dst_type == DST_TYPE_IS_SAT) {
+                       if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+                               dst_set_inversion(state, p->inversion);
+                       dst_set_fec(state, p->u.qpsk.fec_inner);
+                       dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+                       dst_set_polarization(state);
+                       dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+
+               } else if (state->dst_type == DST_TYPE_IS_TERR)
+                       dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+               else if (state->dst_type == DST_TYPE_IS_CABLE) {
+                       dst_set_fec(state, p->u.qam.fec_inner);
+                       dst_set_symbolrate(state, p->u.qam.symbol_rate);
+                       dst_set_modulation(state, p->u.qam.modulation);
+               }
+               dst_write_tuna(fe);
        }
-       dst_write_tuna(fe);
 
+       if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+               dst_read_status(fe, status);
+
+       *delay = HZ/10;
        return 0;
 }
 
@@ -1445,7 +1455,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .set_frontend = dst_set_frontend,
+       .tune = dst_set_frontend,
        .get_frontend = dst_get_frontend,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
@@ -1469,7 +1479,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .set_frontend = dst_set_frontend,
+       .tune = dst_set_frontend,
        .get_frontend = dst_get_frontend,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
@@ -1496,7 +1506,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .set_frontend = dst_set_frontend,
+       .tune = dst_set_frontend,
        .get_frontend = dst_get_frontend,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
index 2239651969c88f236c073d691e4598722fdc27d3..c650b4bf7f5f8caee597fb19455ad0dd70593290 100644 (file)
@@ -283,16 +283,17 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message,
                hw_buffer->msg[4] = 0x03;
                hw_buffer->msg[5] = length & 0xff;
                hw_buffer->msg[6] = 0x00;
+
                /*
                 *      Need to compute length for EN50221 section 8.3.2, for the time being
                 *      assuming 8.3.2 is not applicable
                 */
                memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
        }
+
        return 0;
 }
 
-
 static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
 {
        if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
index 77977e9c013e7d1e1bfd0b157a5f461e9418502b..01b4e0aac0491fc0620414f84f1207263d9a0f1e 100644 (file)
@@ -600,7 +600,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
        struct dst_state* state = NULL;
 
        switch(type) {
-#ifdef BTTV_BOARD_DVICO_DVBT_LITE
        case BTTV_BOARD_DVICO_DVBT_LITE:
                card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
                if (card->fe != NULL) {
@@ -608,22 +607,15 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                        card->fe->ops->info.frequency_max = 862000000;
                }
                break;
-#endif
 
-#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
        case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
                lgdt330x_reset(card);
                card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
                if (card->fe != NULL)
                        dprintk ("dvb_bt8xx: lgdt330x detected\n");
                break;
-#endif
 
-#ifdef BTTV_BOARD_TWINHAN_VP3021
-       case BTTV_BOARD_TWINHAN_VP3021:
-#else
        case BTTV_BOARD_NEBULA_DIGITV:
-#endif
                /*
                 * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
                 * this would be a cleaner solution than trying each frontend in turn.
@@ -812,9 +804,7 @@ static int dvb_bt8xx_probe(struct device *dev)
                card->irq_err_ignore = 0;
                break;
 
-#ifdef BTTV_BOARD_DVICO_DVBT_LITE
        case BTTV_BOARD_DVICO_DVBT_LITE:
-#endif
                card->gpio_mode = 0x0400C060;
                card->op_sync_orin = 0;
                card->irq_err_ignore = 0;
@@ -823,19 +813,13 @@ static int dvb_bt8xx_probe(struct device *dev)
                 * DA_APP(parallel) */
                break;
 
-#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
        case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
-#endif
                card->gpio_mode = 0x0400c060;
                card->op_sync_orin = BT878_RISC_SYNC_MASK;
                card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
                break;
 
-#ifdef BTTV_BOARD_TWINHAN_VP3021
-       case BTTV_BOARD_TWINHAN_VP3021:
-#else
        case BTTV_BOARD_NEBULA_DIGITV:
-#endif
        case BTTV_BOARD_AVDVBT_761:
                card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
                card->op_sync_orin = 0;
index 7cf4c4a888ec6626055380d4c7b1406799c6dfc0..6018fcdba1e6dc6ec02fa9a61d1a742c6b2bca71 100644 (file)
@@ -21,35 +21,35 @@ config DVB_CINERGYT2_TUNING
 config DVB_CINERGYT2_STREAM_URB_COUNT
        int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
        depends on DVB_CINERGYT2_TUNING
-        default "32"
+       default "32"
        help
          USB Request Blocks for Highspeed Stream transfers are scheduled in
          a queue for the Host Controller.
 
          Usually the default value is a safe choice.
 
-         You may increase this number if you are using this device in a 
-         Server Environment with many high-traffic USB Highspeed devices 
+         You may increase this number if you are using this device in a
+         Server Environment with many high-traffic USB Highspeed devices
          sharing the same USB bus.
 
 
 config DVB_CINERGYT2_STREAM_BUF_SIZE
        int "Size of URB Stream Buffers for Highspeed Transfers"
        depends on DVB_CINERGYT2_TUNING
-        default "512"
+       default "512"
        help
          Should be a multiple of native buffer size of 512 bytes.
          Default value is a safe choice.
 
-         You may increase this number if you are using this device in a 
-         Server Environment with many high-traffic USB Highspeed devices 
+         You may increase this number if you are using this device in a
+         Server Environment with many high-traffic USB Highspeed devices
          sharing the same USB bus.
 
 
 config DVB_CINERGYT2_QUERY_INTERVAL
        int "Status update interval [milliseconds]"
        depends on DVB_CINERGYT2_TUNING
-        default "250"
+       default "250"
        help
          This is the interval for status readouts from the demodulator.
          You may try lower values if you need more responsive signal quality
@@ -64,9 +64,9 @@ config DVB_CINERGYT2_QUERY_INTERVAL
 config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
        bool "Register the onboard IR Remote Control Receiver as Input Device"
        depends on DVB_CINERGYT2_TUNING
-        default "yes"
+       default "yes"
        help
-         Enable this option if you want to use the onboard Infrared Remote 
+         Enable this option if you want to use the onboard Infrared Remote
          Control Receiver as Linux-Input device.
 
          Right now only the keycode table for the default Remote Control
@@ -77,7 +77,7 @@ config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
 config DVB_CINERGYT2_RC_QUERY_INTERVAL
        int "Infrared Remote Controller update interval [milliseconds]"
        depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-        default "50"
+       default "50"
        help
          If you have a very fast-repeating remote control you can try lower
          values, for normal consumer receivers the default value should be
index 1d69bf031fb97efdce8c04c1e32520fa074a4bcc..c4b4c5b6b7c803d2ae7e8c7299901be9380a94fd 100644 (file)
@@ -131,6 +131,8 @@ struct cinergyt2 {
 
        wait_queue_head_t poll_wq;
        int pending_fe_events;
+       int disconnect_pending;
+       atomic_t inuse;
 
        void *streambuf;
        dma_addr_t streambuf_dmahandle;
@@ -343,7 +345,7 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct cinergyt2 *cinergyt2 = demux->priv;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (cinergyt2->streaming == 0)
@@ -359,7 +361,7 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct cinergyt2 *cinergyt2 = demux->priv;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (--cinergyt2->streaming == 0)
@@ -479,23 +481,37 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       int err;
+       int err = -ERESTARTSYS;
 
-       if ((err = dvb_generic_open(inode, file)))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
+       if ((err = dvb_generic_open(inode, file))) {
+               up(&cinergyt2->sem);
                return err;
+       }
 
-       if (down_interruptible(&cinergyt2->sem))
-               return -ERESTARTSYS;
 
        if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
                cinergyt2_sleep(cinergyt2, 0);
                schedule_delayed_work(&cinergyt2->query_work, HZ/2);
        }
 
+       atomic_inc(&cinergyt2->inuse);
+
        up(&cinergyt2->sem);
        return 0;
 }
 
+static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
+{
+       dvb_unregister_device(cinergyt2->fedev);
+       dvb_unregister_adapter(&cinergyt2->adapter);
+
+       cinergyt2_free_stream_urbs(cinergyt2);
+       kfree(cinergyt2);
+}
+
 static int cinergyt2_release (struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -504,7 +520,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
        if (down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
-       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+       if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
                cancel_delayed_work(&cinergyt2->query_work);
                flush_scheduled_work();
                cinergyt2_sleep(cinergyt2, 1);
@@ -512,6 +528,11 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
 
        up(&cinergyt2->sem);
 
+       if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
+               warn("delayed unregister in release");
+               cinergyt2_unregister(cinergyt2);
+       }
+
        return dvb_generic_release(inode, file);
 }
 
@@ -519,7 +540,14 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
 {
        struct dvb_device *dvbdev = file->private_data;
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
+
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
        poll_wait(file, &cinergyt2->poll_wq, wait);
+
+       up(&cinergyt2->sem);
+
        return (POLLIN | POLLRDNORM | POLLPRI);
 }
 
@@ -564,10 +592,15 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
                                (__u16 __user *) arg);
 
        case FE_READ_UNCORRECTED_BLOCKS:
-               /* UNC are already converted to host byte order... */
-               return put_user(stat->uncorrected_block_count,
-                               (__u32 __user *) arg);
+       {
+               uint32_t unc_count;
+
+               unc_count = stat->uncorrected_block_count;
+               stat->uncorrected_block_count = 0;
 
+               /* UNC are already converted to host byte order... */
+               return put_user(unc_count,(__u32 __user *) arg);
+       }
        case FE_SET_FRONTEND:
        {
                struct dvbt_set_parameters_msg *param = &cinergyt2->param;
@@ -580,7 +613,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
                if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
                        return -EFAULT;
 
-               if (down_interruptible(&cinergyt2->sem))
+               if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                        return -ERESTARTSYS;
 
                param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -691,7 +724,7 @@ static void cinergyt2_query_rc (void *data)
        struct cinergyt2_rc_event rc_events[12];
        int n, len, i;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return;
 
        len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@@ -786,7 +819,6 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
 static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2)
 {
        cancel_delayed_work(&cinergyt2->rc_query_work);
-       flush_scheduled_work();
        input_unregister_device(cinergyt2->rc_input_dev);
 }
 
@@ -817,7 +849,7 @@ static void cinergyt2_query (void *data)
        uint8_t lock_bits;
        uint32_t unc;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return;
 
        unc = s->uncorrected_block_count;
@@ -917,28 +949,25 @@ static void cinergyt2_disconnect (struct usb_interface *intf)
 {
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-       if (down_interruptible(&cinergyt2->sem))
-               return;
+       flush_scheduled_work();
 
        cinergyt2_unregister_rc(cinergyt2);
 
+       cancel_delayed_work(&cinergyt2->query_work);
+       wake_up_interruptible(&cinergyt2->poll_wq);
+
        cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
-       dvb_net_release(&cinergyt2->dvbnet);
-       dvb_dmxdev_release(&cinergyt2->dmxdev);
-       dvb_dmx_release(&cinergyt2->demux);
-       dvb_unregister_device(cinergyt2->fedev);
-       dvb_unregister_adapter(&cinergyt2->adapter);
+       cinergyt2->disconnect_pending = 1;
 
-       cinergyt2_free_stream_urbs(cinergyt2);
-       up(&cinergyt2->sem);
-       kfree(cinergyt2);
+       if (!atomic_read(&cinergyt2->inuse))
+               cinergyt2_unregister(cinergyt2);
 }
 
 static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
 {
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (state.event > PM_EVENT_ON) {
@@ -961,7 +990,7 @@ static int cinergyt2_resume (struct usb_interface *intf)
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
        struct dvbt_set_parameters_msg *param = &cinergyt2->param;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (!cinergyt2->sleeping) {
@@ -1014,4 +1043,3 @@ module_exit (cinergyt2_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
-
index a9a7b342104816b0c78d870efd6030567cee86d8..12ee912a5705176af05f73be9e61ffa2e140687d 100644 (file)
@@ -5,7 +5,7 @@ config DVB_CORE
        help
          DVB core utility functions for device handling, software fallbacks etc.
          Say Y when you have a DVB card and want to use it. Say Y if your want
-         to build your drivers outside the kernel, but need the DVB core. All 
+         to build your drivers outside the kernel, but need the DVB core. All
          in-kernel drivers will select this automatically if needed.
          If unsure say N.
 
index c6baac20f529062fae13e894181a520460ae6ce0..7adb50c1e8ebb0c3f9ab8a5e60c9c9f7784b4328 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-               dvb_ca_en50221.o dvb_frontend.o \
+               dvb_ca_en50221.o dvb_frontend.o \
                dvb_net.o dvb_ringbuffer.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
index 5956c35d34accd234cf1cf5ecf4bc0fdd0a2f12f..4bb779aeff6af804f3682fca089b5e075add7f18 100644 (file)
@@ -1745,9 +1745,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
 
        for (i = 0; i < ca->slot_count; i++) {
                dvb_ca_en50221_slot_shutdown(ca, i);
-               if (ca->slot_info[i].rx_buffer.data != NULL) {
-                       vfree(ca->slot_info[i].rx_buffer.data);
-               }
+               vfree(ca->slot_info[i].rx_buffer.data);
        }
        kfree(ca->slot_info);
        dvb_unregister_device(ca->dvbdev);
index c49fd0bd7181dd89a2c67d73a891e5073cde6e9f..772003fb18219fa741cd060f3af7271ef53c29f0 100644 (file)
@@ -409,16 +409,16 @@ static u8 *skip_pes_header(u8 **bufp)
 
        if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
                if (buf[7] & PTS_ONLY)
-                       pts = buf+9;
+                       pts = buf+9;
                else pts = NULL;
                buf = inbuf + 9 + inbuf[8];
        } else {        /* mpeg1 */
                for (buf = inbuf + 6; *buf == 0xff; buf++)
-                       if (buf == inbuf + 6 + 16) {
-                               break;
-                       }
+                       if (buf == inbuf + 6 + 16) {
+                               break;
+                       }
                if ((*buf & 0xc0) == 0x40)
-                       buf += 2;
+                       buf += 2;
                skip = mpeg1_skip_table [*buf >> 4];
                if (skip == 5 || skip == 10) pts = buf;
                else pts = NULL;
@@ -529,9 +529,9 @@ static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_t
        pic->picture_header = 0;
        pic->sequence_header_data
                = ( INIT_HORIZONTAL_SIZE << 20 )
-                       | ( INIT_VERTICAL_SIZE << 8 )
-                       | ( INIT_ASPECT_RATIO << 4 )
-                       | ( INIT_FRAME_RATE );
+                       | ( INIT_VERTICAL_SIZE << 8 )
+                       | ( INIT_ASPECT_RATIO << 4 )
+                       | ( INIT_FRAME_RATE );
        pic->mpeg1_flag = 0;
        pic->vinfo.horizontal_size
                = INIT_DISP_HORIZONTAL_SIZE;
index 95ea5095e07e07ae0ecb5d46240aaa297d7b7442..4a08c4ab67309190b07e8bb1491d12fdd695b8cd 100644 (file)
@@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex);
 
 struct dvb_frontend_private {
 
+       /* thread/frontend values */
        struct dvb_device *dvbdev;
        struct dvb_frontend_parameters parameters;
        struct dvb_fe_events events;
@@ -100,20 +101,25 @@ struct dvb_frontend_private {
        wait_queue_head_t wait_queue;
        pid_t thread_pid;
        unsigned long release_jiffies;
-       int state;
-       int bending;
-       int lnb_drift;
-       int inversion;
-       int auto_step;
-       int auto_sub_step;
-       int started_auto_step;
-       int min_delay;
-       int max_drift;
-       int step_size;
-       int exit;
-       int wakeup;
+       unsigned int exit;
+       unsigned int wakeup;
        fe_status_t status;
-       fe_sec_tone_mode_t tone;
+       unsigned long tune_mode_flags;
+       unsigned int delay;
+
+       /* swzigzag values */
+       unsigned int state;
+       unsigned int bending;
+       int lnb_drift;
+       unsigned int inversion;
+       unsigned int auto_step;
+       unsigned int auto_sub_step;
+       unsigned int started_auto_step;
+       unsigned int min_delay;
+       unsigned int max_drift;
+       unsigned int step_size;
+       int quality;
+       unsigned int check_wrapped;
 };
 
 
@@ -208,21 +214,21 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
                fe->ops->init(fe);
 }
 
-static void update_delay(int *quality, int *delay, int min_delay, int locked)
+static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
 {
-           int q2;
+       int q2;
 
-           dprintk ("%s\n", __FUNCTION__);
+       dprintk ("%s\n", __FUNCTION__);
 
-           if (locked)
-                     (*quality) = (*quality * 220 + 36*256) / 256;
-           else
-                     (*quality) = (*quality * 220 + 0) / 256;
+       if (locked)
+               (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
+       else
+               (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
 
-           q2 = *quality - 128;
-           q2 *= q2;
+       q2 = fepriv->quality - 128;
+       q2 *= q2;
 
-           *delay = min_delay + q2 * HZ / (128*128);
+       fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
 }
 
 /**
@@ -232,7 +238,7 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked)
  * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
  * @returns Number of complete iterations that have been performed.
  */
-static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
+static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
 {
        int autoinversion;
        int ready = 0;
@@ -321,6 +327,129 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
        return 0;
 }
 
+static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+{
+       fe_status_t s;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+       /* if we've got no parameters, just keep idling */
+       if (fepriv->state & FESTATE_IDLE) {
+               fepriv->delay = 3*HZ;
+               fepriv->quality = 0;
+               return;
+       }
+
+       /* in SCAN mode, we just set the frontend when asked and leave it alone */
+       if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
+               if (fepriv->state & FESTATE_RETUNE) {
+                       if (fe->ops->set_frontend)
+                               fe->ops->set_frontend(fe, &fepriv->parameters);
+                       fepriv->state = FESTATE_TUNED;
+               }
+               fepriv->delay = 3*HZ;
+               fepriv->quality = 0;
+               return;
+       }
+
+       /* get the frontend status */
+       if (fepriv->state & FESTATE_RETUNE) {
+               s = 0;
+       } else {
+               if (fe->ops->read_status)
+                       fe->ops->read_status(fe, &s);
+               if (s != fepriv->status) {
+                       dvb_frontend_add_event(fe, s);
+                       fepriv->status = s;
+               }
+       }
+
+       /* if we're not tuned, and we have a lock, move to the TUNED state */
+       if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               fepriv->state = FESTATE_TUNED;
+
+               /* if we're tuned, then we have determined the correct inversion */
+               if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+                   (fepriv->parameters.inversion == INVERSION_AUTO)) {
+                       fepriv->parameters.inversion = fepriv->inversion;
+               }
+               return;
+       }
+
+       /* if we are tuned already, check we're still locked */
+       if (fepriv->state & FESTATE_TUNED) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+               /* we're tuned, and the lock is still good... */
+               if (s & FE_HAS_LOCK) {
+                       return;
+               } else { /* if we _WERE_ tuned, but now don't have a lock */
+                       fepriv->state = FESTATE_ZIGZAG_FAST;
+                       fepriv->started_auto_step = fepriv->auto_step;
+                       fepriv->check_wrapped = 0;
+               }
+       }
+
+       /* don't actually do anything if we're in the LOSTLOCK state,
+        * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
+       if ((fepriv->state & FESTATE_LOSTLOCK) &&
+           (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               return;
+       }
+
+       /* don't do anything if we're in the DISEQC state, since this
+        * might be someone with a motorized dish controlled by DISEQC.
+        * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
+       if (fepriv->state & FESTATE_DISEQC) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               return;
+       }
+
+       /* if we're in the RETUNE state, set everything up for a brand
+        * new scan, keeping the current inversion setting, as the next
+        * tune is _very_ likely to require the same */
+       if (fepriv->state & FESTATE_RETUNE) {
+               fepriv->lnb_drift = 0;
+               fepriv->auto_step = 0;
+               fepriv->auto_sub_step = 0;
+               fepriv->started_auto_step = 0;
+               fepriv->check_wrapped = 0;
+       }
+
+       /* fast zigzag. */
+       if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
+               fepriv->delay = fepriv->min_delay;
+
+               /* peform a tune */
+               if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
+                       /* OK, if we've run out of trials at the fast speed.
+                        * Drop back to slow for the _next_ attempt */
+                       fepriv->state = FESTATE_SEARCHING_SLOW;
+                       fepriv->started_auto_step = fepriv->auto_step;
+                       return;
+               }
+               fepriv->check_wrapped = 1;
+
+               /* if we've just retuned, enter the ZIGZAG_FAST state.
+                * This ensures we cannot return from an
+                * FE_SET_FRONTEND ioctl before the first frontend tune
+                * occurs */
+               if (fepriv->state & FESTATE_RETUNE) {
+                       fepriv->state = FESTATE_TUNING_FAST;
+               }
+       }
+
+       /* slow zigzag */
+       if (fepriv->state & FESTATE_SEARCHING_SLOW) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+               /* Note: don't bother checking for wrapping; we stay in this
+                * state until we get a lock */
+               dvb_frontend_swzigzag_autotune(fe, 0);
+       }
+}
+
 static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 {
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
@@ -330,7 +459,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 
        if (fepriv->dvbdev->writers == 1)
                if (time_after(jiffies, fepriv->release_jiffies +
-                                       dvb_shutdown_timeout * HZ))
+                                 dvb_shutdown_timeout * HZ))
                        return 1;
 
        return 0;
@@ -355,18 +484,14 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
        wake_up_interruptible(&fepriv->wait_queue);
 }
 
-/*
- * FIXME: use linux/kthread.h
- */
 static int dvb_frontend_thread(void *data)
 {
        struct dvb_frontend *fe = data;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        unsigned long timeout;
        char name [15];
-       int quality = 0, delay = 3*HZ;
        fe_status_t s;
-       int check_wrapped = 0;
+       struct dvb_frontend_parameters *params;
 
        dprintk("%s\n", __FUNCTION__);
 
@@ -377,6 +502,9 @@ static int dvb_frontend_thread(void *data)
        sigfillset(&current->blocked);
        unlock_kernel();
 
+       fepriv->check_wrapped = 0;
+       fepriv->quality = 0;
+       fepriv->delay = 3*HZ;
        fepriv->status = 0;
        dvb_frontend_init(fe);
        fepriv->wakeup = 0;
@@ -386,7 +514,7 @@ static int dvb_frontend_thread(void *data)
 
                timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
                                                           dvb_frontend_should_wakeup(fe),
-                                                          delay);
+                                                          fepriv->delay);
                if (0 != dvb_frontend_is_exiting(fe)) {
                        /* got signal or quitting */
                        break;
@@ -397,108 +525,22 @@ static int dvb_frontend_thread(void *data)
                if (down_interruptible(&fepriv->sem))
                        break;
 
-               /* if we've got no parameters, just keep idling */
-               if (fepriv->state & FESTATE_IDLE) {
-                       delay = 3*HZ;
-                       quality = 0;
-                       continue;
-               }
+               /* do an iteration of the tuning loop */
+               if (fe->ops->tune) {
+                       /* have we been asked to retune? */
+                       params = NULL;
+                       if (fepriv->state & FESTATE_RETUNE) {
+                               params = &fepriv->parameters;
+                               fepriv->state = FESTATE_TUNED;
+                       }
 
-               /* get the frontend status */
-               if (fepriv->state & FESTATE_RETUNE) {
-                       s = 0;
-               } else {
-                       if (fe->ops->read_status)
-                               fe->ops->read_status(fe, &s);
+                       fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
                        if (s != fepriv->status) {
                                dvb_frontend_add_event(fe, s);
                                fepriv->status = s;
                        }
-               }
-               /* if we're not tuned, and we have a lock, move to the TUNED state */
-               if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-                       fepriv->state = FESTATE_TUNED;
-
-                       /* if we're tuned, then we have determined the correct inversion */
-                       if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
-                           (fepriv->parameters.inversion == INVERSION_AUTO)) {
-                               fepriv->parameters.inversion = fepriv->inversion;
-                       }
-                       continue;
-               }
-
-               /* if we are tuned already, check we're still locked */
-               if (fepriv->state & FESTATE_TUNED) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-
-                       /* we're tuned, and the lock is still good... */
-                       if (s & FE_HAS_LOCK)
-                               continue;
-                       else { /* if we _WERE_ tuned, but now don't have a lock */
-                               fepriv->state = FESTATE_ZIGZAG_FAST;
-                               fepriv->started_auto_step = fepriv->auto_step;
-                               check_wrapped = 0;
-                       }
-               }
-
-               /* don't actually do anything if we're in the LOSTLOCK state,
-                * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
-               if ((fepriv->state & FESTATE_LOSTLOCK) &&
-                   (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-                       continue;
-               }
-
-               /* don't do anything if we're in the DISEQC state, since this
-                * might be someone with a motorized dish controlled by DISEQC.
-                * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
-               if (fepriv->state & FESTATE_DISEQC) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-                       continue;
-               }
-
-               /* if we're in the RETUNE state, set everything up for a brand
-                * new scan, keeping the current inversion setting, as the next
-                * tune is _very_ likely to require the same */
-               if (fepriv->state & FESTATE_RETUNE) {
-                       fepriv->lnb_drift = 0;
-                       fepriv->auto_step = 0;
-                       fepriv->auto_sub_step = 0;
-                       fepriv->started_auto_step = 0;
-                       check_wrapped = 0;
-               }
-
-               /* fast zigzag. */
-               if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
-                       delay = fepriv->min_delay;
-
-                       /* peform a tune */
-                       if (dvb_frontend_autotune(fe, check_wrapped)) {
-                               /* OK, if we've run out of trials at the fast speed.
-                                * Drop back to slow for the _next_ attempt */
-                               fepriv->state = FESTATE_SEARCHING_SLOW;
-                               fepriv->started_auto_step = fepriv->auto_step;
-                               continue;
-                       }
-                       check_wrapped = 1;
-
-                       /* if we've just retuned, enter the ZIGZAG_FAST state.
-                        * This ensures we cannot return from an
-                        * FE_SET_FRONTEND ioctl before the first frontend tune
-                        * occurs */
-                       if (fepriv->state & FESTATE_RETUNE) {
-                               fepriv->state = FESTATE_TUNING_FAST;
-                       }
-               }
-
-               /* slow zigzag */
-               if (fepriv->state & FESTATE_SEARCHING_SLOW) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-
-                       /* Note: don't bother checking for wrapping; we stay in this
-                        * state until we get a lock */
-                       dvb_frontend_autotune(fe, 0);
+               } else {
+                       dvb_frontend_swzigzag(fe);
                }
        }
 
@@ -733,7 +775,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
-                       fepriv->tone = (fe_sec_tone_mode_t) parg;
                }
                break;
 
@@ -747,7 +788,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
        case FE_DISHNETWORK_SEND_LEGACY_CMD:
                if (fe->ops->dishnetwork_send_legacy_command) {
-                       err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
+                       err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
                } else if (fe->ops->set_voltage) {
@@ -767,13 +808,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                         * initialization, so parg is 8 bits and does not
                         * include the initialization or start bit
                         */
-                       unsigned int cmd = ((unsigned int) parg) << 1;
+                       unsigned long cmd = ((unsigned long) parg) << 1;
                        struct timeval nexttime;
                        struct timeval tv[10];
                        int i;
                        u8 last = 1;
                        if (dvb_frontend_debug)
-                               printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd);
+                               printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd);
                        do_gettimeofday(&nexttime);
                        if (dvb_frontend_debug)
                                memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -814,7 +855,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
        case FE_ENABLE_HIGH_LNB_VOLTAGE:
                if (fe->ops->enable_high_lnb_voltage)
-                       err = fe->ops->enable_high_lnb_voltage(fe, (int) parg);
+                       err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
                break;
 
        case FE_SET_FRONTEND: {
@@ -891,6 +932,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
                }
                break;
+
+       case FE_SET_FRONTEND_TUNE_MODE:
+               fepriv->tune_mode_flags = (unsigned long) parg;
+               break;
        };
 
        up (&fepriv->sem);
@@ -932,6 +977,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
 
                /*  empty event queue */
                fepriv->events.eventr = fepriv->events.eventw = 0;
+
+               /* normal tune mode when opened R/W */
+               fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
        }
 
        return ret;
@@ -990,7 +1038,6 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
        init_MUTEX (&fepriv->events.sem);
        fe->dvb = dvb;
        fepriv->inversion = INVERSION_OFF;
-       fepriv->tone = SEC_TONE_OFF;
 
        printk ("DVB: registering frontend %i (%s)...\n",
                fe->dvb->num,
index 1e0840d02f1f5e0307cbd7b9cc1d9eabc53c7f56..70a6d14efda72dddb4b2cb9b92127e77534ce853 100644 (file)
@@ -58,10 +58,19 @@ struct dvb_frontend_ops {
        int (*init)(struct dvb_frontend* fe);
        int (*sleep)(struct dvb_frontend* fe);
 
+       /* if this is set, it overrides the default swzigzag */
+       int (*tune)(struct dvb_frontend* fe,
+                   struct dvb_frontend_parameters* params,
+                   unsigned int mode_flags,
+                   int *delay,
+                   fe_status_t *status);
+
+       /* these two are only used for the swzigzag code */
        int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-       int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
        int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
 
+       int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
        int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
        int (*read_ber)(struct dvb_frontend* fe, u32* ber);
        int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
@@ -74,8 +83,9 @@ struct dvb_frontend_ops {
        int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
        int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
        int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-       int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg);
-       int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+       int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
+       int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
+       int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
 };
 
 #define MAX_EVENT 8
index 86bba81e851e0efe9eeed9b06979493328439dcc..6711eb6a058c9bc6548bb323c684785e549a3466 100644 (file)
@@ -1222,7 +1222,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
        return if_num;
 }
 
-static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num)
+static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
 {
        struct net_device *net = dvbnet->device[num];
        struct dvb_net_priv *priv;
@@ -1296,9 +1296,9 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
 
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               if ((unsigned int) parg >= DVB_NET_DEVICES_MAX)
+               if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
                        return -EINVAL;
-               ret = dvb_net_remove_if(dvbnet, (unsigned int) parg);
+               ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
                if (!ret)
                        module_put(dvbdev->adapter->module);
                return ret;
index 283c6e9339a4651b5b6c954e124d7e38025a1d0a..77ad2410f4d3cd29cfb3a63a72c6dd6512c22cba 100644 (file)
@@ -112,10 +112,10 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
        split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
        if (split > 0) {
                if (!usermem)
-                       memcpy(buf, rbuf->data+rbuf->pread, split);
+                       memcpy(buf, rbuf->data+rbuf->pread, split);
                else
-                       if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
-                               return -EFAULT;
+                       if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+                               return -EFAULT;
                buf += split;
                todo -= split;
                rbuf->pread = 0;
@@ -124,7 +124,7 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
                memcpy(buf, rbuf->data+rbuf->pread, todo);
        else
                if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
-                       return -EFAULT;
+                       return -EFAULT;
 
        rbuf->pread = (rbuf->pread + todo) % rbuf->size;
 
@@ -167,7 +167,7 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
 }
 
 ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-                               int offset, u8* buf, size_t len, int usermem)
+                               int offset, u8* buf, size_t len, int usermem)
 {
        size_t todo;
        size_t split;
@@ -183,10 +183,10 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
        split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
        if (split > 0) {
                if (!usermem)
-                       memcpy(buf, rbuf->data+idx, split);
+                       memcpy(buf, rbuf->data+idx, split);
                else
-                       if (copy_to_user(buf, rbuf->data+idx, split))
-                               return -EFAULT;
+                       if (copy_to_user(buf, rbuf->data+idx, split))
+                               return -EFAULT;
                buf += split;
                todo -= split;
                idx = 0;
@@ -195,7 +195,7 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
                memcpy(buf, rbuf->data+idx, todo);
        else
                if (copy_to_user(buf, rbuf->data+idx, todo))
-                       return -EFAULT;
+                       return -EFAULT;
 
        return len;
 }
@@ -209,12 +209,12 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
        // clean up disposed packets
        while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
                if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
-                       pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
-                       pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
-                       DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
+                       pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
+                       pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
+                       DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
                } else {
-                       // first packet is not disposed, so we stop cleaning now
-                       break;
+                       // first packet is not disposed, so we stop cleaning now
+                       break;
                }
        }
 }
@@ -242,8 +242,8 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t*
                curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
 
                if (curpktstatus == PKT_READY) {
-                       *pktlen = curpktlen;
-                       return idx;
+                       *pktlen = curpktlen;
+                       return idx;
                }
 
                consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
index fa476f662f82c453da2028ca8267fee6b6ae11f8..6d25609727719df623adfd83fde491fb1d071cf2 100644 (file)
@@ -106,7 +106,7 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
 ** returns number of bytes transferred or -EFAULT
 */
 extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
-                                  size_t len, int usermem);
+                                  size_t len, int usermem);
 
 
 /* write routines & macros */
@@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
 ** returns number of bytes transferred or -EFAULT
 */
 extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
-                                   size_t len);
+                                   size_t len);
 
 
 /**
@@ -133,7 +133,7 @@ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
  * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
  */
 extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
-                                       size_t len);
+                                       size_t len);
 
 /**
  * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
@@ -149,7 +149,7 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
  * returns Number of bytes read, or -EFAULT.
  */
 extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-                                      int offset, u8* buf, size_t len, int usermem);
+                                      int offset, u8* buf, size_t len, int usermem);
 
 /**
  * Dispose of a packet in the ring buffer.
index a4aee8665854f49691e2f695b6803fa792a80b33..06b696e9acbdf0857ac9a4fd34473accc43fa3b8 100644 (file)
@@ -92,10 +92,10 @@ static int dvb_device_open(struct inode *inode, struct file *file)
                old_fops = file->f_op;
                file->f_op = fops_get(dvbdev->fops);
                if(file->f_op->open)
-                       err = file->f_op->open(inode,file);
+                       err = file->f_op->open(inode,file);
                if (err) {
-                       fops_put(file->f_op);
-                       file->f_op = fops_get(old_fops);
+                       fops_put(file->f_op);
+                       file->f_op = fops_get(old_fops);
                }
                fops_put(old_fops);
                return err;
@@ -356,18 +356,18 @@ int dvb_usercopy(struct inode *inode, struct file *file,
        case _IOC_WRITE:
        case (_IOC_WRITE | _IOC_READ):
                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-                       parg = sbuf;
+                       parg = sbuf;
                } else {
-                       /* too big to allocate from stack */
-                       mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
-                       if (NULL == mbuf)
-                               return -ENOMEM;
-                       parg = mbuf;
+                       /* too big to allocate from stack */
+                       mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+                       if (NULL == mbuf)
+                               return -ENOMEM;
+                       parg = mbuf;
                }
 
                err = -EFAULT;
                if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
-                       goto out;
+                       goto out;
                break;
        }
 
@@ -384,7 +384,7 @@ int dvb_usercopy(struct inode *inode, struct file *file,
        case _IOC_READ:
        case (_IOC_WRITE | _IOC_READ):
                if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
-                       err = -EFAULT;
+                       err = -EFAULT;
                break;
        }
 
index 0cc6e4a0e27c7e37924c36be26403822536c6b36..74ed5853f0fb02c1d0be40518d7426b50c2d3b44 100644 (file)
@@ -97,7 +97,7 @@ we simply define out own dvb_usercopy(), which will hopefully become
 generic_usercopy()  someday... */
 
 extern int dvb_usercopy(struct inode *inode, struct file *file,
-                           unsigned int cmd, unsigned long arg,
+                           unsigned int cmd, unsigned long arg,
                            int (*func)(struct inode *inode, struct file *file,
                            unsigned int cmd, void *arg));
 
index 54e2b29076b12efc981d328cf09d51dce144ccd7..90a69d343b79833c429263e22b9faf4c57b689a1 100644 (file)
@@ -37,16 +37,16 @@ config DVB_USB_DIBUSB_MB
          DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
 
          Devices supported by this driver:
-           TwinhanDTV USB-Ter (VP7041)
-           TwinhanDTV Magic Box (VP7041e)
-           KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
-           Hama DVB-T USB1.1-Box
-           DiBcom USB1.1 reference devices (non-public)
-           Ultima Electronic/Artec T1 USB TVBOX
+           Artec T1 USB1.1 boxes
+           Avermedia AverTV DVBT USB1.1
            Compro Videomate DVB-U2000 - DVB-T USB
+           DiBcom USB1.1 reference devices (non-public)
            Grandtec DVB-T USB
-           Avermedia AverTV DVBT USB1.1
-           Artec T1 USB1.1 boxes
+           Hama DVB-T USB1.1-Box
+           KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
+           TwinhanDTV Magic Box (VP7041e)
+           TwinhanDTV USB-Ter (VP7041)
+           Ultima Electronic/Artec T1 USB TVBOX
 
          The VP7041 seems to be identical to "CTS Portable" (Chinese
          Television System).
@@ -54,6 +54,12 @@ config DVB_USB_DIBUSB_MB
          Say Y if you own such a device and want to use it. You should build it as
          a module.
 
+config DVB_USB_DIBUSB_MB_FAULTY
+       bool "Support faulty USB IDs"
+       depends on DVB_USB_DIBUSB_MB
+       help
+         Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
+
 config DVB_USB_DIBUSB_MC
        tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
        depends on DVB_USB
@@ -63,8 +69,8 @@ config DVB_USB_DIBUSB_MC
          DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
 
          Devices supported by this driver:
-           DiBcom USB2.0 reference devices (non-public)
            Artec T1 USB2.0 boxes
+           DiBcom USB2.0 reference devices (non-public)
 
          Say Y if you own such a device and want to use it. You should build it as
          a module.
index d05fab01cccdb9b34093b0dfdda028b45ad27275..358ed153865ff1c6731ca6108978b5d83e19c0f7 100644 (file)
  * design, so it can be reused for the "analogue-only" device (if it will
  * appear at all).
  *
- * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue
- * part
+ * TODO: Use the cx25840-driver for the analogue part
  *
  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net)
+ * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
  *
  *     This program is free software; you can redistribute it and/or modify it
  *     under the terms of the GNU General Public License as published by the Free
@@ -25,6 +26,9 @@
 #include "cxusb.h"
 
 #include "cx22702.h"
+#include "lgdt330x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
 
 /* debug */
 int dvb_usb_cxusb_debug;
@@ -156,6 +160,99 @@ static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
        return 0;
 }
 
+static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       u8 ircode[4];
+       int i;
+
+       cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
+
+       *event = 0;
+       *state = REMOTE_NO_KEY_PRESSED;
+
+       for (i = 0; i < d->props.rc_key_map_size; i++) {
+               if (keymap[i].custom == ircode[2] &&
+                   keymap[i].data == ircode[3]) {
+                       *event = keymap[i].event;
+                       *state = REMOTE_KEY_PRESSED;
+
+                       return 0;
+               }
+       }
+
+       return 0;
+}
+
+struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
+       { 0xfe, 0x02, KEY_TV },
+       { 0xfe, 0x0e, KEY_MP3 },
+       { 0xfe, 0x1a, KEY_DVD },
+       { 0xfe, 0x1e, KEY_FAVORITES },
+       { 0xfe, 0x16, KEY_SETUP },
+       { 0xfe, 0x46, KEY_POWER2 },
+       { 0xfe, 0x0a, KEY_EPG },
+       { 0xfe, 0x49, KEY_BACK },
+       { 0xfe, 0x4d, KEY_MENU },
+       { 0xfe, 0x51, KEY_UP },
+       { 0xfe, 0x5b, KEY_LEFT },
+       { 0xfe, 0x5f, KEY_RIGHT },
+       { 0xfe, 0x53, KEY_DOWN },
+       { 0xfe, 0x5e, KEY_OK },
+       { 0xfe, 0x59, KEY_INFO },
+       { 0xfe, 0x55, KEY_TAB },
+       { 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */
+       { 0xfe, 0x12, KEY_NEXTSONG },   /* Skip */
+       { 0xfe, 0x42, KEY_ENTER  },     /* Windows/Start */
+       { 0xfe, 0x15, KEY_VOLUMEUP },
+       { 0xfe, 0x05, KEY_VOLUMEDOWN },
+       { 0xfe, 0x11, KEY_CHANNELUP },
+       { 0xfe, 0x09, KEY_CHANNELDOWN },
+       { 0xfe, 0x52, KEY_CAMERA },
+       { 0xfe, 0x5a, KEY_TUNER },      /* Live */
+       { 0xfe, 0x19, KEY_OPEN },
+       { 0xfe, 0x0b, KEY_1 },
+       { 0xfe, 0x17, KEY_2 },
+       { 0xfe, 0x1b, KEY_3 },
+       { 0xfe, 0x07, KEY_4 },
+       { 0xfe, 0x50, KEY_5 },
+       { 0xfe, 0x54, KEY_6 },
+       { 0xfe, 0x48, KEY_7 },
+       { 0xfe, 0x4c, KEY_8 },
+       { 0xfe, 0x58, KEY_9 },
+       { 0xfe, 0x13, KEY_ANGLE },      /* Aspect */
+       { 0xfe, 0x03, KEY_0 },
+       { 0xfe, 0x1f, KEY_ZOOM },
+       { 0xfe, 0x43, KEY_REWIND },
+       { 0xfe, 0x47, KEY_PLAYPAUSE },
+       { 0xfe, 0x4f, KEY_FASTFORWARD },
+       { 0xfe, 0x57, KEY_MUTE },
+       { 0xfe, 0x0d, KEY_STOP },
+       { 0xfe, 0x01, KEY_RECORD },
+       { 0xfe, 0x4e, KEY_POWER },
+};
+
+static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
+{
+       static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
+       static u8 reset []         = { RESET,      0x80 };
+       static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+       static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+       static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+       static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+       mt352_write(fe, clock_config,   sizeof(clock_config));
+       udelay(200);
+       mt352_write(fe, reset,          sizeof(reset));
+       mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+       mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+       mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+       mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+       return 0;
+}
+
 struct cx22702_config cxusb_cx22702_config = {
        .demod_address = 0x63,
 
@@ -165,17 +262,47 @@ struct cx22702_config cxusb_cx22702_config = {
        .pll_set  = dvb_usb_pll_set_i2c,
 };
 
+struct lgdt330x_config cxusb_lgdt330x_config = {
+       .demod_address = 0x0e,
+       .demod_chip    = LGDT3303,
+       .pll_set       = dvb_usb_pll_set_i2c,
+};
+
+struct mt352_config cxusb_dee1601_config = {
+       .demod_address = 0x0f,
+       .demod_init    = cxusb_dee1601_demod_init,
+       .pll_set       = dvb_usb_pll_set,
+};
+
 /* Callbacks for DVB USB */
-static int cxusb_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
 {
        u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
        d->pll_addr = 0x61;
-       memcpy(d->pll_init,bpll,4);
+       memcpy(d->pll_init, bpll, 4);
        d->pll_desc = &dvb_pll_fmd1216me;
        return 0;
 }
 
-static int cxusb_frontend_attach(struct dvb_usb_device *d)
+static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
+{
+       u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
+       /* bpll[2] : unset bit 3, set bits 4&5
+          bpll[3] : 0x50 - digital, 0x20 - analog */
+       d->pll_addr = 0x61;
+       memcpy(d->pll_init, bpll, 4);
+       d->pll_desc = &dvb_pll_tdvs_tua6034;
+       return 0;
+}
+
+static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
+{
+       d->pll_addr = 0x61;
+       d->pll_desc = &dvb_pll_thomson_dtt7579;
+       return 0;
+}
+
+static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d)
 {
        u8 b;
        if (usb_set_interface(d->udev,0,6) < 0)
@@ -189,22 +316,84 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d)
        return -EIO;
 }
 
+static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d)
+{
+       if (usb_set_interface(d->udev,0,7) < 0)
+               err("set interface failed");
+
+       cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+
+       if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL)
+               return 0;
+
+       return -EIO;
+}
+
+static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
+{
+       if (usb_set_interface(d->udev,0,0) < 0)
+               err("set interface failed");
+
+       cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+
+       if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+               return 0;
+
+       return -EIO;
+}
+
+/*
+ * DViCO bluebird firmware needs the "warm" product ID to be patched into the
+ * firmware file before download.
+ */
+
+#define BLUEBIRD_01_ID_OFFSET 6638
+static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw)
+{
+       if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
+               return -EINVAL;
+
+       if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
+           fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
+
+               /* FIXME: are we allowed to change the fw-data ? */
+               fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1;
+               fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8;
+
+               return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2);
+       }
+
+       return -EINVAL;
+}
+
 /* DVB USB Driver stuff */
-static struct dvb_usb_properties cxusb_properties;
+static struct dvb_usb_properties cxusb_medion_properties;
+static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties;
+static struct dvb_usb_properties cxusb_bluebird_dee1601_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE,NULL);
+       if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
+               dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
+               dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0) {
+               return 0;
+       }
+
+       return -EINVAL;
 }
 
 static struct usb_device_id cxusb_table [] = {
                { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
+               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
+               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) },
+               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) },
                {}              /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
 
-static struct dvb_usb_properties cxusb_properties = {
+static struct dvb_usb_properties cxusb_medion_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
 
        .usb_ctrl = CYPRESS_FX2,
@@ -213,8 +402,8 @@ static struct dvb_usb_properties cxusb_properties = {
 
        .streaming_ctrl   = cxusb_streaming_ctrl,
        .power_ctrl       = cxusb_power_ctrl,
-       .frontend_attach  = cxusb_frontend_attach,
-       .tuner_attach     = cxusb_tuner_attach,
+       .frontend_attach  = cxusb_cx22702_frontend_attach,
+       .tuner_attach     = cxusb_fmd1216me_tuner_attach,
 
        .i2c_algo         = &cxusb_i2c_algo,
 
@@ -240,6 +429,91 @@ static struct dvb_usb_properties cxusb_properties = {
        }
 };
 
+static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl          = DEVICE_SPECIFIC,
+       .firmware          = "dvb-usb-bluebird-01.fw",
+       .download_firmware = bluebird_patch_dvico_firmware_download,
+       /* use usb alt setting 0 for EP4 transfer (dvb-t),
+          use usb alt setting 7 for EP2 transfer (atsc) */
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .streaming_ctrl   = cxusb_streaming_ctrl,
+       .power_ctrl       = cxusb_power_ctrl,
+       .frontend_attach  = cxusb_lgdt330x_frontend_attach,
+       .tuner_attach     = cxusb_lgh064f_tuner_attach,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 5,
+               .endpoint = 0x02,
+               .u = {
+                       .bulk = {
+                               .buffersize = 8192,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "DViCO FusionHDTV5 USB Gold",
+                       { &cxusb_table[1], NULL },
+                       { &cxusb_table[2], NULL },
+               },
+       }
+};
+
+static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl          = DEVICE_SPECIFIC,
+       .firmware          = "dvb-usb-bluebird-01.fw",
+       .download_firmware = bluebird_patch_dvico_firmware_download,
+       /* use usb alt setting 0 for EP4 transfer (dvb-t),
+          use usb alt setting 7 for EP2 transfer (atsc) */
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .streaming_ctrl   = cxusb_streaming_ctrl,
+       .power_ctrl       = cxusb_power_ctrl,
+       .frontend_attach  = cxusb_dee1601_frontend_attach,
+       .tuner_attach     = cxusb_dee1601_tuner_attach,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .rc_interval      = 150,
+       .rc_key_map       = dvico_mce_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+       .rc_query         = cxusb_rc_query,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 5,
+               .endpoint = 0x04,
+               .u = {
+                       .bulk = {
+                               .buffersize = 8192,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "DViCO FusionHDTV DVB-T Dual USB",
+                       { &cxusb_table[3], NULL },
+                       { &cxusb_table[4], NULL },
+               },
+       }
+};
+
 static struct usb_driver cxusb_driver = {
        .name           = "dvb_usb_cxusb",
        .probe          = cxusb_probe,
index 135c2a81f5817f5685745d22966483737afd7190..087c99427853f6a51496b6598f7aec5bb8941859 100644 (file)
@@ -21,6 +21,8 @@ extern int dvb_usb_cxusb_debug;
 #define CMD_STREAMING_ON  0x36
 #define CMD_STREAMING_OFF 0x37
 
+#define CMD_GET_IR_CODE   0x47
+
 #define CMD_ANALOG        0x50
 #define CMD_DIGITAL       0x51
 
index 52ac3e5adf5dd99de63a18821f57e258f8fcab69..dd5a131958862a8bd7090dc2328c81fc499bfc1a 100644 (file)
@@ -65,11 +65,11 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
                d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
 
        if (b2[0] == 0xfe) {
-               info("this device has the Thomson Cable onboard. Which is default.");
+               info("This device has the Thomson Cable onboard. Which is default.");
                dibusb_thomson_tuner_attach(d);
        } else {
                u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
-               info("this device has the Panasonic ENV77H11D5 onboard.");
+               info("This device has the Panasonic ENV77H11D5 onboard.");
                d->pll_addr = 0x60;
                memcpy(d->pll_init,bpll,4);
                d->pll_desc = &dvb_pll_tda665x;
@@ -98,15 +98,15 @@ static int dibusb_probe(struct usb_interface *intf,
 
 /* do not change the order of the ID table */
 static struct usb_device_id dibusb_dib3000mb_table [] = {
-/* 00 */       { USB_DEVICE(USB_VID_WIDEVIEW,          USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-/* 01 */       { USB_DEVICE(USB_VID_WIDEVIEW,          USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 00 */       { USB_DEVICE(USB_VID_WIDEVIEW,          USB_PID_AVERMEDIA_DVBT_USB_COLD) },
+/* 01 */       { USB_DEVICE(USB_VID_WIDEVIEW,          USB_PID_AVERMEDIA_DVBT_USB_WARM) },
 /* 02 */       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_COLD) },
 /* 03 */       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_WARM) },
 /* 04 */       { USB_DEVICE(USB_VID_COMPRO_UNK,        USB_PID_COMPRO_DVBU2000_UNK_COLD) },
 /* 05 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_COLD) },
 /* 06 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_WARM) },
-/* 07 */       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_COLD) },
-/* 08 */       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_WARM) },
+/* 07 */       { USB_DEVICE(USB_VID_EMPIA,             USB_PID_KWORLD_VSTREAM_COLD) },
+/* 08 */       { USB_DEVICE(USB_VID_EMPIA,             USB_PID_KWORLD_VSTREAM_WARM) },
 /* 09 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_COLD) },
 /* 10 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_WARM) },
 /* 11 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_DIBCOM_MOD3000_COLD) },
@@ -117,27 +117,34 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
 /* 16 */       { USB_DEVICE(USB_VID_VISIONPLUS,        USB_PID_TWINHAN_VP7041_WARM) },
 /* 17 */       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_COLD) },
 /* 18 */       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_WARM) },
-/* 19 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
-/* 20 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
-/* 21 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
-/* 22 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+/* 19 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+/* 20 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+/* 21 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+/* 22 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
 /* 23 */       { USB_DEVICE(USB_VID_ADSTECH,           USB_PID_ADSTECH_USB2_COLD) },
 
 /* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
 /* 24 */       { USB_DEVICE(USB_VID_ADSTECH,           USB_PID_ADSTECH_USB2_WARM) },
-/* 25 */       { USB_DEVICE(USB_VID_KYE,                       USB_PID_KYE_DVB_T_COLD) },
-/* 26 */       { USB_DEVICE(USB_VID_KYE,                       USB_PID_KYE_DVB_T_WARM) },
+/* 25 */       { USB_DEVICE(USB_VID_KYE,               USB_PID_KYE_DVB_T_COLD) },
+/* 26 */       { USB_DEVICE(USB_VID_KYE,               USB_PID_KYE_DVB_T_WARM) },
 
 /* 27 */       { USB_DEVICE(USB_VID_KWORLD,            USB_PID_KWORLD_VSTREAM_COLD) },
 
-/* 28 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,         USB_PID_ULTIMA_TVBOX_USB2_COLD) },
-/* 29 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,         USB_PID_ULTIMA_TVBOX_USB2_WARM) },
+/* 28 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 29 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) },
 
-// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+/*
+ * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
+ *      we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
+ *      have been left on the device. If you don't have such a device but an Artec
+ *      device that's supposed to work with this driver but is not detected by it,
+ *      free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
+ */
 
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
 /* 30 */       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
 #endif
+
                        { }             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
@@ -257,7 +264,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
                }
        },
 
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
        .num_device_descs = 2,
 #else
        .num_device_descs = 1,
@@ -267,11 +274,12 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
                        { &dibusb_dib3000mb_table[20], NULL },
                        { &dibusb_dib3000mb_table[21], NULL },
                },
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
                {       "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
                        { &dibusb_dib3000mb_table[30], NULL },
                        { NULL },
                },
+               { NULL },
 #endif
        }
 };
@@ -323,6 +331,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
                        { &dibusb_dib3000mb_table[27], NULL },
                        { NULL }
                },
+               { NULL },
        }
 };
 
@@ -369,6 +378,7 @@ static struct dvb_usb_properties artec_t1_usb2_properties = {
                        { &dibusb_dib3000mb_table[28], NULL },
                        { &dibusb_dib3000mb_table[29], NULL },
                },
+               { NULL },
        }
 };
 
index 450417a9e64b6632fd62cc3affd346a55203da9d..e6c55c9c9417d2afe8bf67a0b906c0342548f56c 100644 (file)
@@ -32,7 +32,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d,
        sndbuf[1] = vv;
        sndbuf[2] = wo ? wlen : rlen;
 
-       if (!wo) {
+       if (wo) {
                memcpy(&sndbuf[3],wbuf,wlen);
                dvb_usb_generic_write(d,sndbuf,7);
        } else {
index 6e2bac873445700e7d83b1e5317763b3e16263db..130ea7f21f5e62eb27331a3d6bfcef03c0b18939 100644 (file)
@@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = {
                  .cold_ids = { &dtt200u_usb_table[0], NULL },
                  .warm_ids = { &dtt200u_usb_table[1], NULL },
                },
-               { NULL },
+               { 0 },
        }
 };
 
@@ -160,7 +160,7 @@ static struct dvb_usb_properties wt220u_properties = {
        .pid_filter_count = 15,
 
        .usb_ctrl = CYPRESS_FX2,
-       .firmware = "dvb-usb-wt220u-01.fw",
+       .firmware = "dvb-usb-wt220u-02.fw",
 
        .power_ctrl      = dtt200u_power_ctrl,
        .streaming_ctrl  = dtt200u_streaming_ctrl,
@@ -192,7 +192,7 @@ static struct dvb_usb_properties wt220u_properties = {
                  .cold_ids = { &dtt200u_usb_table[2], NULL },
                  .warm_ids = { &dtt200u_usb_table[3], NULL },
                },
-               { NULL },
+               { 0 },
        }
 };
 
index 6f1f3042e21a54a5ce3f70be303601d66d5670dc..005b0a7df3585d1653e61d8b8a63a9278a0ab7cf 100644 (file)
@@ -13,6 +13,7 @@
 #define _DVB_USB_DTT200U_H_
 
 #define DVB_USB_LOG_PREFIX "dtt200u"
+
 #include "dvb-usb.h"
 
 extern int dvb_usb_dtt200u_debug;
@@ -25,15 +26,15 @@ extern int dvb_usb_dtt200u_debug;
  *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
  */
 
-#define GET_SPEED            0x00
-#define GET_TUNE_STATUS      0x81
-#define GET_RC_CODE          0x84
-#define GET_CONFIGURATION    0x88
-#define GET_AGC              0x89
-#define GET_SNR              0x8a
-#define GET_VIT_ERR_CNT      0x8c
-#define GET_RS_ERR_CNT       0x8d
-#define GET_RS_UNCOR_BLK_CNT 0x8e
+#define GET_SPEED              0x00
+#define GET_TUNE_STATUS                0x81
+#define GET_RC_CODE            0x84
+#define GET_CONFIGURATION      0x88
+#define GET_AGC                        0x89
+#define GET_SNR                        0x8a
+#define GET_VIT_ERR_CNT                0x8c
+#define GET_RS_ERR_CNT         0x8d
+#define GET_RS_UNCOR_BLK_CNT   0x8e
 
 /* write
  *  01 - init
@@ -44,12 +45,12 @@ extern int dvb_usb_dtt200u_debug;
  *  08 - transfer switch
  */
 
-#define SET_INIT         0x01
-#define SET_RF_FREQ      0x02
-#define SET_BANDWIDTH    0x03
-#define SET_PID_FILTER   0x04
-#define RESET_PID_FILTER 0x05
-#define SET_STREAMING    0x08
+#define SET_INIT               0x01
+#define SET_RF_FREQ            0x02
+#define SET_BANDWIDTH          0x03
+#define SET_PID_FILTER         0x04
+#define RESET_PID_FILTER       0x05
+#define SET_STREAMING          0x08
 
 extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
 
index 7300489d3e2420b66bcdf21450394faab5106e22..a3460bf2d9fa56eb1ab4495678a51ede6b0d4b63 100644 (file)
@@ -24,7 +24,7 @@ extern int dvb_usb_disable_rc_polling;
 #define deb_mem(args...)  dprintk(dvb_usb_debug,0x80,args)
 
 /* commonly used  methods */
-extern int usb_cypress_load_firmware(struct usb_device *, const char *, int);
+extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *);
 
 extern int dvb_usb_urb_submit(struct dvb_usb_device *);
 extern int dvb_usb_urb_kill(struct dvb_usb_device *);
index 5244e39770a0e425cc691420240bde8ea1deb715..8535895819fb5e1d8d72bdadbdd6f07ace87fe97 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include "dvb-usb-common.h"
 
-#include <linux/firmware.h>
 #include <linux/usb.h>
 
 struct usb_cypress_controller {
@@ -19,9 +18,10 @@ struct usb_cypress_controller {
 };
 
 static struct usb_cypress_controller cypress[] = {
-       { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
-       { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
-       { .id = CYPRESS_FX2,    .name = "Cypress FX2",    .cpu_cs_register = 0xe600 },
+       { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
+       { .id = CYPRESS_AN2135,  .name = "Cypress AN2135",  .cpu_cs_register = 0x7f92 },
+       { .id = CYPRESS_AN2235,  .name = "Cypress AN2235",  .cpu_cs_register = 0x7f92 },
+       { .id = CYPRESS_FX2,     .name = "Cypress FX2",     .cpu_cs_register = 0xe600 },
 };
 
 /*
@@ -30,71 +30,117 @@ static struct usb_cypress_controller cypress[] = {
 static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
 {
        return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
-                       0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+                       0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
 }
 
-int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type)
+int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
 {
-       const struct firmware *fw = NULL;
-       u16 addr;
-       u8 *b,*p;
-       int ret = 0,i;
+       struct hexline hx;
+       u8 reset;
+       int ret,pos=0;
 
-       if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) {
-               err("did not find the firmware file. (%s) "
-                       "Please see linux/Documentation/dvb/ for more details on firmware-problems.",
-                       filename);
+       /* stop the CPU */
+       reset = 1;
+       if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+               err("could not stop the USB controller CPU.");
+
+       while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
+               deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
+               ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+
+               if (ret != hx.len) {
+                       err("error while transferring firmware "
+                               "(transferred size: %d, block size: %d)",
+                               ret,hx.len);
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+       if (ret < 0) {
+               err("firmware download failed at %d with %d",pos,ret);
                return ret;
        }
 
-       info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name);
-
-       p = kmalloc(fw->size,GFP_KERNEL);
-       if (p != NULL) {
-               u8 reset;
-               /*
-                * you cannot use the fw->data as buffer for
-                * usb_control_msg, a new buffer has to be
-                * created
-                */
-               memcpy(p,fw->data,fw->size);
-
-               /* stop the CPU */
-               reset = 1;
-               if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
-                       err("could not stop the USB controller CPU.");
-               for(i = 0; p[i+3] == 0 && i < fw->size; ) {
-                       b = (u8 *) &p[i];
-                       addr = cpu_to_le16( *((u16 *) &b[1]) );
-
-                       deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]);
-
-                       ret = usb_cypress_writemem(udev,addr,&b[4],b[0]);
-
-                       if (ret != b[0]) {
-                               err("error while transferring firmware "
-                                       "(transferred size: %d, block size: %d)",
-                                       ret,b[0]);
-                               ret = -EINVAL;
-                               break;
-                       }
-                       i += 5 + b[0];
-               }
-               /* length in ret */
-               if (ret > 0)
-                       ret = 0;
+       if (ret == 0) {
                /* restart the CPU */
                reset = 0;
                if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
                        err("could not restart the USB controller CPU.");
                        ret = -EINVAL;
                }
+       } else
+               ret = -EIO;
 
-               kfree(p);
-       } else {
-               ret = -ENOMEM;
+       return ret;
+}
+EXPORT_SYMBOL(usb_cypress_load_firmware);
+
+int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props)
+{
+       int ret;
+       const struct firmware *fw = NULL;
+
+       if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
+               err("did not find the firmware file. (%s) "
+                       "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+                       props->firmware,ret);
+               return ret;
        }
-       release_firmware(fw);
 
+       info("downloading firmware from file '%s'",props->firmware);
+
+       switch (props->usb_ctrl) {
+               case CYPRESS_AN2135:
+               case CYPRESS_AN2235:
+               case CYPRESS_FX2:
+                       ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
+                       break;
+               case DEVICE_SPECIFIC:
+                       if (props->download_firmware)
+                               ret = props->download_firmware(udev,fw);
+                       else {
+                               err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
+                               ret = -EINVAL;
+                       }
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+       }
+
+       release_firmware(fw);
        return ret;
 }
+
+int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos)
+{
+       u8 *b = (u8 *) &fw->data[*pos];
+       int data_offs = 4;
+       if (*pos >= fw->size)
+               return 0;
+
+       memset(hx,0,sizeof(struct hexline));
+
+       hx->len  = b[0];
+
+       if ((*pos + hx->len + 4) >= fw->size)
+               return -EINVAL;
+
+       hx->addr = le16_to_cpu( *((u16 *) &b[1]) );
+       hx->type = b[3];
+
+       if (hx->type == 0x04) {
+               /* b[4] and b[5] are the Extended linear address record data field */
+               hx->addr |= (b[4] << 24) | (b[5] << 16);
+/*             hx->len -= 2;
+               data_offs += 2; */
+       }
+       memcpy(hx->data,&b[data_offs],hx->len);
+       hx->chk = b[hx->len + data_offs];
+
+       *pos += hx->len + 5;
+
+       return *pos;
+}
+EXPORT_SYMBOL(dvb_usb_get_hexline);
+
index da970947dfc72e5a77df1a4fa4a552c8ad16b038..9b254532af4dddd6e528c16c0a5770b3d8612173 100644 (file)
@@ -52,9 +52,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
        struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
        int ret = 0;
 
-       /* if there is nothing to initialize */
-       if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 &&
-               d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00)
+       /* if pll_desc is not used */
+       if (d->pll_desc == NULL)
                return 0;
 
        if (d->tuner_pass_ctrl)
@@ -80,6 +79,9 @@ int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep
 {
        struct dvb_usb_device *d = fe->dvb->priv;
 
+       if (d->pll_desc == NULL)
+               return 0;
+
        deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
 
        b[0] = d->pll_addr << 1;
index 6be99e537e12904bf4475c6e3bc3f837ad80627d..d229343832265f175af3f7778e3b556ed817ac34 100644 (file)
 #define USB_PID_WINTV_NOVA_T_USB2_COLD         0x9300
 #define USB_PID_WINTV_NOVA_T_USB2_WARM         0x9301
 #define USB_PID_NEBULA_DIGITV                          0x0201
-#define USB_PID_DVICO_BLUEBIRD_LGZ201          0xdb00
-#define USB_PID_DVICO_BLUEBIRD_TH7579          0xdb10
 #define USB_PID_DVICO_BLUEBIRD_LGDT                    0xd820
-#define USB_PID_DVICO_BLUEBIRD_LGZ201_1                0xdb01
-#define USB_PID_DVICO_BLUEBIRD_TH7579_2                0xdb11
+#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD             0xd500
+#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM             0xd501
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD             0xdb00
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM             0xdb01
+#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD             0xdb10
+#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM             0xdb11
+#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD            0xdb50
+#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM            0xdb51
 #define USB_PID_MEDION_MD95700                         0x0932
 #define USB_PID_KYE_DVB_T_COLD                         0x701e
 #define USB_PID_KYE_DVB_T_WARM                         0x701f
index dd8e0b94edbab6ae619c1a0d91abc667071b5ffc..2e23060cbbca736c4f8a0ea690ee3a893d36b9e9 100644 (file)
@@ -138,6 +138,9 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
 
        int ret = -ENOMEM,cold=0;
 
+       if (du != NULL)
+               *du = NULL;
+
        if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
                deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
                return -ENODEV;
@@ -145,38 +148,40 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
 
        if (cold) {
                info("found a '%s' in cold state, will try to load a firmware",desc->name);
-               ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl);
-       } else {
-               info("found a '%s' in warm state.",desc->name);
-               d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
-               if (d == NULL) {
-                       err("no memory for 'struct dvb_usb_device'");
+               ret = dvb_usb_download_firmware(udev,props);
+               if (!props->no_reconnect)
                        return ret;
+       }
+
+       info("found a '%s' in warm state.",desc->name);
+       d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+       if (d == NULL) {
+               err("no memory for 'struct dvb_usb_device'");
+               return ret;
+       }
+       memset(d,0,sizeof(struct dvb_usb_device));
+
+       d->udev = udev;
+       memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
+       d->desc = desc;
+       d->owner = owner;
+
+       if (d->props.size_of_priv > 0) {
+               d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
+               if (d->priv == NULL) {
+                       err("no memory for priv in 'struct dvb_usb_device'");
+                       kfree(d);
+                       return -ENOMEM;
                }
-               memset(d,0,sizeof(struct dvb_usb_device));
-
-               d->udev = udev;
-               memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
-               d->desc = desc;
-               d->owner = owner;
-
-               if (d->props.size_of_priv > 0) {
-                       d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
-                       if (d->priv == NULL) {
-                               err("no memory for priv in 'struct dvb_usb_device'");
-                               kfree(d);
-                               return -ENOMEM;
-                       }
-                       memset(d->priv,0,d->props.size_of_priv);
-               }
+               memset(d->priv,0,d->props.size_of_priv);
+       }
 
-               usb_set_intfdata(intf, d);
+       usb_set_intfdata(intf, d);
 
-               if (du != NULL)
-                       *du = d;
+       if (du != NULL)
+               *du = d;
 
-               ret = dvb_usb_init(d);
-       }
+       ret = dvb_usb_init(d);
 
        if (ret == 0)
                info("%s successfully initialized and connected.",desc->name);
index b4a1a98006c7d9f8abcf95686cb93db84b401fde..dd568396e594819aa0fba7e90bec3b7137605e86 100644 (file)
@@ -10,8 +10,8 @@
 
 #include <linux/config.h>
 #include <linux/input.h>
-#include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -94,7 +94,11 @@ struct dvb_usb_device;
  * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
  *  download.
  * @firmware: name of the firmware file.
- *
+ * @download_firmware: called to download the firmware when the usb_ctrl is
+ *  DEVICE_SPECIFIC.
+ * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
+    so do the warm initialization right after it
+
  * @size_of_priv: how many bytes shall be allocated for the private field
  *  of struct dvb_usb_device.
  *
@@ -142,11 +146,14 @@ struct dvb_usb_properties {
        int caps;
        int pid_filter_count;
 
-#define CYPRESS_AN2135  0
-#define CYPRESS_AN2235  1
-#define CYPRESS_FX2     2
+#define DEVICE_SPECIFIC 0
+#define CYPRESS_AN2135  1
+#define CYPRESS_AN2235  2
+#define CYPRESS_FX2     3
        int usb_ctrl;
-       const char *firmware;
+       const char firmware[FIRMWARE_NAME_MAX];
+       int (*download_firmware) (struct usb_device *, const struct firmware *);
+       int no_reconnect;
 
        int size_of_priv;
 
@@ -326,5 +333,15 @@ extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
 extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
 extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
 
+/* commonly used firmware download types and function */
+struct hexline {
+       u8 len;
+       u32 addr;
+       u8 type;
+       u8 data[255];
+       u8 chk;
+};
+extern int dvb_usb_get_hexline(const struct firmware *, struct hexline *, int *);
+extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
 
 #endif
index fac48fc7a4aca3e2b7df0f455be0190d48eb8133..412039d8dbae728a730fac25742701a7fe288ad2 100644 (file)
@@ -129,10 +129,6 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
                dibusb_read_eeprom_byte(d,i, &b);
 
                mac[5 - (i - 136)] = b;
-
-/*             deb_ee("%02x ",b);
-               if ((i+1) % 16 == 0)
-                       deb_ee("\n");*/
        }
 
        return 0;
@@ -153,7 +149,7 @@ static struct usb_device_id nova_t_table [] = {
 /* 01 */       { USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_WARM) },
                        { }             /* Terminating entry */
 };
-MODULE_DEVICE_TABLE (usb, nova_t_table);
+MODULE_DEVICE_TABLE(usb, nova_t_table);
 
 static struct dvb_usb_properties nova_t_properties = {
        .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
@@ -198,6 +194,7 @@ static struct dvb_usb_properties nova_t_properties = {
                        { &nova_t_table[0], NULL },
                        { &nova_t_table[1], NULL },
                },
+               { NULL },
        }
 };
 
index 104b5d016c7b17e3c76376164b8c2464c18e9299..0885d9fb2bf231a6373fbbc30725d0adaf5ae67d 100644 (file)
@@ -190,7 +190,7 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
 }
 
 static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
-                                   struct dvb_diseqc_master_cmd *m)
+                                   struct dvb_diseqc_master_cmd *m)
 {
        struct vp702x_fe_state *st = fe->demodulator_priv;
        u8 cmd[8],ibuf[10];
index 4a3e8c7eca2b862de2721e88f8707b7e94f5b2c9..a808d48e7bf24092ac6be65c6996c3582c42b354 100644 (file)
@@ -13,47 +13,47 @@ extern int dvb_usb_vp702x_debug;
 /* commands are read and written with USB control messages */
 
 /* consecutive read/write operation */
-#define REQUEST_OUT       0xB2
-#define REQUEST_IN               0xB3
+#define REQUEST_OUT            0xB2
+#define REQUEST_IN             0xB3
 
 /* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0
  * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer
  * the returning buffer looks as follows
  * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */
 
-#define GET_TUNER_STATUS  0x05
+#define GET_TUNER_STATUS       0x05
 /* additional in buffer:
  * 0   1   2    3              4   5   6               7       8
  * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */
 
-#define GET_SYSTEM_STRING 0x06
+#define GET_SYSTEM_STRING      0x06
 /* additional in buffer:
  * 0   1   2   3   4   5   6   7   8
  * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */
 
-#define SET_DISEQC_CMD    0x08
+#define SET_DISEQC_CMD         0x08
 /* additional out buffer:
  * 0    1  2  3  4
  * len  X1 X2 X3 X4
  * additional in buffer:
  * 0   1 2
- * N/A 0 0   b[1] == b[2] == 0 -> success otherwise not */
+ * N/A 0 0   b[1] == b[2] == 0 -> success, failure otherwise */
 
-#define SET_LNB_POWER     0x09
+#define SET_LNB_POWER          0x09
 /* additional out buffer:
  * 0    1    2
  * 0x00 0xff 1 = on, 0 = off
  * additional in buffer:
  * 0   1 2
- * N/A 0 0   b[1] == b[2] == 0 -> success otherwise not */
+ * N/A 0 0   b[1] == b[2] == 0 -> success failure otherwise */
 
-#define GET_MAC_ADDRESS   0x0A
+#define GET_MAC_ADDRESS                0x0A
 /* #define GET_MAC_ADDRESS   0x0B */
 /* additional in buffer:
  * 0   1   2            3    4    5    6    7    8
  * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */
 
-#define SET_PID_FILTER    0x11
+#define SET_PID_FILTER         0x11
 /* additional in buffer:
  * 0        1        ... 14       15       16
  * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */
@@ -64,39 +64,38 @@ extern int dvb_usb_vp702x_debug;
  * freq0 freq1 divstep srate0 srate1 srate2 flag chksum
  */
 
-
 /* one direction requests */
-#define READ_REMOTE_REQ       0xB4
+#define READ_REMOTE_REQ                0xB4
 /* IN  i: 0; v: 0; b[0] == request, b[1] == key */
 
-#define READ_PID_NUMBER_REQ   0xB5
+#define READ_PID_NUMBER_REQ    0xB5
 /* IN  i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */
 
-#define WRITE_EEPROM_REQ      0xB6
+#define WRITE_EEPROM_REQ       0xB6
 /* OUT i: offset; v: value to write; no extra buffer */
 
-#define READ_EEPROM_REQ       0xB7
+#define READ_EEPROM_REQ                0xB7
 /* IN  i: bufferlen; v: offset; buffer with bufferlen bytes */
 
-#define READ_STATUS           0xB8
+#define READ_STATUS            0xB8
 /* IN  i: 0; v: 0; bufferlen 10 */
 
-#define READ_TUNER_REG_REQ    0xB9
+#define READ_TUNER_REG_REQ     0xB9
 /* IN  i: 0; v: register; b[0] = value */
 
-#define READ_FX2_REG_REQ      0xBA
+#define READ_FX2_REG_REQ       0xBA
 /* IN  i: offset; v: 0; b[0] = value */
 
-#define WRITE_FX2_REG_REQ     0xBB
+#define WRITE_FX2_REG_REQ      0xBB
 /* OUT i: offset; v: value to write; 1 byte extra buffer */
 
-#define SET_TUNER_POWER_REQ   0xBC
+#define SET_TUNER_POWER_REQ    0xBC
 /* IN  i: 0 = power off, 1 = power on */
 
-#define WRITE_TUNER_REG_REQ   0xBD
+#define WRITE_TUNER_REG_REQ    0xBD
 /* IN  i: register, v: value to write, no extra buffer */
 
-#define RESET_TUNER           0xBE
+#define RESET_TUNER            0xBE
 /* IN  i: 0, v: 0, no extra buffer */
 
 extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
index 3835235b68dff0f18793c0b711af42c3160ed6cd..028204956bb007ba31684552c20b844af5459f36 100644 (file)
@@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = {
                  .cold_ids = { &vp7045_usb_table[2], NULL },
                  .warm_ids = { &vp7045_usb_table[3], NULL },
                },
-               { NULL },
+               { 0 },
        }
 };
 
index 8e269e1c1f9dfb68e2ecae64e1a6b656da267741..db3a8b40031eaa379edaaa066f5d0423860a5b91 100644 (file)
@@ -16,6 +16,12 @@ config DVB_CX24110
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_CX24123
+       tristate "Conexant CX24123 based"
+       depends on DVB_CORE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
 config DVB_TDA8083
        tristate "Philips TDA8083 based"
        depends on DVB_CORE
@@ -50,18 +56,19 @@ comment "DVB-T (terrestrial) frontends"
        depends on DVB_CORE
 
 config DVB_SP8870
-       tristate "Spase sp8870 based"
+       tristate "Spase sp8870 based"
        depends on DVB_CORE
        select FW_LOADER
        help
-         A DVB-T tuner module. Say Y when you want to support this frontend.
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
          This driver needs external firmware. Please use the command
          "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
-         download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_SP887X
-       tristate "Spase sp887x based"
+       tristate "Spase sp887x based"
        depends on DVB_CORE
        select FW_LOADER
        help
@@ -69,7 +76,8 @@ config DVB_SP887X
 
          This driver needs external firmware. Please use the command
          "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
-         download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_CX22700
        tristate "Conexant CX22700 based"
@@ -78,10 +86,10 @@ config DVB_CX22700
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_CX22702
-       tristate "Conexant cx22702 demodulator (OFDM)"
-       depends on DVB_CORE
-       help
-         A DVB-T tuner module. Say Y when you want to support this frontend.
+       tristate "Conexant cx22702 demodulator (OFDM)"
+       depends on DVB_CORE
+       help
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_L64781
        tristate "LSI L64781"
@@ -98,8 +106,9 @@ config DVB_TDA1004X
 
          This driver needs external firmware. Please use the commands
          "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
-         download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+         download/extract them, and then copy them to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_NXT6000
        tristate "NxtWave Communications NXT6000 based"
@@ -140,13 +149,13 @@ config DVB_VES1820
        tristate "VLSI VES1820 based"
        depends on DVB_CORE
        help
-         A DVB-C tuner module. Say Y when you want to support this frontend.
+         A DVB-C tuner module. Say Y when you want to support this frontend.
 
 config DVB_TDA10021
        tristate "Philips TDA10021 based"
        depends on DVB_CORE
        help
-         A DVB-C tuner module. Say Y when you want to support this frontend.
+         A DVB-C tuner module. Say Y when you want to support this frontend.
 
 config DVB_STV0297
        tristate "ST STV0297 based"
@@ -164,6 +173,11 @@ config DVB_NXT2002
        help
          An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
+         This driver needs external firmware. Please use the command
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
+
 config DVB_NXT200X
        tristate "Nextwave NXT2002/NXT2004 based"
        depends on DVB_CORE
@@ -172,6 +186,12 @@ config DVB_NXT200X
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+         This driver needs external firmware. Please use the commands
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+         download/extract them, and then copy them to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
+
 config DVB_OR51211
        tristate "or51211 based (pcHDTV HD2000 card)"
        depends on DVB_CORE
index a98760fe08a18a7c60d4f4e661dfe0fce514dfb3..615ec830e1c911d8c1adb28b93f73b51259e4bcd 100644 (file)
@@ -32,3 +32,4 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+obj-$(CONFIG_DVB_CX24123) += cx24123.o
index 8ceb9a33c7af35bb2fdd70cb9aa513f2947dd71d..3b132bafd4de0f0f39bcf87ab83b5b05ae444c88 100644 (file)
@@ -255,7 +255,7 @@ static int bcm3510_bert_reset(struct bcm3510_state *st)
        bcm3510_register_value b;
        int ret;
 
-       if ((ret < bcm3510_readB(st,0xfa,&b)) < 0)
+       if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
                return ret;
 
        b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
@@ -623,13 +623,13 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
                err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
                return ret;
        }
-       deb_info("got firmware: %d\n",fw->size);
+       deb_info("got firmware: %zd\n",fw->size);
 
        b = fw->data;
        for (i = 0; i < fw->size;) {
                addr = le16_to_cpu( *( (u16 *)&b[i] ) );
                len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
-               deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size);
+               deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
                if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
                        err("firmware download failed: %d\n",ret);
                        return ret;
index 5de0e6d350b1ae7223bee890f9710efda14f87d3..0fc899f81c5e9be0a16b1f263a09465fc3adeb96 100644 (file)
@@ -195,6 +195,16 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet
        return 0;
 }
 
+static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct cx22702_state* state = fe->demodulator_priv;
+       dprintk ("%s(%d)\n", __FUNCTION__, enable);
+       if (enable)
+               return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
+       else
+               return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1);
+}
+
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
 static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
@@ -202,7 +212,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
        struct cx22702_state* state = fe->demodulator_priv;
 
        /* set PLL */
-       cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+       cx22702_i2c_gate_ctrl(fe, 1);
        if (state->config->pll_set) {
                state->config->pll_set(fe, p);
        } else if (state->config->pll_desc) {
@@ -216,7 +226,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
        } else {
                BUG();
        }
-       cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+       cx22702_i2c_gate_ctrl(fe, 0);
 
        /* set inversion */
        cx22702_set_inversion (state, p->inversion);
@@ -349,11 +359,10 @@ static int cx22702_init (struct dvb_frontend* fe)
        cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
 
        /* init PLL */
-       if (state->config->pll_init) {
-               cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe);
+       if (state->config->pll_init)
                state->config->pll_init(fe);
-               cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
-       }
+
+       cx22702_i2c_gate_ctrl(fe, 0);
 
        return 0;
 }
@@ -531,6 +540,7 @@ static struct dvb_frontend_ops cx22702_ops = {
        .read_signal_strength = cx22702_read_signal_strength,
        .read_snr = cx22702_read_snr,
        .read_ucblocks = cx22702_read_ucblocks,
+       .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 };
 
 module_param(debug, int, 0644);
index 0c4db80ec332b7611e210308204e8a808b64e686..d15d32c51dc5dd466f133bbad301b1cc3824cb2f 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/jiffies.h>
 
 #include "dvb_frontend.h"
 #include "cx24110.h"
@@ -56,7 +55,7 @@ static int debug;
 
 static struct {u8 reg; u8 data;} cx24110_regdata[]=
                      /* Comments beginning with @ denote this value should
-                        be the default */
+                        be the default */
        {{0x09,0x01}, /* SoftResetAll */
         {0x09,0x00}, /* release reset */
         {0x01,0xe8}, /* MSB of code rate 27.5MS/s */
@@ -67,26 +66,26 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]=
         {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
         {0x0a,0x00}, /* @ partial chip disables, do not set */
         {0x0b,0x01}, /* set output clock in gapped mode, start signal low
-                        active for first byte */
+                        active for first byte */
         {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
         {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
         {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
-                        to avoid starting the BER counter. Reset the
-                        CRC test bit. Finite counting selected */
+                        to avoid starting the BER counter. Reset the
+                        CRC test bit. Finite counting selected */
         {0x15,0xff}, /* @ size of the limited time window for RS BER
-                        estimation. It is <value>*256 RS blocks, this
-                        gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
+                        estimation. It is <value>*256 RS blocks, this
+                        gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
         {0x16,0x00}, /* @ enable all RS output ports */
         {0x17,0x04}, /* @ time window allowed for the RS to sync */
         {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
-                        for automatically */
+                        for automatically */
                      /* leave the current code rate and normalization
-                        registers as they are after reset... */
+                        registers as they are after reset... */
         {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
-                        only once */
+                        only once */
         {0x23,0x18}, /* @ size of the limited time window for Viterbi BER
-                        estimation. It is <value>*65536 channel bits, i.e.
-                        approx. 38ms at 27.5MS/s, rate 3/4 */
+                        estimation. It is <value>*65536 channel bits, i.e.
+                        approx. 38ms at 27.5MS/s, rate 3/4 */
         {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
                      /* leave front-end AGC parameters at default values */
                      /* leave decimation AGC parameters at default values */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
new file mode 100644 (file)
index 0000000..d661c6f
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+    Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+
+    Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
+
+    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/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24123.h"
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk (KERN_DEBUG "cx24123: " args); \
+       } while (0)
+
+struct cx24123_state
+{
+       struct i2c_adapter* i2c;
+       struct dvb_frontend_ops ops;
+       const struct cx24123_config* config;
+
+       struct dvb_frontend frontend;
+
+       u32 lastber;
+       u16 snr;
+       u8  lnbreg;
+
+       /* Some PLL specifics for tuning */
+       u32 VCAarg;
+       u32 VGAarg;
+       u32 bandselectarg;
+       u32 pllarg;
+
+       /* The Demod/Tuner can't easily provide these, we cache them */
+       u32 currentfreq;
+       u32 currentsymbolrate;
+};
+
+/* Various tuner defaults need to be established for a given symbol rate Sps */
+static struct
+{
+       u32 symbolrate_low;
+       u32 symbolrate_high;
+       u32 VCAslope;
+       u32 VCAoffset;
+       u32 VGA1offset;
+       u32 VGA2offset;
+       u32 VCAprogdata;
+       u32 VGAprogdata;
+} cx24123_AGC_vals[] =
+{
+       {
+               .symbolrate_low         = 1000000,
+               .symbolrate_high        = 4999999,
+               .VCAslope               = 0x07,
+               .VCAoffset              = 0x0f,
+               .VGA1offset             = 0x1f8,
+               .VGA2offset             = 0x1f8,
+               .VGAprogdata            = (2 << 18) | (0x1f8 << 9) | 0x1f8,
+               .VCAprogdata            = (4 << 18) | (0x07 << 9) | 0x07,
+       },
+       {
+               .symbolrate_low         =  5000000,
+               .symbolrate_high        = 14999999,
+               .VCAslope               = 0x1f,
+               .VCAoffset              = 0x1f,
+               .VGA1offset             = 0x1e0,
+               .VGA2offset             = 0x180,
+               .VGAprogdata            = (2 << 18) | (0x180 << 9) | 0x1e0,
+               .VCAprogdata            = (4 << 18) | (0x07 << 9) | 0x1f,
+       },
+       {
+               .symbolrate_low         = 15000000,
+               .symbolrate_high        = 45000000,
+               .VCAslope               = 0x3f,
+               .VCAoffset              = 0x3f,
+               .VGA1offset             = 0x180,
+               .VGA2offset             = 0x100,
+               .VGAprogdata            = (2 << 18) | (0x100 << 9) | 0x180,
+               .VCAprogdata            = (4 << 18) | (0x07 << 9) | 0x3f,
+       },
+};
+
+/*
+ * Various tuner defaults need to be established for a given frequency kHz.
+ * fixme: The bounds on the bands do not match the doc in real life.
+ * fixme: Some of them have been moved, other might need adjustment.
+ */
+static struct
+{
+       u32 freq_low;
+       u32 freq_high;
+       u32 bandselect;
+       u32 VCOdivider;
+       u32 VCOnumber;
+       u32 progdata;
+} cx24123_bandselect_vals[] =
+{
+       {
+               .freq_low       = 950000,
+               .freq_high      = 1018999,
+               .bandselect     = 0x40,
+               .VCOdivider     = 4,
+               .VCOnumber      = 7,
+               .progdata       = (0 << 18) | (0 << 9) | 0x40,
+       },
+       {
+               .freq_low       = 1019000,
+               .freq_high      = 1074999,
+               .bandselect     = 0x80,
+               .VCOdivider     = 4,
+               .VCOnumber      = 8,
+               .progdata       = (0 << 18) | (0 << 9) | 0x80,
+       },
+       {
+               .freq_low       = 1075000,
+               .freq_high      = 1227999,
+               .bandselect     = 0x01,
+               .VCOdivider     = 2,
+               .VCOnumber      = 1,
+               .progdata       = (0 << 18) | (1 << 9) | 0x01,
+       },
+       {
+               .freq_low       = 1228000,
+               .freq_high      = 1349999,
+               .bandselect     = 0x02,
+               .VCOdivider     = 2,
+               .VCOnumber      = 2,
+               .progdata       = (0 << 18) | (1 << 9) | 0x02,
+       },
+       {
+               .freq_low       = 1350000,
+               .freq_high      = 1481999,
+               .bandselect     = 0x04,
+               .VCOdivider     = 2,
+               .VCOnumber      = 3,
+               .progdata       = (0 << 18) | (1 << 9) | 0x04,
+       },
+       {
+               .freq_low       = 1482000,
+               .freq_high      = 1595999,
+               .bandselect     = 0x08,
+               .VCOdivider     = 2,
+               .VCOnumber      = 4,
+               .progdata       = (0 << 18) | (1 << 9) | 0x08,
+       },
+       {
+               .freq_low       = 1596000,
+               .freq_high      = 1717999,
+               .bandselect     = 0x10,
+               .VCOdivider     = 2,
+               .VCOnumber      = 5,
+               .progdata       = (0 << 18) | (1 << 9) | 0x10,
+       },
+       {
+               .freq_low       = 1718000,
+               .freq_high      = 1855999,
+               .bandselect     = 0x20,
+               .VCOdivider     = 2,
+               .VCOnumber      = 6,
+               .progdata       = (0 << 18) | (1 << 9) | 0x20,
+       },
+       {
+               .freq_low       = 1856000,
+               .freq_high      = 2035999,
+               .bandselect     = 0x40,
+               .VCOdivider     = 2,
+               .VCOnumber      = 7,
+               .progdata       = (0 << 18) | (1 << 9) | 0x40,
+       },
+       {
+               .freq_low       = 2036000,
+               .freq_high      = 2149999,
+               .bandselect     = 0x80,
+               .VCOdivider     = 2,
+               .VCOnumber      = 8,
+               .progdata       = (0 << 18) | (1 << 9) | 0x80,
+       },
+};
+
+static struct {
+       u8 reg;
+       u8 data;
+} cx24123_regdata[] =
+{
+       {0x00, 0x03}, /* Reset system */
+       {0x00, 0x00}, /* Clear reset */
+       {0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */
+       {0x03, 0x07},
+       {0x04, 0x10},
+       {0x05, 0x04},
+       {0x06, 0x31},
+       {0x0d, 0x02},
+       {0x0e, 0x03},
+       {0x0f, 0xfe},
+       {0x10, 0x01},
+       {0x14, 0x01},
+       {0x15, 0x98},
+       {0x16, 0x00},
+       {0x17, 0x01},
+       {0x1b, 0x05},
+       {0x1c, 0x80},
+       {0x1d, 0x00},
+       {0x1e, 0x00},
+       {0x20, 0x41},
+       {0x21, 0x15},
+       {0x27, 0x14},
+       {0x28, 0x46},
+       {0x29, 0x00},
+       {0x2a, 0xb0},
+       {0x2b, 0x73},
+       {0x2c, 0x00},
+       {0x2d, 0x00},
+       {0x2e, 0x00},
+       {0x2f, 0x00},
+       {0x30, 0x00},
+       {0x31, 0x00},
+       {0x32, 0x8c},
+       {0x33, 0x00},
+       {0x34, 0x00},
+       {0x35, 0x03},
+       {0x36, 0x02},
+       {0x37, 0x3a},
+       {0x3a, 0x00},   /* Enable AGC accumulator */
+       {0x44, 0x00},
+       {0x45, 0x00},
+       {0x46, 0x05},
+       {0x56, 0x41},
+       {0x57, 0xff},
+       {0x67, 0x83},
+};
+
+static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
+{
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+       int err;
+
+       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+               printk("%s: writereg error(err == %i, reg == 0x%02x,"
+                        " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
+{
+       u8 buf[] = { reg, data };
+       /* fixme: put the intersil addr int the config */
+       struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
+       int err;
+
+       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+               printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
+                        " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+               return -EREMOTEIO;
+       }
+
+       /* cache the write, no way to read back */
+       state->lnbreg = data;
+
+       return 0;
+}
+
+static int cx24123_readreg(struct cx24123_state* state, u8 reg)
+{
+       int ret;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+               { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2) {
+               printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret);
+               return ret;
+       }
+
+       return b1[0];
+}
+
+static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
+{
+       return state->lnbreg;
+}
+
+static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
+{
+       switch (inversion) {
+       case INVERSION_OFF:
+               cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f);
+               cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+               break;
+       case INVERSION_ON:
+               cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80);
+               cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+               break;
+       case INVERSION_AUTO:
+               cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion)
+{
+       u8 val;
+
+       val = cx24123_readreg(state, 0x1b) >> 7;
+
+       if (val == 0)
+               *inversion = INVERSION_OFF;
+       else
+               *inversion = INVERSION_ON;
+
+       return 0;
+}
+
+static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
+{
+       if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
+               fec = FEC_AUTO;
+
+       /* Hardware has 5/11 and 3/5 but are never unused */
+       switch (fec) {
+       case FEC_NONE:
+               return cx24123_writereg(state, 0x0f, 0x01);
+       case FEC_1_2:
+               return cx24123_writereg(state, 0x0f, 0x02);
+       case FEC_2_3:
+               return cx24123_writereg(state, 0x0f, 0x04);
+       case FEC_3_4:
+               return cx24123_writereg(state, 0x0f, 0x08);
+       case FEC_5_6:
+               return cx24123_writereg(state, 0x0f, 0x20);
+       case FEC_7_8:
+               return cx24123_writereg(state, 0x0f, 0x80);
+       case FEC_AUTO:
+               return cx24123_writereg(state, 0x0f, 0xae);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec)
+{
+       int ret;
+       u8 val;
+
+       ret = cx24123_readreg (state, 0x1b);
+       if (ret < 0)
+               return ret;
+       val = ret & 0x07;
+       switch (val) {
+       case 1:
+               *fec = FEC_1_2;
+               break;
+       case 3:
+               *fec = FEC_2_3;
+               break;
+       case 4:
+               *fec = FEC_3_4;
+               break;
+       case 5:
+               *fec = FEC_4_5;
+               break;
+       case 6:
+               *fec = FEC_5_6;
+               break;
+       case 7:
+               *fec = FEC_7_8;
+               break;
+       case 2: /* *fec = FEC_3_5; break; */
+       case 0: /* *fec = FEC_5_11; break; */
+               *fec = FEC_AUTO;
+               break;
+       default:
+               *fec = FEC_NONE; // can't happen
+       }
+
+       return 0;
+}
+
+/* fixme: Symbol rates < 3MSps may not work because of precision loss */
+static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
+{
+       u32 val;
+
+       val = (srate / 1185) * 100;
+
+       /* Compensate for scaling up, by removing 17 symbols per 1Msps */
+       val = val - (17 * (srate / 1000000));
+
+       cx24123_writereg(state, 0x08, (val >> 16) & 0xff );
+       cx24123_writereg(state, 0x09, (val >>  8) & 0xff );
+       cx24123_writereg(state, 0x0a, (val      ) & 0xff );
+
+       return 0;
+}
+
+/*
+ * Based on the required frequency and symbolrate, the tuner AGC has to be configured
+ * and the correct band selected. Calculate those values
+ */
+static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       u32 ndiv = 0, adiv = 0, vco_div = 0;
+       int i = 0;
+
+       /* Defaults for low freq, low rate */
+       state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
+       state->VGAarg = cx24123_AGC_vals[0].VGAprogdata;
+       state->bandselectarg = cx24123_bandselect_vals[0].progdata;
+       vco_div = cx24123_bandselect_vals[0].VCOdivider;
+
+       /* For the given symbolerate, determine the VCA and VGA programming bits */
+       for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
+       {
+               if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
+                               (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
+                       state->VCAarg = cx24123_AGC_vals[i].VCAprogdata;
+                       state->VGAarg = cx24123_AGC_vals[i].VGAprogdata;
+               }
+       }
+
+       /* For the given frequency, determine the bandselect programming bits */
+       for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++)
+       {
+               if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
+                               (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) {
+                       state->bandselectarg = cx24123_bandselect_vals[i].progdata;
+                       vco_div = cx24123_bandselect_vals[i].VCOdivider;
+               }
+       }
+
+       /* Determine the N/A dividers for the requested lband freq (in kHz). */
+       /* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */
+       ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff;
+       adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f;
+
+       if (adiv == 0)
+               adiv++;
+
+       /* determine the correct pll frequency values. */
+       /* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */
+       state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14);
+       state->pllarg |= (ndiv << 5) | adiv;
+
+       return 0;
+}
+
+/*
+ * Tuner data is 21 bits long, must be left-aligned in data.
+ * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip.
+ */
+static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       unsigned long timeout;
+
+       /* align the 21 bytes into to bit23 boundary */
+       data = data << 3;
+
+       /* Reset the demod pll word length to 0x15 bits */
+       cx24123_writereg(state, 0x21, 0x15);
+
+       /* write the msb 8 bits, wait for the send to be completed */
+       timeout = jiffies + msecs_to_jiffies(40);
+       cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
+       while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+               if (time_after(jiffies, timeout)) {
+                       printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+                       return -EREMOTEIO;
+               }
+               msleep(10);
+       }
+
+       /* send another 8 bytes, wait for the send to be completed */
+       timeout = jiffies + msecs_to_jiffies(40);
+       cx24123_writereg(state, 0x22, (data>>8) & 0xff );
+       while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+               if (time_after(jiffies, timeout)) {
+                       printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+                       return -EREMOTEIO;
+               }
+               msleep(10);
+       }
+
+       /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */
+       timeout = jiffies + msecs_to_jiffies(40);
+       cx24123_writereg(state, 0x22, (data) & 0xff );
+       while ((cx24123_readreg(state, 0x20) & 0x80)) {
+               if (time_after(jiffies, timeout)) {
+                       printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+                       return -EREMOTEIO;
+               }
+               msleep(10);
+       }
+
+       /* Trigger the demod to configure the tuner */
+       cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2);
+       cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd);
+
+       return 0;
+}
+
+static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       if (cx24123_pll_calculate(fe, p) != 0) {
+               printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__);
+               return -EINVAL;
+       }
+
+       /* Write the new VCO/VGA */
+       cx24123_pll_writereg(fe, p, state->VCAarg);
+       cx24123_pll_writereg(fe, p, state->VGAarg);
+
+       /* Write the new bandselect and pll args */
+       cx24123_pll_writereg(fe, p, state->bandselectarg);
+       cx24123_pll_writereg(fe, p, state->pllarg);
+
+       return 0;
+}
+
+static int cx24123_initfe(struct dvb_frontend* fe)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       int i;
+
+       /* Configure the demod to a good set of defaults */
+       for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
+               cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
+
+       if (state->config->pll_init)
+               state->config->pll_init(fe);
+
+       /* Configure the LNB for 14V */
+       if (state->config->use_isl6421)
+               cx24123_writelnbreg(state, 0x0, 0x2a);
+
+       return 0;
+}
+
+static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       u8 val;
+
+       switch (state->config->use_isl6421) {
+
+       case 1:
+
+               val = cx24123_readlnbreg(state, 0x0);
+
+               switch (voltage) {
+               case SEC_VOLTAGE_13:
+                       return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
+               case SEC_VOLTAGE_18:
+                       return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
+               case SEC_VOLTAGE_OFF:
+                       return cx24123_writelnbreg(state, 0x0, val & 0x30);
+               default:
+                       return -EINVAL;
+               };
+
+       case 0:
+
+               val = cx24123_readreg(state, 0x29);
+
+               switch (voltage) {
+               case SEC_VOLTAGE_13:
+                       dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+                       if (state->config->enable_lnb_voltage)
+                               state->config->enable_lnb_voltage(fe, 1);
+                       return cx24123_writereg(state, 0x29, val | 0x80);
+               case SEC_VOLTAGE_18:
+                       dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+                       if (state->config->enable_lnb_voltage)
+                               state->config->enable_lnb_voltage(fe, 1);
+                       return cx24123_writereg(state, 0x29, val & 0x7f);
+               case SEC_VOLTAGE_OFF:
+                       dprintk("%s: setting voltage off\n", __FUNCTION__);
+                       if (state->config->enable_lnb_voltage)
+                               state->config->enable_lnb_voltage(fe, 0);
+                       return 0;
+               default:
+                       return -EINVAL;
+               };
+       }
+
+       return 0;
+}
+
+static int cx24123_send_diseqc_msg(struct dvb_frontend* fe,
+                                  struct dvb_diseqc_master_cmd *cmd)
+{
+       /* fixme: Implement diseqc */
+       printk("%s: No support yet\n",__FUNCTION__);
+
+       return -ENOTSUPP;
+}
+
+static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       int sync = cx24123_readreg(state, 0x14);
+       int lock = cx24123_readreg(state, 0x20);
+
+       *status = 0;
+       if (lock & 0x01)
+               *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+       if (sync & 0x04)
+               *status |= FE_HAS_VITERBI;
+       if (sync & 0x08)
+               *status |= FE_HAS_CARRIER;
+       if (sync & 0x80)
+               *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+       return 0;
+}
+
+/*
+ * Configured to return the measurement of errors in blocks, because no UCBLOCKS value
+ * is available, so this value doubles up to satisfy both measurements
+ */
+static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       state->lastber =
+               ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+               (cx24123_readreg(state, 0x1d) << 8 |
+               cx24123_readreg(state, 0x1e));
+
+       /* Do the signal quality processing here, it's derived from the BER. */
+       /* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
+       if (state->lastber < 5000)
+               state->snr = 655*100;
+       else if ( (state->lastber >=   5000) && (state->lastber <  55000) )
+               state->snr = 655*90;
+       else if ( (state->lastber >=  55000) && (state->lastber < 150000) )
+               state->snr = 655*80;
+       else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
+               state->snr = 655*70;
+       else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
+               state->snr = 655*65;
+       else
+               state->snr = 0;
+
+       *ber = state->lastber;
+
+       return 0;
+}
+
+static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
+
+       return 0;
+}
+
+static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       *snr = state->snr;
+
+       return 0;
+}
+
+static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       *ucblocks = state->lastber;
+
+       return 0;
+}
+
+static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       if (state->config->set_ts_params)
+               state->config->set_ts_params(fe, 0);
+
+       state->currentfreq=p->frequency;
+       state->currentsymbolrate = p->u.qpsk.symbol_rate;
+
+       cx24123_set_inversion(state, p->inversion);
+       cx24123_set_fec(state, p->u.qpsk.fec_inner);
+       cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
+       cx24123_pll_tune(fe, p);
+
+       /* Enable automatic aquisition and reset cycle */
+       cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
+       cx24123_writereg(state, 0x00, 0x10);
+       cx24123_writereg(state, 0x00, 0);
+
+       return 0;
+}
+
+static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       if (cx24123_get_inversion(state, &p->inversion) != 0) {
+               printk("%s: Failed to get inversion status\n",__FUNCTION__);
+               return -EREMOTEIO;
+       }
+       if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
+               printk("%s: Failed to get fec status\n",__FUNCTION__);
+               return -EREMOTEIO;
+       }
+       p->frequency = state->currentfreq;
+       p->u.qpsk.symbol_rate = state->currentsymbolrate;
+
+       return 0;
+}
+
+static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       u8 val;
+
+       switch (state->config->use_isl6421) {
+       case 1:
+
+               val = cx24123_readlnbreg(state, 0x0);
+
+               switch (tone) {
+               case SEC_TONE_ON:
+                       return cx24123_writelnbreg(state, 0x0, val | 0x10);
+               case SEC_TONE_OFF:
+                       return cx24123_writelnbreg(state, 0x0, val & 0x2f);
+               default:
+                       printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+                       return -EINVAL;
+               }
+
+       case 0:
+
+               val = cx24123_readreg(state, 0x29);
+
+               switch (tone) {
+               case SEC_TONE_ON:
+                       dprintk("%s: setting tone on\n", __FUNCTION__);
+                       return cx24123_writereg(state, 0x29, val | 0x10);
+               case SEC_TONE_OFF:
+                       dprintk("%s: setting tone off\n",__FUNCTION__);
+                       return cx24123_writereg(state, 0x29, val & 0xef);
+               default:
+                       printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void cx24123_release(struct dvb_frontend* fe)
+{
+       struct cx24123_state* state = fe->demodulator_priv;
+       dprintk("%s\n",__FUNCTION__);
+       kfree(state);
+}
+
+static struct dvb_frontend_ops cx24123_ops;
+
+struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+                                   struct i2c_adapter* i2c)
+{
+       struct cx24123_state* state = NULL;
+       int ret;
+
+       dprintk("%s\n",__FUNCTION__);
+
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL);
+       if (state == NULL) {
+               printk("Unable to kmalloc\n");
+               goto error;
+       }
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
+       state->lastber = 0;
+       state->snr = 0;
+       state->lnbreg = 0;
+       state->VCAarg = 0;
+       state->VGAarg = 0;
+       state->bandselectarg = 0;
+       state->pllarg = 0;
+       state->currentfreq = 0;
+       state->currentsymbolrate = 0;
+
+       /* check if the demod is there */
+       ret = cx24123_readreg(state, 0x00);
+       if ((ret != 0xd1) && (ret != 0xe1)) {
+               printk("Version != d1 or e1\n");
+               goto error;
+       }
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       kfree(state);
+
+       return NULL;
+}
+
+static struct dvb_frontend_ops cx24123_ops = {
+
+       .info = {
+               .name = "Conexant CX24123/CX24109",
+               .type = FE_QPSK,
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_stepsize = 1011, /* kHz for QPSK frontends */
+               .frequency_tolerance = 29500,
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 45000000,
+               .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_RECOVER
+       },
+
+       .release = cx24123_release,
+
+       .init = cx24123_initfe,
+       .set_frontend = cx24123_set_frontend,
+       .get_frontend = cx24123_get_frontend,
+       .read_status = cx24123_read_status,
+       .read_ber = cx24123_read_ber,
+       .read_signal_strength = cx24123_read_signal_strength,
+       .read_snr = cx24123_read_snr,
+       .read_ucblocks = cx24123_read_ucblocks,
+       .diseqc_send_master_cmd = cx24123_send_diseqc_msg,
+       .set_tone = cx24123_set_tone,
+       .set_voltage = cx24123_set_voltage,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx24123_attach);
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
new file mode 100644 (file)
index 0000000..0c922b5
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+    Copyright (C) 2005 Steven Toth <stoth@hauppauge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef CX24123_H
+#define CX24123_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24123_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /*
+          cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
+          for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
+          from register 0x29 of the CX24123 demodulator
+       */
+       int use_isl6421;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+       /* Need to set device param for start_dma */
+       int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+       void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
+};
+
+extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif /* CX24123_H */
index f857b869616c305cff9cf1b66135eaa303eb6841..a3d57ce9dd1230ded1a291ad590e39703dcf7c54 100644 (file)
@@ -107,18 +107,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
 };
 EXPORT_SYMBOL(dvb_pll_microtune_4042);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7611 = {
-       .name  = "Thomson dtt7611",
-       .min   =  44000000,
-       .max   = 958000000,
+struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+       /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+       .name  = "Thomson dtt761x",
+       .min   =  57000000,
+       .max   = 863000000,
        .count = 3,
        .entries = {
-               { 157250000, 44000000, 62500, 0x8e, 0x39 },
-               { 454000000, 44000000, 62500, 0x8e, 0x3a },
+               { 147000000, 44000000, 62500, 0x8e, 0x39 },
+               { 417000000, 44000000, 62500, 0x8e, 0x3a },
                { 999999999, 44000000, 62500, 0x8e, 0x3c },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7611);
+EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
 
 struct dvb_pll_desc dvb_pll_unknown_1 = {
        .name  = "unknown 1", /* used by dntv live dvb-t */
index 497d31dcf41ebd0e832004ce6194f02a4b913287..24d4d2e9acd8fdcc6361621454af2c43a110cb18 100644 (file)
@@ -25,7 +25,7 @@ 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_dtt7611;
+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;
index cb5301865d07e9d0775bb9bb588ff3b05a3483fd..9d214643b87a4c65e1551070adfc636165bc13c4 100644 (file)
@@ -27,6 +27,7 @@
  *   DViCO FusionHDTV 3 Gold-T
  *   DViCO FusionHDTV 5 Gold
  *   DViCO FusionHDTV 5 Lite
+ *   DViCO FusionHDTV 5 USB Gold
  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
  *
  * TODO:
@@ -402,6 +403,8 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
                state->config->pll_set(fe, param);
 
        /* Keep track of the new frequency */
+       /* FIXME this is the wrong way to do this...           */
+       /* The tuner is shared with the video4linux analog API */
        state->current_frequency = param->frequency;
 
        lgdt330x_SwReset(state);
index 8d672283c93de1ef15c3d500c1fd4896b8a03bb2..ec4e641acc64446db0f8577342652dd8614c2961 100644 (file)
@@ -501,7 +501,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
        case ID_VP310:
        // For now we will do this only for the VP310.
        // It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
-               if ((ret = mt312_readreg(state, CONFIG, &config_val) < 0))
+               ret = mt312_readreg(state, CONFIG, &config_val);
+               if (ret < 0)
                        return ret;
                if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
                {
index 52c416043a628f24dd24cc65279a4f45057f306a..4f263e65ba1419af035891219640146b63e8a327 100644 (file)
@@ -22,7 +22,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
 #define CRC_CCIT_MASK 0x1021
index a458a3bfff7009fa3ed80f99822edcef2e23507d..a16eeba0020d8484a8a43c44032eb754e831fdba 100644 (file)
@@ -574,11 +574,11 @@ static struct dvb_frontend_ops nxt6000_ops = {
                .symbol_rate_max = 9360000,     /* FIXME */
                .symbol_rate_tolerance = 4000,
                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-                       FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-                       FE_CAN_HIERARCHY_AUTO,
+                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO,
        },
 
        .release = nxt6000_release,
index 531f76246e5f71bdd226632f4f908a5d8fcc60ec..7c3aed1f546be2609631206639271fbd6f9b178b 100644 (file)
@@ -25,7 +25,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
 
@@ -112,7 +113,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
        u8 tudata[585];
        int i;
 
-       dprintk("Firmware is %d bytes\n",fw->size);
+       dprintk("Firmware is %zd bytes\n",fw->size);
 
        /* Get eprom data */
        tudata[0] = 17;
index 18715091aed8e779e2a64f1241a057aecf642574..d69477596921909e38ab53fda4d236f979352eb8 100644 (file)
@@ -521,8 +521,8 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state,
 
                case FEC_3_4:
                        s5h1420_writereg(state, 0x30, 0x04);
-                       s5h1420_writereg(state, 0x31, 0x12 | inversion);
-                       break;
+                       s5h1420_writereg(state, 0x31, 0x12 | inversion);
+                       break;
 
                case FEC_5_6:
                        s5h1420_writereg(state, 0x30, 0x08);
index fc06cd6b46c3c843df95422811cb35faf3a44646..73829e647e50ad0cccb0e2f8cf6f8b18ada520ff 100644 (file)
@@ -22,7 +22,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
 
index e3b6657822432e98f39fe3a6c6630d092a096581..eb8a602198ca99ad6990c783f31a305c368214b8 100644 (file)
@@ -5,7 +5,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
 
@@ -581,7 +582,7 @@ static struct dvb_frontend_ops sp887x_ops = {
                .caps = 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_RECOVER
+                       FE_CAN_RECOVER
        },
 
        .release = sp887x_release,
index 177d71d56b67ac579ac9111c5397bffcbfa01dbe..5bcd00f792e63ac7dbe255223103c91b4015865e 100644 (file)
@@ -131,6 +131,13 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
        return ret == 2 ? 0 : ret;
 }
 
+int stv0299_enable_plli2c (struct dvb_frontend* fe)
+{
+       struct stv0299_state* state = fe->demodulator_priv;
+
+       return stv0299_writeregI(state, 0x05, 0xb5);    /*  enable i2c repeater on stv0299  */
+}
+
 static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
 {
        dprintk ("%s\n", __FUNCTION__);
@@ -387,7 +394,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
        };
 }
 
-static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
+static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
 {
        struct stv0299_state* state = fe->demodulator_priv;
        u8 reg0x08;
@@ -407,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
 
        cmd = cmd << 1;
        if (debug_legacy_dish_switch)
-               printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
+               printk ("%s switch command: 0x%04lx\n",__FUNCTION__, cmd);
 
        do_gettimeofday (&nexttime);
        if (debug_legacy_dish_switch)
@@ -717,5 +724,6 @@ MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
              "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
 MODULE_LICENSE("GPL");
 
+EXPORT_SYMBOL(stv0299_enable_plli2c);
 EXPORT_SYMBOL(stv0299_writereg);
 EXPORT_SYMBOL(stv0299_attach);
index 9af3d71c89dbe9a6c5e5a90f54fe6bdd6f2c692f..32c87b4c2f1375ec78c267db07cc666130eb6642 100644 (file)
@@ -94,6 +94,7 @@ struct stv0299_config
 };
 
 extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
+extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
 
 extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
                                           struct i2c_adapter* i2c);
index 425cd19136fe351ed339077cb2e80863a2bf4268..21255cac9793e89b07a3627a076120364cb83163 100644 (file)
@@ -95,7 +95,7 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
        u8 b0 [] = { reg };
        u8 b1 [] = { 0 };
        struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-                                 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+                                 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
        int ret;
 
        ret = i2c_transfer (state->i2c, msg, 2);
@@ -434,7 +434,7 @@ static struct dvb_frontend_ops tda10021_ops = {
                .frequency_max = 858000000,
                .symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
                .symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
-       #if 0
+#if 0
                .frequency_tolerance = ???,
                .symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
        #endif
index dd02aff467fe49c4acc7cd2674472cce88a10ad0..c63e9a5084eb7ffcb1c50b9efebee1a0f85b946c 100644 (file)
@@ -23,7 +23,8 @@
  * This driver needs external firmware. Please use the commands
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
- * download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+ * download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
 #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
@@ -271,32 +272,57 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state,
 static int tda10046h_set_bandwidth(struct tda1004x_state *state,
                                   fe_bandwidth_t bandwidth)
 {
-       static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e };
-       static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 };
-       static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd };
-
+       static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
+       static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
+       static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
+
+       static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
+       static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
+       static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
+       int tda10046_clk53m;
+
+       if ((state->config->if_freq == TDA10046_FREQ_045) ||
+           (state->config->if_freq == TDA10046_FREQ_052))
+               tda10046_clk53m = 0;
+       else
+               tda10046_clk53m = 1;
        switch (bandwidth) {
        case BANDWIDTH_6_MHZ:
-               tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+               if (tda10046_clk53m)
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
+                                                 sizeof(bandwidth_6mhz_53M));
+               else
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
+                                                 sizeof(bandwidth_6mhz_48M));
                if (state->config->if_freq == TDA10046_FREQ_045) {
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09);
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
                }
                break;
 
        case BANDWIDTH_7_MHZ:
-               tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+               if (tda10046_clk53m)
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
+                                                 sizeof(bandwidth_7mhz_53M));
+               else
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
+                                                 sizeof(bandwidth_7mhz_48M));
                if (state->config->if_freq == TDA10046_FREQ_045) {
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
                }
                break;
 
        case BANDWIDTH_8_MHZ:
-               tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+               if (tda10046_clk53m)
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
+                                                 sizeof(bandwidth_8mhz_53M));
+               else
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
+                                                 sizeof(bandwidth_8mhz_48M));
                if (state->config->if_freq == TDA10046_FREQ_045) {
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
                }
                break;
 
@@ -418,9 +444,22 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
 static void tda10046_init_plls(struct dvb_frontend* fe)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
+       int tda10046_clk53m;
+
+       if ((state->config->if_freq == TDA10046_FREQ_045) ||
+           (state->config->if_freq == TDA10046_FREQ_052))
+               tda10046_clk53m = 0;
+       else
+               tda10046_clk53m = 1;
 
        tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
-       tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10
+       if(tda10046_clk53m) {
+               printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
+               tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
+       } else {
+               printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
+               tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
+       }
        if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
                dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
                tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
@@ -428,26 +467,32 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
                dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
                tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
        }
-       tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
+       if(tda10046_clk53m)
+               tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
+       else
+               tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
+       /* Note clock frequency is handled implicitly */
        switch (state->config->if_freq) {
-       case TDA10046_FREQ_3617:
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
-               break;
-       case TDA10046_FREQ_3613:
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13);
-               break;
        case TDA10046_FREQ_045:
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
                break;
        case TDA10046_FREQ_052:
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
+               break;
+       case TDA10046_FREQ_3617:
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
+               break;
+       case TDA10046_FREQ_3613:
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
                break;
        }
        tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
+       /* let the PLLs settle */
+       msleep(120);
 }
 
 static int tda10046_fwupload(struct dvb_frontend* fe)
@@ -462,13 +507,13 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
        /* let the clocks recover from sleep */
        msleep(5);
 
+       /* The PLLs need to be reprogrammed after sleep */
+       tda10046_init_plls(fe);
+
        /* don't re-upload unless necessary */
        if (tda1004x_check_upload_ok(state) == 0)
                return 0;
 
-       /* set parameters */
-       tda10046_init_plls(fe);
-
        if (state->config->request_firmware != NULL) {
                /* request the firmware, this will block until someone uploads it */
                printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
@@ -484,7 +529,6 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
                        return ret;
        } else {
                /* boot from firmware eeprom */
-               /* Hac Note: we might need to do some GPIO Magic here */
                printk(KERN_INFO "tda1004x: booting from eeprom\n");
                tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
                msleep(300);
@@ -606,10 +650,9 @@ static int tda10046_init(struct dvb_frontend* fe)
 
        // tda setup
        tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
-       tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream
-       tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
+       tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
+       tda1004x_write_byteI(state, TDA1004X_CONFC1, 8);      // disable pulse killer
 
-       tda10046_init_plls(fe);
        switch (state->config->agc_config) {
        case TDA10046_AGC_DEFAULT:
                tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
@@ -626,25 +669,22 @@ static int tda10046_init(struct dvb_frontend* fe)
        case TDA10046_AGC_TDA827X:
                tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
                tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
-               tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize
-               tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+               tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+               tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
                break;
        }
+       tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
        tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
        tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);    // }
        tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
        tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);     // }
        tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
-       tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
+       tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
        tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
        tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
        tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
        tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
 
-       tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
-       tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
-       tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select
-
        state->initialised = 1;
        return 0;
 }
@@ -686,9 +726,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 
        // Set standard params.. or put them to auto
        if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
-           (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
-           (fe_params->u.ofdm.constellation == QAM_AUTO) ||
-           (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
+               (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
+               (fe_params->u.ofdm.constellation == QAM_AUTO) ||
+               (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
                tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);        // enable auto
                tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits
                tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
@@ -851,6 +891,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
+
        dprintk("%s\n", __FUNCTION__);
 
        // inversion status
@@ -875,16 +916,18 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
                        break;
                }
                break;
-
        case TDA1004X_DEMOD_TDA10046:
                switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
-               case 0x60:
+               case 0x5c:
+               case 0x54:
                        fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
                        break;
-               case 0x6e:
+               case 0x6a:
+               case 0x60:
                        fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
                        break;
-               case 0x80:
+               case 0x7b:
+               case 0x70:
                        fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
                        break;
                }
index f02842be0d602b70dc3bca573ef0546bf496109c..84f8f9f52869a778f797d7dc2bfffb73f61b52b1 100644 (file)
@@ -8,7 +8,7 @@ config DVB_PLUTO2
          Support for PCI cards based on the Pluto2 FPGA like the Satelco
          Easywatch Mobile Terrestrial DVB-T Receiver.
 
-          Since these cards have no MPEG decoder onboard, they transmit
+         Since these cards have no MPEG decoder onboard, they transmit
          only compressed MPEG data over the PCI bus, so you need
          an external software decoder to watch TV on your computer.
 
index fa5034a9ecf588ae955b751818b955814fc6eeb3..5b2aadb8385c2b92ee1d3b57145975fc185d848d 100644 (file)
@@ -18,9 +18,10 @@ config DVB_AV7110
          This driver only supports the fullfeatured cards with
          onboard MPEG2 decoder.
 
-          This driver needs an external firmware. Please use the script
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
-          download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+         This driver needs an external firmware. Please use the script
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
          Say Y if you own such a card and want to use it.
 
index 825ab1c38a4f75f60077caa22a828514a3fedd91..a690730ac39d831054956e4a953ce560e18b7486 100644 (file)
@@ -16,7 +16,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 hostprogs-y    := fdump
 
 ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h 
+$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
 
 $(obj)/av7110_firm.h:
        $(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
index 7dae91e5863c002c885e4247b8b253dfe37dc90c..8ce4146f55f12cc96953e1f96e6b0826fa3ea684 100644 (file)
@@ -133,7 +133,13 @@ static void init_av7110_av(struct av7110 *av7110)
        /* remaining inits according to card and frontend type */
        av7110->analog_tuner_flags = 0;
        av7110->current_input = 0;
-       if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
+       if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) {
+               printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n",
+                       av7110->dvb_adapter.num);
+               av7110->adac_type = DVB_ADAC_MSP34x5;
+               av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
+       }
+       else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
                printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
                        av7110->dvb_adapter.num);
                av7110->adac_type = DVB_ADAC_CRYSTAL;
@@ -156,10 +162,10 @@ static void init_av7110_av(struct av7110 *av7110)
        else {
                av7110->adac_type = adac;
                printk("dvb-ttpci: adac type set to %d @ card %d\n",
-                       av7110->dvb_adapter.num, av7110->adac_type);
+                       av7110->adac_type, av7110->dvb_adapter.num);
        }
 
-       if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
+       if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) {
                // switch DVB SCART on
                ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
                if (ret < 0)
@@ -190,17 +196,15 @@ static void recover_arm(struct av7110 *av7110)
 
        av7110_bootarm(av7110);
        msleep(100);
-       restart_feeds(av7110);
-       av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
-}
 
-static void arm_error(struct av7110 *av7110)
-{
-       dprintk(4, "%p\n",av7110);
+       init_av7110_av(av7110);
+
+       /* card-specific recovery */
+       if (av7110->recover)
+               av7110->recover(av7110);
 
-       av7110->arm_errors++;
-       av7110->arm_ready = 0;
-       recover_arm(av7110);
+       restart_feeds(av7110);
+       av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
 }
 
 static void av7110_arm_sync(struct av7110 *av7110)
@@ -240,26 +244,22 @@ static int arm_thread(void *data)
 
                if (down_interruptible(&av7110->dcomlock))
                        break;
-
                newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
                up(&av7110->dcomlock);
 
-               if (newloops == av7110->arm_loops) {
+               if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
                        printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
                               av7110->dvb_adapter.num);
 
-                       arm_error(av7110);
-                       av7710_set_video_mode(av7110, vidmode);
-
-                       init_av7110_av(av7110);
+                       recover_arm(av7110);
 
                        if (down_interruptible(&av7110->dcomlock))
                                break;
-
                        newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
                        up(&av7110->dcomlock);
                }
                av7110->arm_loops = newloops;
+               av7110->arm_errors = 0;
        }
 
        av7110->arm_thread = NULL;
@@ -510,10 +510,6 @@ static void gpioirq(unsigned long data)
                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
 
                av7110->video_size.h = h_ar & 0xfff;
-               dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
-                       av7110->video_size.w,
-                       av7110->video_size.h,
-                       av7110->video_size.aspect_ratio);
 
                event.type = VIDEO_EVENT_SIZE_CHANGED;
                event.u.size.w = av7110->video_size.w;
@@ -535,6 +531,11 @@ static void gpioirq(unsigned long data)
                        event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
                        av7110->videostate.video_format = VIDEO_FORMAT_4_3;
                }
+
+               dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
+                       av7110->video_size.w, av7110->video_size.h,
+                       av7110->video_size.aspect_ratio);
+
                dvb_video_add_event(av7110, &event);
                break;
        }
@@ -714,6 +715,8 @@ static struct dvb_device dvbdev_osd = {
 static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
                          u16 subpid, u16 pcrpid)
 {
+       u16 aflags = 0;
+
        dprintk(4, "%p\n", av7110);
 
        if (vpid == 0x1fff || apid == 0x1fff ||
@@ -725,8 +728,11 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
                av7110->pids[DMX_PES_PCR] = 0;
        }
 
-       return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5,
-                            pcrpid, vpid, apid, ttpid, subpid);
+       if (av7110->audiostate.bypass_mode)
+               aflags |= 0x8000;
+
+       return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6,
+                            pcrpid, vpid, apid, ttpid, subpid, aflags);
 }
 
 int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
@@ -1043,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110)
        struct dvb_demux *dvbdmx = &av7110->demux;
        struct dvb_demux_feed *feed;
        int mode;
-       int i;
+       int i, j;
 
        dprintk(4, "%p\n", av7110);
 
@@ -1051,10 +1057,21 @@ static void restart_feeds(struct av7110 *av7110)
        av7110->playing = 0;
        av7110->rec_mode = 0;
 
-       for (i = 0; i < dvbdmx->filternum; i++) {
+       for (i = 0; i < dvbdmx->feednum; i++) {
                feed = &dvbdmx->feed[i];
-               if (feed->state == DMX_STATE_GO)
+               if (feed->state == DMX_STATE_GO) {
+                       if (feed->type == DMX_TYPE_SEC) {
+                               for (j = 0; j < dvbdmx->filternum; j++) {
+                                       if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
+                                               continue;
+                                       if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
+                                               continue;
+                                       if (dvbdmx->filter[j].state == DMX_STATE_GO)
+                                               dvbdmx->filter[j].state = DMX_STATE_READY;
+                               }
+                       }
                        av7110_start_feed(feed);
+               }
        }
 
        if (mode)
@@ -1483,9 +1500,9 @@ static int get_firmware(struct av7110* av7110)
                if (ret == -ENOENT) {
                        printk(KERN_ERR "dvb-ttpci: could not load firmware,"
                               " file not found: dvb-ttpci-01.fw\n");
-                       printk(KERN_ERR "dvb-ttpci: usually this should be in"
-                              " /usr/lib/hotplug/firmware\n");
-                       printk(KERN_ERR "dvb-ttpci: and can be downloaded here"
+                       printk(KERN_ERR "dvb-ttpci: usually this should be in "
+                              "/usr/lib/hotplug/firmware or /lib/firmware\n");
+                       printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
                               " http://www.linuxtv.org/download/dvb/firmware/\n");
                } else
                        printk(KERN_ERR "dvb-ttpci: cannot request firmware"
@@ -2110,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_fe_params = *params;
                ret = av7110->fe_set_frontend(fe, params);
+       }
        return ret;
 }
 
@@ -2153,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_master_cmd = *cmd;
                ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
+       }
        return ret;
 }
 
@@ -2163,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_minicmd = minicmd;
                ret = av7110->fe_diseqc_send_burst(fe, minicmd);
+       }
        return ret;
 }
 
@@ -2173,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_tone = tone;
                ret = av7110->fe_set_tone(fe, tone);
+       }
        return ret;
 }
 
@@ -2183,12 +2208,14 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_voltage = voltage;
                ret = av7110->fe_set_voltage(fe, voltage);
+       }
        return ret;
 }
 
-static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd)
 {
        struct av7110* av7110 = fe->dvb->priv;
 
@@ -2198,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un
        return ret;
 }
 
+static void dvb_s_recover(struct av7110* av7110)
+{
+       av7110_fe_init(av7110->fe);
+
+       av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
+       if (av7110->saved_master_cmd.msg_len) {
+               msleep(20);
+               av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
+       }
+       msleep(20);
+       av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
+       msleep(20);
+       av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
+
+       av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
+}
+
 static u8 read_pwm(struct av7110* av7110)
 {
        u8 b = 0xff;
@@ -2235,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110)
                                av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
                                av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
                                av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->recover = dvb_s_recover;
                                break;
                        }
 
@@ -2244,15 +2289,17 @@ static int frontend_init(struct av7110 *av7110)
                                av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
                                av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
                                av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->recover = dvb_s_recover;
                                break;
                        }
 
                        // Try the grundig 29504-451
-                       av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+                       av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
                        if (av7110->fe) {
                                av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
                                av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
                                av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->recover = dvb_s_recover;
                                break;
                        }
 
@@ -2274,12 +2321,12 @@ static int frontend_init(struct av7110 *av7110)
                case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
 
                        // ALPS TDLB7
-                       av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+                       av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
                        break;
 
                case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
 
-                       av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+                       av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
                        break;
 
                case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
@@ -2289,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110)
                                av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
                                av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
                                av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->recover = dvb_s_recover;
                        }
                        break;
 
@@ -2314,8 +2362,11 @@ static int frontend_init(struct av7110 *av7110)
                case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
                        /* ALPS BSBE1 */
                        av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
-                       if (av7110->fe)
+                       if (av7110->fe) {
                                av7110->fe->ops->set_voltage = lnbp21_set_voltage;
+                               av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+                               av7110->recover = dvb_s_recover;
+                       }
                        break;
                }
        }
index cce00ef293e94fa41daa0419f54cca8b85778d61..6ea30df2e823c3dc54cf10699df7d2af4609ac3b 100644 (file)
@@ -98,7 +98,8 @@ struct av7110 {
        int adac_type;         /* audio DAC type */
 #define DVB_ADAC_TI      0
 #define DVB_ADAC_CRYSTAL  1
-#define DVB_ADAC_MSP     2
+#define DVB_ADAC_MSP34x0  2
+#define DVB_ADAC_MSP34x5  3
 #define DVB_ADAC_NONE   -1
 
 
@@ -228,6 +229,9 @@ struct av7110 {
        struct dvb_video_events  video_events;
        video_size_t             video_size;
 
+       u16                     wssMode;
+       u16                     wssData;
+
        u32                     ir_config;
        u32                     ir_command;
        void                    (*ir_handler)(struct av7110 *av7110, u32 ircom);
@@ -245,6 +249,15 @@ struct av7110 {
 
        struct dvb_frontend* fe;
        fe_status_t fe_status;
+
+       /* crash recovery */
+       void                            (*recover)(struct av7110* av7110);
+       struct dvb_frontend_parameters  saved_fe_params;
+       fe_sec_voltage_t                saved_voltage;
+       fe_sec_tone_mode_t              saved_tone;
+       struct dvb_diseqc_master_cmd    saved_master_cmd;
+       fe_sec_mini_cmd_t               saved_minicmd;
+
        int (*fe_init)(struct dvb_frontend* fe);
        int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
        int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
@@ -252,7 +265,7 @@ struct av7110 {
        int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
        int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
        int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-       int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+       int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
        int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
index 0696a5a4f85594c963758fdc53b9b2932a320fe4..400facec740717d5d97f37af108b86dfe8373d0b 100644 (file)
@@ -309,7 +309,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
                i2c_writereg(av7110, 0x20, 0x04, volright);
                return 0;
 
-       case DVB_ADAC_MSP:
+       case DVB_ADAC_MSP34x0:
                vol  = (volleft > volright) ? volleft : volright;
                val     = (vol * 0x73 / 255) << 8;
                if (vol > 0)
@@ -1256,7 +1256,9 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                break;
 
        case AUDIO_SET_BYPASS_MODE:
-               ret = -EINVAL;
+               if (FW_VERSION(av7110->arm_app) < 0x2621)
+                       ret = -EINVAL;
+               av7110->audiostate.bypass_mode = (int)arg;
                break;
 
        case AUDIO_CHANNEL_SELECT:
@@ -1295,7 +1297,11 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                break;
 
        case AUDIO_GET_CAPABILITIES:
-               *(int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+               if (FW_VERSION(av7110->arm_app) < 0x2621)
+                       *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+               else
+                       *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |
+                                               AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
                break;
 
        case AUDIO_CLEAR_BUFFER:
index 87106e8bf35bc83b3fa61c85018caae6c6436687..cb377452b57dcfef26ffa9cd070588f060fe55f2 100644 (file)
@@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110)
 
        dprintk(4, "%p\n", av7110);
 
+       av7110->arm_ready = 0;
+
        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 
        /* Disable DEBI and GPIO irq */
@@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
                        break;
                if (err) {
                        printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
+                       av7110->arm_errors++;
                        return -ETIMEDOUT;
                }
                msleep(1);
@@ -1206,9 +1209,9 @@ int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
        switch (cap->cmd) {
        case OSD_CAP_MEMSIZE:
                if (FW_4M_SDRAM(av7110->arm_app))
-                       cap->val = 1000000;
+                       cap->val = 1000000;
                else
-                       cap->val = 92000;
+                       cap->val = 92000;
                return 0;
        default:
                return -EINVAL;
index 2a5e87ba10521129f04738ea5d9d178598581acd..84b83299b8bec7642c931ebf65177393860517e8 100644 (file)
@@ -167,7 +167,8 @@ enum av7110_encoder_command {
        LoadVidCode,
        SetMonitorType,
        SetPanScanType,
-       SetFreezeMode
+       SetFreezeMode,
+       SetWSSConfig
 };
 
 enum av7110_rec_play_state {
index f5e59fc924afeaf1f75ebd320544a05eba209ba3..9138132ad25f3d10e93f4819e06ba70fe4a3ef22 100644 (file)
@@ -17,6 +17,8 @@ static int av_cnt;
 static struct av7110 *av_list[4];
 static struct input_dev *input_dev;
 
+static u8 delay_timer_finished;
+
 static u16 key_map [256] = {
        KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
        KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
@@ -112,13 +114,16 @@ static void av7110_emit_key(unsigned long parm)
        if (timer_pending(&keyup_timer)) {
                del_timer(&keyup_timer);
                if (keyup_timer.data != keycode || new_toggle != old_toggle) {
+                       delay_timer_finished = 0;
                        input_event(input_dev, EV_KEY, keyup_timer.data, !!0);
                        input_event(input_dev, EV_KEY, keycode, !0);
                } else
-                       input_event(input_dev, EV_KEY, keycode, 2);
-
-       } else
+                       if (delay_timer_finished)
+                               input_event(input_dev, EV_KEY, keycode, 2);
+       } else {
+               delay_timer_finished = 0;
                input_event(input_dev, EV_KEY, keycode, !0);
+       }
 
        keyup_timer.expires = jiffies + UP_TIMEOUT;
        keyup_timer.data = keycode;
@@ -145,7 +150,8 @@ static void input_register_keys(void)
 
 static void input_repeat_key(unsigned long data)
 {
-       /* dummy routine to disable autorepeat in the input driver */
+       /* called by the input driver after rep[REP_DELAY] ms */
+       delay_timer_finished = 1;
 }
 
 
index b5aea4129fa7304aebdd237678f91760cd6aeb48..94cf38c7e8a809f8f5cf5ce2bba99c9f160aea0d 100644 (file)
@@ -490,6 +490,58 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
                break;
        }
+       case VIDIOC_G_SLICED_VBI_CAP:
+       {
+               struct v4l2_sliced_vbi_cap *cap = arg;
+               dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
+               memset(cap, 0, sizeof *cap);
+               if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+                       cap->service_set = V4L2_SLICED_WSS_625;
+                       cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+               }
+               break;
+       }
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *f = arg;
+               dprintk(2, "VIDIOC_G_FMT:\n");
+               if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+                   FW_VERSION(av7110->arm_app) < 0x2623)
+                       return -EAGAIN; /* handled by core driver */
+               memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+               if (av7110->wssMode) {
+                       f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+               }
+               break;
+       }
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *f = arg;
+               dprintk(2, "VIDIOC_S_FMT\n");
+               if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+                   FW_VERSION(av7110->arm_app) < 0x2623)
+                       return -EAGAIN; /* handled by core driver */
+               if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
+                   f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
+                       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+                       /* WSS controlled by firmware */
+                       av7110->wssMode = 0;
+                       av7110->wssData = 0;
+                       return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
+                                            SetWSSConfig, 1, 0);
+               } else {
+                       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+                       f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+                       /* WSS controlled by userspace */
+                       av7110->wssMode = 1;
+                       av7110->wssData = 0;
+               }
+               break;
+       }
        default:
                printk("no such ioctl\n");
                return -ENOIOCTLCMD;
@@ -497,6 +549,46 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        return 0;
 }
 
+static int av7110_vbi_reset(struct inode *inode, struct file *file)
+{
+       struct saa7146_fh *fh = file->private_data;
+       struct saa7146_dev *dev = fh->dev;
+       struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+
+       dprintk(2, "%s\n", __FUNCTION__);
+       av7110->wssMode = 0;
+       av7110->wssData = 0;
+       if (FW_VERSION(av7110->arm_app) < 0x2623)
+               return 0;
+       else
+               return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+}
+
+static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+       struct saa7146_fh *fh = file->private_data;
+       struct saa7146_dev *dev = fh->dev;
+       struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+       struct v4l2_sliced_vbi_data d;
+       int rc;
+
+       dprintk(2, "%s\n", __FUNCTION__);
+       if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
+               return -EINVAL;
+       if (copy_from_user(&d, data, count))
+               return -EFAULT;
+       if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
+               return -EINVAL;
+       if (d.id) {
+               av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
+               rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
+                                  2, 1, av7110->wssData);
+       } else {
+               av7110->wssData = 0;
+               rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+       }
+       return (rc < 0) ? rc : count;
+}
 
 /****************************************************************************
  * INITIALIZATION
@@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = {
        { VIDIOC_S_TUNER,       SAA7146_EXCLUSIVE },
        { VIDIOC_G_AUDIO,       SAA7146_EXCLUSIVE },
        { VIDIOC_S_AUDIO,       SAA7146_EXCLUSIVE },
+       { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
+       { VIDIOC_G_FMT,         SAA7146_BEFORE },
+       { VIDIOC_S_FMT,         SAA7146_BEFORE },
        { 0, 0 }
 };
 
@@ -587,7 +682,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
 
        printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
                av7110->dvb_adapter.num);
-       av7110->adac_type = DVB_ADAC_MSP;
+       av7110->adac_type = DVB_ADAC_MSP34x0;
        msleep(100); // the probing above resets the msp...
        msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
        msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
@@ -692,12 +787,11 @@ int av7110_init_v4l(struct av7110 *av7110)
                saa7146_vv_release(dev);
                return -ENODEV;
        }
-       if (av7110->analog_tuner_flags) {
-               if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
-                       ERR(("cannot register vbi v4l2 device. skipping.\n"));
-               } else {
+       if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+               ERR(("cannot register vbi v4l2 device. skipping.\n"));
+       } else {
+               if (av7110->analog_tuner_flags)
                        av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
-               }
        }
        return 0;
 }
@@ -778,7 +872,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
 static struct saa7146_ext_vv av7110_vv_data_st = {
        .inputs         = 1,
        .audios         = 1,
-       .capabilities   = 0,
+       .capabilities   = V4L2_CAP_SLICED_VBI_OUTPUT,
        .flags          = 0,
 
        .stds           = &standard[0],
@@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
 
        .ioctls         = &ioctls[0],
        .ioctl          = av7110_ioctl,
+
+       .vbi_fops.open  = av7110_vbi_reset,
+       .vbi_fops.release = av7110_vbi_reset,
+       .vbi_fops.write = av7110_vbi_write,
 };
 
 static struct saa7146_ext_vv av7110_vv_data_c = {
        .inputs         = 1,
        .audios         = 1,
-       .capabilities   = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
+       .capabilities   = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
        .flags          = SAA7146_USE_PORT_B_FOR_VBI,
 
        .stds           = &standard[0],
@@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
 
        .ioctls         = &ioctls[0],
        .ioctl          = av7110_ioctl,
+
+       .vbi_fops.open  = av7110_vbi_reset,
+       .vbi_fops.release = av7110_vbi_reset,
+       .vbi_fops.write = av7110_vbi_write,
 };
 
index 9f51bae7194c26430d98dc0ed86b2478f1a935d6..f9d00452e6393132c9bc044b8215bffca5eba680 100644 (file)
@@ -127,7 +127,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
        saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
        udelay(1);
 
-       result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0);
+       result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
 
        if (result == -ETIMEDOUT)
                budget_av->slot_status = 0;
@@ -145,7 +145,7 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
        saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
        udelay(1);
 
-       result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0);
+       result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
 
        if (result == -ETIMEDOUT)
                budget_av->slot_status = 0;
@@ -192,7 +192,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
 {
        struct budget_av *budget_av = (struct budget_av *) ca->data;
        struct saa7146_dev *saa = budget_av->budget.dev;
-       int timeout = 500; // 5 seconds (4.4.6 Ready)
+       int timeout = 50; // 5 seconds (4.4.6 Ready)
 
        if (slot != 0)
                return -EINVAL;
@@ -256,19 +256,37 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
 {
        struct budget_av *budget_av = (struct budget_av *) ca->data;
        struct saa7146_dev *saa = budget_av->budget.dev;
+       int cam_present = 0;
 
        if (slot != 0)
                return -EINVAL;
 
-       if (!budget_av->slot_status) {
+       if (!budget_av->slot_status)
+       {
+               // first of all test the card detect line
                saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
                udelay(1);
                if (saa7146_read(saa, PSR) & MASK_06)
                {
+                       cam_present = 1;
+               }
+               saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+               // that is unreliable however, so try and read from IO memory
+               if (!cam_present)
+               {
+                       saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+                       if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
+                       {
+                               cam_present = 1;
+                       }
+               }
+
+               // did we find something?
+               if (cam_present) {
                        printk(KERN_INFO "budget-av: cam inserted\n");
                        budget_av->slot_status = 1;
                }
-               saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
        } else if (!open) {
                saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
                if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
@@ -484,6 +502,140 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
        return 0;
 }
 
+#define MIN2(a,b) ((a) < (b) ? (a) : (b))
+#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
+
+static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
+                                       struct i2c_adapter *i2c,
+                                       struct dvb_frontend_parameters *params)
+{
+       u8 reg0 [2] = { 0x00, 0x00 };
+       u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
+       u8 reg2 [3] = { 0x02, 0x00, 0x00 };
+       int _fband;
+       int first_ZF;
+       int R, A, N, P, M;
+       struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
+       int freq = params->frequency;
+
+       first_ZF = (freq) / 1000;
+
+       if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
+                  abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
+               _fband = 2;
+       else
+               _fband = 3;
+
+       if (_fband == 2) {
+               if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+                                   ((first_ZF >= 1430) && (first_ZF < 1950)))
+                       reg0[1] = 0x07;
+               else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
+                                        ((first_ZF >= 1950) && (first_ZF < 2150)))
+                       reg0[1] = 0x0B;
+       }
+
+       if(_fband == 3) {
+               if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+                                   ((first_ZF >= 1455) && (first_ZF < 1950)))
+                       reg0[1] = 0x07;
+               else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
+                                        ((first_ZF >= 1950) && (first_ZF < 2150)))
+                       reg0[1] = 0x0B;
+               else if ((first_ZF >= 1420) && (first_ZF < 1455))
+                       reg0[1] = 0x0F;
+       }
+
+       if (first_ZF > 1525)
+               reg1[1] |= 0x80;
+       else
+               reg1[1] &= 0x7F;
+
+       if (_fband == 2) {
+               if (first_ZF > 1430) { /* 1430MHZ */
+                       reg1[1] &= 0xCF; /* N2 */
+                       reg2[1] &= 0xCF; /* R2 */
+                       reg2[1] |= 0x10;
+               } else {
+                       reg1[1] &= 0xCF; /* N2 */
+                       reg1[1] |= 0x20;
+                       reg2[1] &= 0xCF; /* R2 */
+                       reg2[1] |= 0x10;
+               }
+       }
+
+       if (_fband == 3) {
+               if ((first_ZF >= 1455) &&
+                                  (first_ZF < 1630)) {
+                       reg1[1] &= 0xCF; /* N2 */
+                       reg1[1] |= 0x20;
+                       reg2[1] &= 0xCF; /* R2 */
+                                  } else {
+                                          if (first_ZF < 1455) {
+                                                  reg1[1] &= 0xCF; /* N2 */
+                                                  reg1[1] |= 0x20;
+                                                  reg2[1] &= 0xCF; /* R2 */
+                                                  reg2[1] |= 0x10;
+                                          } else {
+                                                  if (first_ZF >= 1630) {
+                                                          reg1[1] &= 0xCF; /* N2 */
+                                                          reg2[1] &= 0xCF; /* R2 */
+                                                          reg2[1] |= 0x10;
+                                                  }
+                                          }
+                                  }
+       }
+
+       /* set ports, enable P0 for symbol rates > 4Ms/s */
+       if (params->u.qpsk.symbol_rate >= 4000000)
+               reg1[1] |= 0x0c;
+       else
+               reg1[1] |= 0x04;
+
+       reg2[1] |= 0x0c;
+
+       R = 64;
+       A = 64;
+       P = 64;  //32
+
+       M = (freq * R) / 4;             /* in Mhz */
+       N = (M - A * 1000) / (P * 1000);
+
+       reg1[1] |= (N >> 9) & 0x03;
+       reg1[2]  = (N >> 1) & 0xff;
+       reg1[3]  = (N << 7) & 0x80;
+
+       reg2[1] |= (R >> 8) & 0x03;
+       reg2[2]  = R & 0xFF;    /* R */
+
+       reg1[3] |= A & 0x7f;    /* A */
+
+       if (P == 64)
+               reg1[1] |= 0x40; /* Prescaler 64/65 */
+
+       reg0[1] |= 0x03;
+
+       /* already enabled - do not reenable i2c repeater or TX fails */
+       msg.buf = reg0;
+       msg.len = sizeof(reg0);
+       if (i2c_transfer(i2c, &msg, 1) != 1)
+               return -EIO;
+
+       stv0299_enable_plli2c(fe);
+       msg.buf = reg1;
+       msg.len = sizeof(reg1);
+       if (i2c_transfer(i2c, &msg, 1) != 1)
+               return -EIO;
+
+       stv0299_enable_plli2c(fe);
+       msg.buf = reg2;
+       msg.len = sizeof(reg2);
+       if (i2c_transfer(i2c, &msg, 1) != 1)
+               return -EIO;
+
+       return 0;
+}
+
 static u8 typhoon_cinergy1200s_inittab[] = {
        0x01, 0x15,
        0x02, 0x30,
@@ -553,6 +705,18 @@ static struct stv0299_config cinergy_1200s_config = {
        .pll_set = philips_su1278_ty_ci_pll_set,
 };
 
+static struct stv0299_config cinergy_1200s_1894_0010_config = {
+       .demod_address = 0x68,
+       .inittab = typhoon_cinergy1200s_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP0,
+       .min_delay_ms = 100,
+       .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+       .pll_set = philips_su1278sh2_tua6100_pll_set,
+};
 
 static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
@@ -749,6 +913,15 @@ static void frontend_init(struct budget_av *budget_av)
        switch (saa->pci->subsystem_device) {
 
        case SUBID_DVBS_KNC1:
+               if (saa->pci->subsystem_vendor == 0x1894) {
+                       fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
+                                            &budget_av->budget.i2c_adap);
+               } else {
+                       fe = stv0299_attach(&typhoon_config,
+                                            &budget_av->budget.i2c_adap);
+               }
+               break;
+
        case SUBID_DVBS_KNC1_PLUS:
        case SUBID_DVBS_TYPHOON:
                fe = stv0299_attach(&typhoon_config,
@@ -1003,6 +1176,7 @@ MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
 static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
        MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
+       MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
        MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
        MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
        MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
index 017fcbccb8cc8c1eb737e7b41916001c16f2496b..633e68c341c87d2c99ed72e1f434693b5bfc1c4f 100644 (file)
@@ -404,9 +404,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
        tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
 
        /* frontend power on */
-       if (bi->type == BUDGET_FS_ACTIVY)
-               saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
-       else
+       if (bi->type != BUDGET_FS_ACTIVY)
                saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 
        if (budget_register(budget) == 0) {
index fafe6407b3d0d3deb7ba658ea440321de1da44ee..238c77b52f89f7f0f759ec4dc99acd3487a240ae 100644 (file)
@@ -112,6 +112,7 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
  *   Routines for the Fujitsu Siemens Activy budget card
  *   22 kHz tone and DiSEqC are handled by the frontend.
  *   Voltage must be set here.
+ *   GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
  */
 static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
 {
@@ -121,11 +122,16 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
 
        switch (voltage) {
                case SEC_VOLTAGE_13:
+                       saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
                        saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
                        break;
                case SEC_VOLTAGE_18:
+                       saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
                        saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
                        break;
+               case SEC_VOLTAGE_OFF:
+                       saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);
+                       break;
                default:
                        return -EINVAL;
        }
@@ -206,7 +212,7 @@ static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
        return 0;
 }
 
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u8 buf;
@@ -580,6 +586,7 @@ static void frontend_init(struct budget *budget)
                if (budget->dvb_frontend) {
                        budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
                        budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+                       budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
                        if (lnbp21_init(budget)) {
                                printk("%s: No LNBP21 found!\n", __FUNCTION__);
                                goto error_out;
@@ -624,7 +631,7 @@ static void frontend_init(struct budget *budget)
                budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
                        budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
-                       break;
+                       budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
                }
                break;
 
@@ -632,7 +639,7 @@ static void frontend_init(struct budget *budget)
                budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
                        budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
-                       break;
+                       budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
                }
                break;
 
index 18aa22b5478d654d15e37cddd7712c57bd09e609..1f31e91195b0c6817718d5ca4f6658247064416f 100644 (file)
@@ -13,7 +13,7 @@
     Holger Waechtler   Convergence
 
     Copyright (C) 2002-2003 Ralph Metzler <rjkm@metzlerbros.de>
-                           Metzler Brothers Systementwicklung GbR
+                           Metzler Brothers Systementwicklung GbR
 
     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
index c6c1d41a2efb70c77b46db6a80450282d7fe4fdf..914587d52b57622131592134d7feef0e9d651c6b 100644 (file)
@@ -10,7 +10,7 @@ config DVB_TTUSB_BUDGET
          Support for external USB adapters designed by Technotrend and
          produced by Hauppauge, shipped under the brand name 'Nova-USB'.
 
-          These devices don't have a MPEG decoder built in, so you need
+         These devices don't have a MPEG decoder built in, so you need
          an external software decoder to watch TV.
 
          Say Y if you own such a device and want to use it.
index c334526af66f27c436864294ca0377f48b7e1499..83611012ef345242460527b2452940bfa356e34f 100644 (file)
@@ -8,14 +8,15 @@ config DVB_TTUSB_DEC
          produced by Hauppauge, shipped under the brand name 'DEC2000-t'
          and 'DEC3000-s'.
 
-          Even if these devices have a MPEG decoder built in, they transmit
+         Even if these devices have a MPEG decoder built in, they transmit
          only compressed MPEG data over the USB bus, so you need
          an external software decoder to watch TV on your computer.
 
-          This driver needs external firmware. Please use the commands
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
-          download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+         This driver needs external firmware. Please use the commands
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
+         download/extract them, and then copy them to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
          Say Y if you own such a device and want to use it.
index 8abc21890129f18867a12ed07a5dc6b9b478440e..d8966d1d25ee7c613df1411d20d558a00351d81a 100644 (file)
@@ -369,7 +369,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
 
 static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
 {
-       struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+       struct ttusb_dec *dec = priv;
 
        dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,
                                       &dec->audio_filter->feed->feed.ts,
@@ -380,7 +380,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
 
 static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
 {
-       struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+       struct ttusb_dec *dec = priv;
 
        dec->video_filter->feed->cb.ts(data, 188, NULL, 0,
                                       &dec->video_filter->feed->feed.ts,
@@ -965,8 +965,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
 
        case DMX_TS_PES_TELETEXT:
                dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
-               dprintk("  pes_type: DMX_TS_PES_TELETEXT\n");
-               break;
+               dprintk("  pes_type: DMX_TS_PES_TELETEXT(not supported)\n");
+               return -ENOSYS;
 
        case DMX_TS_PES_PCR:
                dprintk("  pes_type: DMX_TS_PES_PCR\n");
@@ -975,8 +975,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
                break;
 
        case DMX_TS_PES_OTHER:
-               dprintk("  pes_type: DMX_TS_PES_OTHER\n");
-               break;
+               dprintk("  pes_type: DMX_TS_PES_OTHER(not supported)\n");
+               return -ENOSYS;
 
        default:
                dprintk("  pes_type: unknown (%d)\n", dvbdmxfeed->pes_type);
@@ -1182,7 +1182,7 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
                     (unsigned long)dec);
 }
 
-static int ttusb_init_rc(struct ttusb_dec *dec)
+static int ttusb_init_rc( struct ttusb_dec *dec)
 {
        struct input_dev *input_dev;
        u8 b[] = { 0x00, 0x01 };
@@ -1203,13 +1203,12 @@ static int ttusb_init_rc(struct ttusb_dec *dec)
        input_dev->keycode = rc_keys;
 
        for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
-               set_bit(rc_keys[i], input_dev->keybit);
+                 set_bit(rc_keys[i], input_dev->keybit);
 
        input_register_device(input_dev);
 
        if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
                printk("%s: usb_submit_urb failed\n",__FUNCTION__);
-
        /* enable irq pipe */
        ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
 
@@ -1395,6 +1394,7 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec)
                        /* We can't trust the USB IDs that some firmwares
                           give the box */
                        switch (model) {
+                       case 0x00070001:
                        case 0x00070008:
                        case 0x0007000c:
                                ttusb_dec_set_model(dec, TTUSB_DEC3000S);
@@ -1588,7 +1588,7 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command,
                           int param_length, const u8 params[],
                           int *result_length, u8 cmd_result[])
 {
-       struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv;
+       struct ttusb_dec* dec = fe->dvb->priv;
        return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
 }
 
index 725af3af5b27105f5c2e8555e68de691272e41fc..a5a46175fa0969e302e59e75e14afa5a2e5cf2ab 100644 (file)
@@ -42,8 +42,39 @@ struct ttusbdecfe_state {
 
 static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-       *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
-                 FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+       struct ttusbdecfe_state* state = fe->demodulator_priv;
+       u8 b[] = { 0x00, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00 };
+       u8 result[4];
+       int len, ret;
+
+       *status=0;
+
+       ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result);
+       if(ret)
+               return ret;
+
+       if(len != 4) {
+               printk(KERN_ERR "%s: unexpected reply\n", __FUNCTION__);
+               return -EIO;
+       }
+
+       switch(result[3]) {
+               case 1:  /* not tuned yet */
+               case 2:  /* no signal/no lock*/
+                       break;
+               case 3:  /* signal found and locked*/
+                       *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+                       FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+                       break;
+               case 4:
+                       *status = FE_TIMEDOUT;
+                       break;
+               default:
+                       pr_info("%s: returned unknown value: %d\n",
+                               __FUNCTION__, result[3]);
+                       return -EIO;
+       }
 
        return 0;
 }
@@ -64,6 +95,16 @@ static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_fron
        return 0;
 }
 
+static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe,
+                                       struct dvb_frontend_tune_settings* fesettings)
+{
+               fesettings->min_delay_ms = 1500;
+               /* Drift compensation makes no sense for DVB-T */
+               fesettings->step_size = 0;
+               fesettings->max_drift = 0;
+               return 0;
+}
+
 static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
        struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
@@ -212,6 +253,8 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
 
        .set_frontend = ttusbdecfe_dvbt_set_frontend,
 
+       .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
+
        .read_status = ttusbdecfe_read_status,
 };
 
@@ -223,11 +266,11 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 125,
+               .symbol_rate_min        = 1000000,  /* guessed */
+               .symbol_rate_max        = 45000000, /* guessed */
                .caps = 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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-                       FE_CAN_HIERARCHY_AUTO,
+                       FE_CAN_QPSK
        },
 
        .release = ttusbdecfe_release,
index c2ebe8754a9569bf326430a08920e3a096a2aa07..dc292da2605ffb4204dfcfb7c24b1ffc23256c42 100644 (file)
@@ -220,6 +220,7 @@ static struct file_operations pcm20_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = pcm20_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 877c770558e9c407350da4ea90d92b2e875cefd2..914deab4e04440c462e28a28998ff2c8c2e92141 100644 (file)
@@ -299,6 +299,7 @@ static struct file_operations rtrack_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = rt_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 5319a9c9a9796bbf4e0d769a3e120cd98d5dc952..523be820f9c64c3f6fd48fa226aebea16f5489ae 100644 (file)
@@ -256,6 +256,7 @@ static struct file_operations aztech_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = az_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 9b0406318f2d9d31fa74f98dca827d343a1c1443..f1b5ac81e9d2bc734d6dd3345c12d0bd46fa235e 100644 (file)
@@ -490,6 +490,7 @@ static struct file_operations cadet_fops = {
        .release        = cadet_release,
        .read           = cadet_read,
        .ioctl          = cadet_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 630cc786d0a4f5065c357b150435dc1108a5dce7..42c8fce04aa2650aeded8b2f6e21f9adec07ac85 100644 (file)
@@ -301,6 +301,7 @@ static struct file_operations gemtek_pci_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = gemtek_pci_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 6418f03b9ce4b74b1711e03a718efe952028bd06..47173be97b9fa5dbd74d84e6e5ebce0007393609 100644 (file)
@@ -233,6 +233,7 @@ static struct file_operations gemtek_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = gemtek_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index e5e2021a7312f4c82eee58b96e2a5bde455809dc..c30effdf711feb6ba8e5457b5c908ca472abeb52 100644 (file)
@@ -72,6 +72,7 @@ static struct file_operations maestro_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = radio_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 02d39a50d5ed2b742d6e2b65678056a249e096b7..30869308332af3bff2d3af7ba6e2098f0738fe0a 100644 (file)
@@ -80,6 +80,7 @@ static struct file_operations maxiradio_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = radio_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 static struct video_device maxiradio_radio =
index b2256d675b4434f8f8553b13d4892089a6edff6e..28a47c9e7a819a4791d122d02380ca12e46ffd40 100644 (file)
@@ -199,6 +199,7 @@ static struct file_operations rtrack2_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = rt_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 6f03ce4dd7b0e4fb076c72dcfe9cdec20b122c8f..0229f792a05969717a7271356a03a1a6c51da3ce 100644 (file)
@@ -225,6 +225,7 @@ static struct file_operations fmi_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = fmi_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 71971e9bb3422c36acb8280becdfbf03a9c37944..26632cead09a7dc7dd5d59388b719b6f3684b842 100644 (file)
@@ -356,6 +356,7 @@ static struct file_operations fmr2_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = fmr2_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index b03573c6840e56e632bd52f60aa90aabc45abc81..fcfde2e4f1958d47d1c4ec34d69f610cb1733e0b 100644 (file)
@@ -276,6 +276,7 @@ static struct file_operations terratec_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = tt_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index b300bedf7c743825cdffd13b5a58c212d28ff8e2..5a099a50d4d060e1af66e7a31711d7b3182fb2c8 100644 (file)
@@ -255,6 +255,7 @@ static struct file_operations trust_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = tr_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index f304f3c147637c92a7956f88c7fc548429f3338a..8ac9a8ef909441e98171dbb4b4f4e65d5c16b749 100644 (file)
@@ -261,6 +261,7 @@ static struct file_operations typhoon_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = typhoon_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 4c6d6fb49034e04a04d1c2d220e574b5aed1d434..d590e80c922e336a69d610f26f18f3cf28898652 100644 (file)
@@ -313,6 +313,7 @@ static struct file_operations zoltrix_fops =
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = zol_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index fc87efc5049c0c64ef3e660393ef042840e84a8a..2fe260fff85dd25b8d952f23dfbaff412cea4848 100644 (file)
@@ -7,6 +7,15 @@ menu "Video For Linux"
 
 comment "Video Adapters"
 
+config VIDEO_ADV_DEBUG
+       bool "Enable advanced debug functionality"
+       depends on VIDEO_DEV
+       default n
+       ---help---
+         Say Y here to enable advanced debugging functionality on some
+         V4L devices.
+         In doubt, say N.
+
 config VIDEO_BT848
        tristate "BT848 Video For Linux"
        depends on VIDEO_DEV && PCI && I2C
@@ -342,6 +351,6 @@ config VIDEO_DECODER
        depends on VIDEO_DEV && I2C && EXPERIMENTAL
        ---help---
          Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
-         video  decoders.
+         video decoders.
 
 endmenu
index 82060f9909d89db008fa0c5c48dc32b46d5b0cc3..dd24896906fe732022303e7d8418bb075b1475f4 100644 (file)
@@ -3,15 +3,19 @@
 #
 
 bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
-                       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o
+                       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
+                       bttv-input.o
 zoran-objs      :=     zr36120.o zr36120_i2c.o zr36120_mem.o
 zr36067-objs   :=      zoran_procfs.o zoran_device.o \
                        zoran_driver.o zoran_card.o
 tuner-objs     :=      tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
+
+msp3400-objs   :=      msp3400-driver.o msp3400-kthreads.o
+
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
-       tda7432.o tda9875.o ir-kbd-i2c.o ir-kbd-gpio.o
+       tda7432.o tda9875.o ir-kbd-i2c.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
index 881cdcb1875d3f6dce6f9200065e27fe502738f7..7d5a068353f28d8c65ee077ceefa2e7f3d56fd60 100644 (file)
@@ -749,6 +749,7 @@ static struct file_operations ar_fops = {
        .release        = video_exclusive_release,
        .read           = ar_read,
        .ioctl          = ar_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 1c3ff5f38a6d4e70d763330ee547396ec828429e..dda4aa6bef27c6da07a6fc104faef8972075edfe 100644 (file)
@@ -30,8 +30,9 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-
 #include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
 #include "bttv.h"
 #include "bt832.h"
 
@@ -42,9 +43,10 @@ static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1,
                                       I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
 
-/* ---------------------------------------------------------------------- */
+int debug    = 0;    /* debug output */
+module_param(debug,            int, 0644);
 
-#define dprintk     if (debug) printk
+/* ---------------------------------------------------------------------- */
 
 static int bt832_detach(struct i2c_client *client);
 
@@ -61,23 +63,26 @@ int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
        int i,rc;
        buf[0]=0x80; // start at register 0 with auto-increment
        if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
-               printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+               v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
 
        for(i=0;i<65;i++)
                buf[i]=0;
        if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
-               printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+               v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
 
        // Note: On READ the first byte is the current index
        //  (e.g. 0x80, what we just wrote)
 
-       if(1) {
+       if(debug>1) {
                int i;
-               printk("BT832 hexdump:\n");
+               v4l_dbg(2,i2c_client_s,"hexdump:");
                for(i=1;i<65;i++) {
                        if(i!=1) {
-                         if(((i-1)%8)==0) printk(" ");
-                         if(((i-1)%16)==0) printk("\n");
+                               if(((i-1)%8)==0) printk(" ");
+                               if(((i-1)%16)==0) {
+                                       printk("\n");
+                                       v4l_dbg(2,i2c_client_s,"hexdump:");
+                               }
                        }
                        printk(" %02x",buf[i]);
                }
@@ -96,56 +101,56 @@ int bt832_init(struct i2c_client *i2c_client_s)
        bt832_hexdump(i2c_client_s,buf);
 
        if(buf[0x40] != 0x31) {
-               printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
+               v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
                kfree(buf);
                return 0;
        }
 
-       printk("Write 0 tp VPSTATUS\n");
+       v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
        buf[0]=BT832_VP_STATUS; // Reg.52
        buf[1]= 0x00;
        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+               v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
 
        bt832_hexdump(i2c_client_s,buf);
 
 
        // Leave low power mode:
-       printk("Bt832: leave low power mode.\n");
+       v4l_err(i2c_client_s,"leave low power mode.\n");
        buf[0]=BT832_CAM_SETUP0; //0x39 57
        buf[1]=0x08;
        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+               v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
 
        bt832_hexdump(i2c_client_s,buf);
 
-       printk("Write 0 tp VPSTATUS\n");
+       v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
        buf[0]=BT832_VP_STATUS; // Reg.52
        buf[1]= 0x00;
        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+               v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
 
        bt832_hexdump(i2c_client_s,buf);
 
 
        // Enable Output
-       printk("Enable Output\n");
+       v4l_info(i2c_client_s,"Enable Output\n");
        buf[0]=BT832_VP_CONTROL1; // Reg.40
        buf[1]= 0x27 & (~0x01); // Default | !skip
        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+               v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
 
        bt832_hexdump(i2c_client_s,buf);
 
 
        // for testing (even works when no camera attached)
-       printk("bt832: *** Generate NTSC M Bars *****\n");
+       v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
        buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
        buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+               v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
 
-       printk("Bt832: Camera Present: %s\n",
+       v4l_info(i2c_client_s,"Camera Present: %s\n",
                (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
 
        bt832_hexdump(i2c_client_s,buf);
@@ -159,13 +164,9 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        struct bt832 *t;
 
-       printk("bt832_attach\n");
-
        client_template.adapter = adap;
        client_template.addr    = addr;
 
-       printk("bt832: chip found @ 0x%x\n", addr<<1);
-
        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
                return -ENOMEM;
        memset(t,0,sizeof(*t));
@@ -173,6 +174,9 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
        i2c_set_clientdata(&t->client, t);
        i2c_attach_client(&t->client);
 
+       v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
+
+
        if(! bt832_init(&t->client)) {
                bt832_detach(&t->client);
                return -1;
@@ -183,13 +187,8 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
 
 static int bt832_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, bt832_attach);
-#else
-       if (adap->id == I2C_HW_B_BT848)
-               return i2c_probe(adap, &addr_data, bt832_attach);
-#endif
        return 0;
 }
 
@@ -197,7 +196,7 @@ static int bt832_detach(struct i2c_client *client)
 {
        struct bt832 *t = i2c_get_clientdata(client);
 
-       printk("bt832: detach.\n");
+       v4l_info(&t->client,"dettach\n");
        i2c_detach_client(client);
        kfree(t);
        return 0;
@@ -208,7 +207,8 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct bt832 *t = i2c_get_clientdata(client);
 
-       printk("bt832: command %x\n",cmd);
+       if (debug>1)
+               v4l_i2c_print_ioctl(&t->client,cmd);
 
        switch (cmd) {
                case BT832_HEXDUMP: {
@@ -219,7 +219,7 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
                }
                break;
                case BT832_REATTACH:
-                       printk("bt832: re-attach\n");
+                       v4l_info(&t->client,"re-attach\n");
                        i2c_del_driver(&driver);
                        i2c_add_driver(&driver);
                break;
@@ -231,9 +231,9 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static struct i2c_driver driver = {
        .driver = {
-               .name   = "i2c bt832 driver",
+               .name   = "bt832",
        },
-       .id             = -1, /* FIXME */
+       .id             = 0, /* FIXME */
        .attach_adapter = bt832_probe,
        .detach_client  = bt832_detach,
        .command        = bt832_command,
index 012be639aa1861577dc2a5a4d98d6bbdab839068..1621ab133d232aa87b633039959c5def48071f10 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/io.h>
 
 #include "bttvp.h"
+#include <media/v4l2-common.h>
 
 /* fwd decl */
 static void boot_msp34xx(struct bttv *btv, int pin);
@@ -292,6 +293,9 @@ static struct CARD {
        /* likely broken, vendor id doesn't match the other magic views ...
         * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
 
+       /* Duplicate PCI ID, reconfigure for this board during the eeprom read.
+       * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB,  "Hauppauge ImpactVCB" }, */
+
        /* DVB cards (using pci function .1 for mpeg data xfer) */
        { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
        { 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
@@ -2136,7 +2140,6 @@ struct tvcard bttv_tvcards[] = {
                .has_remote     = 1,
                .gpiomask       = 0x1b,
                .no_gpioirq     = 1,
-               .any_irq                = 1,
        },
        [BTTV_BOARD_PV143] = {
                /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
@@ -2817,6 +2820,22 @@ struct tvcard bttv_tvcards[] = {
                .tuner_addr     = ADDR_UNSET,
                .has_radio      = 1,
        },
+       /* ---- card 0x8f ---------------------------------- */
+       [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
+               .name           = "Hauppauge ImpactVCB (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .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_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3037,26 +3056,33 @@ static void miro_pinnacle_gpio(struct bttv *btv)
                switch (id) {
                case 1:
                        info = "PAL / mono";
+                       btv->tda9887_conf = TDA9887_INTERCARRIER;
                        break;
                case 2:
                        info = "PAL+SECAM / stereo";
                        btv->has_radio = 1;
+                       btv->tda9887_conf = TDA9887_QSS;
                        break;
                case 3:
                        info = "NTSC / stereo";
                        btv->has_radio = 1;
+                       btv->tda9887_conf = TDA9887_QSS;
                        break;
                case 4:
                        info = "PAL+SECAM / mono";
+                       btv->tda9887_conf = TDA9887_QSS;
                        break;
                case 5:
                        info = "NTSC / mono";
+                       btv->tda9887_conf = TDA9887_INTERCARRIER;
                        break;
                case 6:
                        info = "NTSC / stereo";
+                       btv->tda9887_conf = TDA9887_INTERCARRIER;
                        break;
                case 7:
                        info = "PAL / stereo";
+                       btv->tda9887_conf = TDA9887_INTERCARRIER;
                        break;
                default:
                        info = "oops: unknown card";
@@ -3067,8 +3093,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
                printk(KERN_INFO
                       "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
                       btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
-               btv->tuner_type  = 33;
-               btv->pinnacle_id = id;
+               btv->tuner_type = TUNER_MT2032;
        }
 }
 
@@ -3370,9 +3395,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
                bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
        }
 
-       if (btv->pinnacle_id != UNSET) {
-               bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
-                                                       &btv->pinnacle_id);
+       if (btv->tda9887_conf) {
+               bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
+                                                       &btv->tda9887_conf);
        }
 
        btv->svhs = bttv_tvcards[btv->c.type].svhs;
@@ -3387,8 +3412,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
                btv->has_remote=1;
        if (!bttv_tvcards[btv->c.type].no_gpioirq)
                btv->gpioirq=1;
-       if (bttv_tvcards[btv->c.type].any_irq)
-               btv->any_irq = 1;
        if (bttv_tvcards[btv->c.type].audio_hook)
                btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
 
@@ -3424,7 +3447,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
 
        /* tuner modules */
        tda9887 = 0;
-       if (btv->pinnacle_id != UNSET)
+       if (btv->tda9887_conf)
                tda9887 = 1;
        if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
            bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
@@ -3471,6 +3494,21 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
        tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data);
        btv->tuner_type = tv.tuner_type;
        btv->has_radio  = tv.has_radio;
+
+       printk("bttv%d: Hauppauge eeprom indicates model#%d\n",
+               btv->c.nr, tv.model);
+
+       /*
+        * Some of the 878 boards have duplicate PCI IDs. Switch the board
+        * type based on model #.
+        */
+       if(tv.model == 64900) {
+               printk("bttv%d: Switching board type from %s to %s\n",
+                       btv->c.nr,
+                       bttv_tvcards[btv->c.type].name,
+                       bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
+               btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB;
+       }
 }
 
 static int terratec_active_radio_upgrade(struct bttv *btv)
index 1ddf9ba613ef96c3e8b142dd41d322c02391cb3c..0e697034678806bd3b2a89b5c18bb1e267e211cd 100644 (file)
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/kdev_t.h>
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+
 #include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
-#include "bttvp.h"
-
 #include "rds.h"
 
 
@@ -210,6 +211,9 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x20,
                .vbipack        = 255,
                .sram           = 0,
+               /* ITU-R frame line number of the first VBI line
+                  we can capture, of the first and second field. */
+               .vbistart       = { 7,320 },
        },{
                .v4l2_id        = V4L2_STD_NTSC_M,
                .name           = "NTSC",
@@ -226,6 +230,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x1a,
                .vbipack        = 144,
                .sram           = 1,
+               .vbistart       = { 10, 273 },
        },{
                .v4l2_id        = V4L2_STD_SECAM,
                .name           = "SECAM",
@@ -242,6 +247,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x20,
                .vbipack        = 255,
                .sram           = 0, /* like PAL, correct? */
+               .vbistart       = { 7, 320 },
        },{
                .v4l2_id        = V4L2_STD_PAL_Nc,
                .name           = "PAL-Nc",
@@ -258,6 +264,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x1a,
                .vbipack        = 144,
                .sram           = -1,
+               .vbistart       = { 7, 320 },
        },{
                .v4l2_id        = V4L2_STD_PAL_M,
                .name           = "PAL-M",
@@ -274,6 +281,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x1a,
                .vbipack        = 144,
                .sram           = -1,
+               .vbistart       = { 10, 273 },
        },{
                .v4l2_id        = V4L2_STD_PAL_N,
                .name           = "PAL-N",
@@ -290,6 +298,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x20,
                .vbipack        = 144,
                .sram           = -1,
+               .vbistart       = { 7, 320},
        },{
                .v4l2_id        = V4L2_STD_NTSC_M_JP,
                .name           = "NTSC-JP",
@@ -306,6 +315,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x16,
                .vbipack        = 144,
                .sram           = -1,
+               .vbistart       = {10, 273},
        },{
                /* that one hopefully works with the strange timing
                 * which video recorders produce when playing a NTSC
@@ -326,6 +336,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vbipack        = 255,
                .vtotal         = 524,
                .sram           = -1,
+               .vbistart       = { 10, 273 },
        }
 };
 static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@@ -1510,14 +1521,6 @@ static struct videobuf_queue_ops bttv_video_qops = {
        .buf_release  = buffer_release,
 };
 
-static const char *v4l1_ioctls[] = {
-       "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
-       "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
-       "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
-       "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
-       "SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
 static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
 {
        switch (cmd) {
@@ -2206,22 +2209,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
        unsigned long flags;
        int retval = 0;
 
-       if (bttv_debug > 1) {
-               switch (_IOC_TYPE(cmd)) {
-               case 'v':
-                       printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n",
-                              btv->c.nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-                              v4l1_ioctls[_IOC_NR(cmd)] : "???");
-                       break;
-               case 'V':
-                       printk("bttv%d: ioctl 0x%x (v4l2, %s)\n",
-                              btv->c.nr, cmd,  v4l2_ioctl_names[_IOC_NR(cmd)]);
-                       break;
-               default:
-                       printk("bttv%d: ioctl 0x%x (???)\n",
-                              btv->c.nr, cmd);
-               }
-       }
+       if (bttv_debug > 1)
+               v4l_print_ioctl(btv->c.name, cmd);
+
        if (btv->errors)
                bttv_reinit_bt848(btv);
 
@@ -2570,10 +2560,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                fmt->count[0]         = fmt2.fmt.vbi.count[0];
                fmt->start[1]         = fmt2.fmt.vbi.start[1];
                fmt->count[1]         = fmt2.fmt.vbi.count[1];
-               if (fmt2.fmt.vbi.flags & VBI_UNSYNC)
-                       fmt->flags   |= V4L2_VBI_UNSYNC;
-               if (fmt2.fmt.vbi.flags & VBI_INTERLACED)
-                       fmt->flags   |= V4L2_VBI_INTERLACED;
+               if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
+                       fmt->flags   |= VBI_UNSYNC;
+               if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
+                       fmt->flags   |= VBI_INTERLACED;
                return 0;
        }
        case VIDIOCSVBIFMT:
@@ -3120,6 +3110,7 @@ static struct file_operations bttv_fops =
        .open     = bttv_open,
        .release  = bttv_release,
        .ioctl    = bttv_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek   = no_llseek,
        .read     = bttv_read,
        .mmap     = bttv_mmap,
@@ -3229,6 +3220,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOCSFREQ:
        case VIDIOCGAUDIO:
        case VIDIOCSAUDIO:
+       case VIDIOC_LOG_STATUS:
                return bttv_common_ioctls(btv,cmd,arg);
 
        default:
@@ -3701,8 +3693,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
 
        btv=(struct bttv *)dev_id;
 
-       if (btv->any_irq)
-               handled = bttv_any_irq(&btv->c);
+       if (btv->custom_irq)
+               handled = btv->custom_irq(btv);
 
        count=0;
        while (1) {
@@ -3738,9 +3730,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                if (astat&BT848_INT_VSYNC)
                        btv->field_count++;
 
-               if (astat & BT848_INT_GPINT) {
+               if ((astat & BT848_INT_GPINT) && btv->remote) {
                        wake_up(&btv->gpioq);
-                       bttv_gpio_irq(&btv->c);
+                       bttv_input_irq(btv);
                }
 
                if (astat & BT848_INT_I2CDONE) {
@@ -3946,7 +3938,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 
        btv->i2c_rc = -1;
        btv->tuner_type  = UNSET;
-       btv->pinnacle_id = UNSET;
        btv->new_input   = UNSET;
        btv->has_radio=radio[btv->c.nr];
 
@@ -4065,11 +4056,11 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        }
 
        /* add subdevices */
-       if (btv->has_remote)
-               bttv_sub_add_device(&btv->c, "remote");
        if (bttv_tvcards[btv->c.type].has_dvb)
                bttv_sub_add_device(&btv->c, "dvb");
 
+       bttv_input_init(btv);
+
        /* everything is fine */
        bttv_num++;
        return 0;
@@ -4104,6 +4095,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
        /* tell gpio modules we are leaving ... */
        btv->shutdown=1;
        wake_up(&btv->gpioq);
+       bttv_input_fini(btv);
        bttv_sub_del_devices(&btv->c);
 
        /* unregister i2c_bus + input */
@@ -4253,7 +4245,7 @@ static int bttv_init_module(void)
        bttv_check_chipset();
 
        bus_register(&bttv_sub_bus_type);
-       return pci_module_init(&bttv_pci_driver);
+       return pci_register_driver(&bttv_pci_driver);
 }
 
 static void bttv_cleanup_module(void)
index 616a5b7e510c5c68c80ea845bf746d135c165dfa..575ce8b8e714d995a92c2f6f0daa53c09e6b2dac 100644 (file)
@@ -113,24 +113,6 @@ void bttv_gpio_irq(struct bttv_core *core)
        }
 }
 
-int bttv_any_irq(struct bttv_core *core)
-{
-       struct bttv_sub_driver *drv;
-       struct bttv_sub_device *dev;
-       struct list_head *item;
-       int handled = 0;
-
-       list_for_each(item,&core->subs) {
-               dev = list_entry(item,struct bttv_sub_device,list);
-               drv = to_bttv_sub_drv(dev->dev.driver);
-               if (drv && drv->any_irq) {
-                       if (drv->any_irq(dev))
-                               handled = 1;
-               }
-       }
-       return handled;
-}
-
 /* ----------------------------------------------------------------------- */
 /* external: sub-driver register/unregister                                */
 
index d6418c023d39070e0c2a2bb47913e1a6518c73bc..748d630c7fe49b06c16635b992edbfba6cda7c3c 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <asm/io.h>
 
 #include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <linux/jiffies.h>
+#include <asm/io.h>
 
 static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
 static struct i2c_adapter bttv_i2c_adap_sw_template;
@@ -105,10 +106,8 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
 
 static struct i2c_adapter bttv_i2c_adap_sw_template = {
        .owner             = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
        .class             = I2C_CLASS_TV_ANALOG,
-#endif
-       .name              = "bt848",
+       .name              = "bttv",
        .id                = I2C_HW_B_BT848,
        .client_register   = attach_inform,
 };
@@ -275,10 +274,8 @@ static struct i2c_algorithm bttv_algo = {
 };
 
 static struct i2c_adapter bttv_i2c_adap_hw_template = {
-       .owner         = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
+       .owner             = THIS_MODULE,
        .class         = I2C_CLASS_TV_ANALOG,
-#endif
        .name          = "bt878",
        .id            = I2C_HW_B_BT848 /* FIXME */,
        .algo          = &bttv_algo,
@@ -441,12 +438,10 @@ int __devinit init_bttv_i2c(struct bttv *btv)
        i2c_set_adapdata(&btv->c.i2c_adap, btv);
        btv->i2c_client.adapter = &btv->c.i2c_adap;
 
-#ifdef I2C_CLASS_TV_ANALOG
        if (bttv_tvcards[btv->c.type].no_video)
                btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
        if (bttv_tvcards[btv->c.type].has_dvb)
                btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
-#endif
 
        if (btv->use_i2c_hw) {
                btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
similarity index 73%
rename from drivers/media/video/ir-kbd-gpio.c
rename to drivers/media/video/bttv-input.c
index de1385e5d05ecce6871247c9cffe648a7a1bf0e3..12197f1b27578a7957dac30f78613f4f1b81ae55 100644 (file)
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
-#include <linux/pci.h>
-
-#include <media/ir-common.h>
 
 #include "bttv.h"
+#include "bttvp.h"
 
 /* ---------------------------------------------------------------------- */
 
@@ -156,9 +154,6 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
 
 /* ---------------------------------------------------------------------- */
 
-/* Ricardo Cerqueira <v4l@cerqueira.org> */
-/* Weird matching, since the remote has "uncommon" keys */
-
 static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
 
        [ 30 ] = KEY_POWER,       // power
@@ -279,34 +274,6 @@ static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
        [0x36] = KEY_PC
 };
 
-struct IR {
-       struct bttv_sub_device  *sub;
-       struct input_dev        *input;
-       struct ir_input_state   ir;
-       char                    name[32];
-       char                    phys[32];
-
-       /* Usual gpio signalling */
-
-       u32                     mask_keycode;
-       u32                     mask_keydown;
-       u32                     mask_keyup;
-       u32                     polling;
-       u32                     last_gpio;
-       struct work_struct      work;
-       struct timer_list       timer;
-
-       /* RC5 gpio */
-       u32 rc5_gpio;
-       struct timer_list timer_end;    /* timer_end for code completion */
-       struct timer_list timer_keyup;  /* timer_end for key release */
-       u32 last_rc5;                   /* last good rc5 code */
-       u32 last_bit;                   /* last raw bit seen */
-       u32 code;                       /* raw code under construction */
-       struct timeval base_time;       /* time of last seen code */
-       int active;                     /* building raw code */
-};
-
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
 static int repeat_delay = 500;
@@ -314,31 +281,17 @@ module_param(repeat_delay, int, 0644);
 static int repeat_period = 33;
 module_param(repeat_period, int, 0644);
 
-#define DEVNAME "ir-kbd-gpio"
-#define dprintk(fmt, arg...)   if (debug) \
-       printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
-
-static void ir_irq(struct bttv_sub_device *sub);
-static int ir_probe(struct device *dev);
-static int ir_remove(struct device *dev);
-
-static struct bttv_sub_driver driver = {
-       .drv = {
-               .name   = DEVNAME,
-               .probe  = ir_probe,
-               .remove = ir_remove,
-       },
-       .gpio_irq       = ir_irq,
-};
+#define DEVNAME "bttv-input"
 
 /* ---------------------------------------------------------------------- */
 
-static void ir_handle_key(struct IR *ir)
+static void ir_handle_key(struct bttv *btv)
 {
+       struct bttv_ir *ir = btv->remote;
        u32 gpio,data;
 
        /* read gpio value */
-       gpio = bttv_gpio_read(ir->sub->core);
+       gpio = bttv_gpio_read(&btv->c);
        if (ir->polling) {
                if (ir->last_gpio == gpio)
                        return;
@@ -347,56 +300,36 @@ static void ir_handle_key(struct IR *ir)
 
        /* extract data */
        data = ir_extract_bits(gpio, ir->mask_keycode);
-       dprintk(DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
+       dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
                gpio, data,
                ir->polling               ? "poll"  : "irq",
                (gpio & ir->mask_keydown) ? " down" : "",
                (gpio & ir->mask_keyup)   ? " up"   : "");
 
-       if (ir->mask_keydown) {
-               /* bit set on keydown */
-               if (gpio & ir->mask_keydown) {
-                       ir_input_keydown(ir->input, &ir->ir, data, data);
-               } else {
-                       ir_input_nokey(ir->input, &ir->ir);
-               }
-
-       } else if (ir->mask_keyup) {
-               /* bit cleared on keydown */
-               if (0 == (gpio & ir->mask_keyup)) {
-                       ir_input_keydown(ir->input, &ir->ir, data, data);
-               } else {
-                       ir_input_nokey(ir->input, &ir->ir);
-               }
-
+       if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+           (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+               ir_input_keydown(ir->dev,&ir->ir,data,data);
        } else {
-               /* can't disturgissh keydown/up :-/ */
-               ir_input_keydown(ir->input, &ir->ir, data, data);
-               ir_input_nokey(ir->input, &ir->ir);
+               ir_input_nokey(ir->dev,&ir->ir);
        }
-}
-
-static void ir_irq(struct bttv_sub_device *sub)
-{
-       struct IR *ir = dev_get_drvdata(&sub->dev);
 
-       if (!ir->polling)
-               ir_handle_key(ir);
 }
 
-static void ir_timer(unsigned long data)
+void bttv_input_irq(struct bttv *btv)
 {
-       struct IR *ir = (struct IR*)data;
+       struct bttv_ir *ir = btv->remote;
 
-       schedule_work(&ir->work);
+       if (!ir->polling)
+               ir_handle_key(btv);
 }
 
-static void ir_work(void *data)
+static void bttv_input_timer(unsigned long data)
 {
-       struct IR *ir = data;
+       struct bttv *btv = (struct bttv*)data;
+       struct bttv_ir *ir = btv->remote;
        unsigned long timeout;
 
-       ir_handle_key(ir);
+       ir_handle_key(btv);
        timeout = jiffies + (ir->polling * HZ / 1000);
        mod_timer(&ir->timer, timeout);
 }
@@ -435,26 +368,26 @@ static u32 rc5_decode(unsigned int code)
                        rc5 |= 1;
                        break;
                case 3:
-                       dprintk("bad code: %x\n", org_code);
+                       dprintk(KERN_WARNING "bad code: %x\n", org_code);
                        return 0;
                }
        }
-       dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+       dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
                "instr=%x\n", rc5, org_code, RC5_START(rc5),
                RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
        return rc5;
 }
 
-static int ir_rc5_irq(struct bttv_sub_device *sub)
+static int bttv_rc5_irq(struct bttv *btv)
 {
-       struct IR *ir = dev_get_drvdata(&sub->dev);
+       struct bttv_ir *ir = btv->remote;
        struct timeval tv;
        u32 gpio;
        u32 gap;
        unsigned long current_jiffies, timeout;
 
        /* read gpio port */
-       gpio = bttv_gpio_read(ir->sub->core);
+       gpio = bttv_gpio_read(&btv->c);
 
        /* remote IRQ? */
        if (!(gpio & 0x20))
@@ -493,14 +426,15 @@ static int ir_rc5_irq(struct bttv_sub_device *sub)
        }
 
        /* toggle GPIO pin 4 to reset the irq */
-       bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
-       bttv_gpio_write(ir->sub->core, gpio | (1 << 4));
+       bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+       bttv_gpio_write(&btv->c, gpio | (1 << 4));
        return 1;
 }
 
-static void ir_rc5_timer_end(unsigned long data)
+
+static void bttv_rc5_timer_end(unsigned long data)
 {
-       struct IR *ir = (struct IR *)data;
+       struct bttv_ir *ir = (struct bttv_ir *)data;
        struct timeval tv;
        unsigned long current_jiffies, timeout;
        u32 gap;
@@ -519,20 +453,20 @@ static void ir_rc5_timer_end(unsigned long data)
 
        /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
        if (gap < 28000) {
-               dprintk("spurious timer_end\n");
+               dprintk(KERN_WARNING "spurious timer_end\n");
                return;
        }
 
        ir->active = 0;
        if (ir->last_bit < 20) {
                /* ignore spurious codes (caused by light/other remotes) */
-               dprintk("short code: %x\n", ir->code);
+               dprintk(KERN_WARNING "short code: %x\n", ir->code);
        } else {
                u32 rc5 = rc5_decode(ir->code);
 
                /* two start bits? */
                if (RC5_START(rc5) != 3) {
-                       dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5));
+                       dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
 
                        /* right address? */
                } else if (RC5_ADDR(rc5) == 0x0) {
@@ -542,10 +476,10 @@ static void ir_rc5_timer_end(unsigned long data)
                        /* Good code, decide if repeat/repress */
                        if (toggle != RC5_TOGGLE(ir->last_rc5) ||
                            instr != RC5_INSTR(ir->last_rc5)) {
-                               dprintk("instruction %x, toggle %x\n", instr,
+                               dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
                                        toggle);
-                               ir_input_nokey(ir->input, &ir->ir);
-                               ir_input_keydown(ir->input, &ir->ir, instr,
+                               ir_input_nokey(ir->dev, &ir->ir);
+                               ir_input_keydown(ir->dev, &ir->ir, instr,
                                                 instr);
                        }
 
@@ -560,34 +494,37 @@ static void ir_rc5_timer_end(unsigned long data)
        }
 }
 
-static void ir_rc5_timer_keyup(unsigned long data)
+static void bttv_rc5_timer_keyup(unsigned long data)
 {
-       struct IR *ir = (struct IR *)data;
+       struct bttv_ir *ir = (struct bttv_ir *)data;
 
-       dprintk("key released\n");
-       ir_input_nokey(ir->input, &ir->ir);
+       dprintk(KERN_DEBUG "key released\n");
+       ir_input_nokey(ir->dev, &ir->ir);
 }
 
 /* ---------------------------------------------------------------------- */
 
-static int ir_probe(struct device *dev)
+int bttv_input_init(struct bttv *btv)
 {
-       struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
-       struct IR *ir;
-       struct input_dev *input_dev;
+       struct bttv_ir *ir;
        IR_KEYTAB_TYPE *ir_codes = NULL;
+       struct input_dev *input_dev;
        int ir_type = IR_TYPE_OTHER;
 
-       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+       if (!btv->has_remote)
+               return -ENODEV;
+
+       ir = kzalloc(sizeof(*ir),GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!ir || !input_dev) {
                kfree(ir);
                input_free_device(input_dev);
                return -ENOMEM;
        }
+       memset(ir,0,sizeof(*ir));
 
        /* detect & configure */
-       switch (sub->core->type) {
+       switch (btv->c.type) {
        case BTTV_BOARD_AVERMEDIA:
        case BTTV_BOARD_AVPHONE98:
        case BTTV_BOARD_AVERMEDIA98:
@@ -643,12 +580,12 @@ static int ir_probe(struct device *dev)
                break;
        case BTTV_BOARD_NEBULA_DIGITV:
                ir_codes = ir_codes_nebula;
-               driver.any_irq = ir_rc5_irq;
-               driver.gpio_irq = NULL;
+               btv->custom_irq = bttv_rc5_irq;
                ir->rc5_gpio = 1;
                break;
        }
        if (NULL == ir_codes) {
+               dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
                kfree(ir);
                input_free_device(input_dev);
                return -ENODEV;
@@ -657,109 +594,92 @@ static int ir_probe(struct device *dev)
        if (ir->rc5_gpio) {
                u32 gpio;
                /* enable remote irq */
-               bttv_gpio_inout(sub->core, (1 << 4), 1 << 4);
-               gpio = bttv_gpio_read(sub->core);
-               bttv_gpio_write(sub->core, gpio & ~(1 << 4));
-               bttv_gpio_write(sub->core, gpio | (1 << 4));
+               bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
+               gpio = bttv_gpio_read(&btv->c);
+               bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+               bttv_gpio_write(&btv->c, gpio | (1 << 4));
        } else {
                /* init hardware-specific stuff */
-               bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
+               bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0);
        }
 
        /* init input device */
+       ir->dev = input_dev;
+
        snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
-                sub->core->type);
+                btv->c.type);
        snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
-                pci_name(sub->core->pci));
+                pci_name(btv->c.pci));
 
        ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
        input_dev->name = ir->name;
        input_dev->phys = ir->phys;
        input_dev->id.bustype = BUS_PCI;
        input_dev->id.version = 1;
-       if (sub->core->pci->subsystem_vendor) {
-               input_dev->id.vendor  = sub->core->pci->subsystem_vendor;
-               input_dev->id.product = sub->core->pci->subsystem_device;
+       if (btv->c.pci->subsystem_vendor) {
+               input_dev->id.vendor  = btv->c.pci->subsystem_vendor;
+               input_dev->id.product = btv->c.pci->subsystem_device;
        } else {
-               input_dev->id.vendor  = sub->core->pci->vendor;
-               input_dev->id.product = sub->core->pci->device;
+               input_dev->id.vendor  = btv->c.pci->vendor;
+               input_dev->id.product = btv->c.pci->device;
        }
-       input_dev->cdev.dev = &sub->core->pci->dev;
-
-       ir->input = input_dev;
-       ir->sub = sub;
+       input_dev->cdev.dev = &btv->c.pci->dev;
 
+       btv->remote = ir;
        if (ir->polling) {
-               INIT_WORK(&ir->work, ir_work, ir);
                init_timer(&ir->timer);
-               ir->timer.function = ir_timer;
-               ir->timer.data     = (unsigned long)ir;
-               schedule_work(&ir->work);
+               ir->timer.function = bttv_input_timer;
+               ir->timer.data     = (unsigned long)btv;
+               ir->timer.expires  = jiffies + HZ;
+               add_timer(&ir->timer);
        } else if (ir->rc5_gpio) {
                /* set timer_end for code completion */
                init_timer(&ir->timer_end);
-               ir->timer_end.function = ir_rc5_timer_end;
+               ir->timer_end.function = bttv_rc5_timer_end;
                ir->timer_end.data = (unsigned long)ir;
 
                init_timer(&ir->timer_keyup);
-               ir->timer_keyup.function = ir_rc5_timer_keyup;
+               ir->timer_keyup.function = bttv_rc5_timer_keyup;
                ir->timer_keyup.data = (unsigned long)ir;
        }
 
        /* all done */
-       dev_set_drvdata(dev, ir);
-       input_register_device(ir->input);
+       input_register_device(btv->remote->dev);
+       printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
 
        /* the remote isn't as bouncy as a keyboard */
-       ir->input->rep[REP_DELAY] = repeat_delay;
-       ir->input->rep[REP_PERIOD] = repeat_period;
+       ir->dev->rep[REP_DELAY] = repeat_delay;
+       ir->dev->rep[REP_PERIOD] = repeat_period;
 
        return 0;
 }
 
-static int ir_remove(struct device *dev)
+void bttv_input_fini(struct bttv *btv)
 {
-       struct IR *ir = dev_get_drvdata(dev);
+       if (btv->remote == NULL)
+               return;
 
-       if (ir->polling) {
-               del_timer(&ir->timer);
+       if (btv->remote->polling) {
+               del_timer_sync(&btv->remote->timer);
                flush_scheduled_work();
        }
 
-       if (ir->rc5_gpio) {
+
+       if (btv->remote->rc5_gpio) {
                u32 gpio;
 
-               del_timer(&ir->timer_end);
+               del_timer_sync(&btv->remote->timer_end);
                flush_scheduled_work();
 
-               gpio = bttv_gpio_read(ir->sub->core);
-               bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+               gpio = bttv_gpio_read(&btv->c);
+               bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
        }
 
-       input_unregister_device(ir->input);
-       kfree(ir);
-       return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr, Pavel Machek");
-MODULE_DESCRIPTION("input driver for bt8x8 gpio IR remote controls");
-MODULE_LICENSE("GPL");
-
-static int ir_init(void)
-{
-       return bttv_sub_register(&driver, "remote");
+       input_unregister_device(btv->remote->dev);
+       kfree(btv->remote);
+       btv->remote = NULL;
 }
 
-static void ir_fini(void)
-{
-       bttv_sub_unregister(&driver);
-}
-
-module_init(ir_init);
-module_exit(ir_fini);
-
 
 /*
  * Local variables:
index f4f58c60f152b2d178156c211ef13aad1a493bd5..72afdd64b8821f217d0f713ea6c9e07028053dae 100644 (file)
 #include <asm/io.h>
 #include "bttvp.h"
 
+/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
+   bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
+   HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
+   of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
+#define VBI_OFFSET ((64 + 0) * 2)
+
 #define VBI_DEFLINES 16
 #define VBI_MAXLINES 32
 
@@ -163,40 +169,30 @@ void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
 void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
 {
        const struct bttv_tvnorm *tvnorm;
-       u32 start0,start1;
-       s32 count0,count1,count;
+       s64 count0,count1,count;
 
        tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
        f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
        f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
        f->fmt.vbi.samples_per_line = 2048;
        f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset           = 244;
+       f->fmt.vbi.offset           = VBI_OFFSET;
        f->fmt.vbi.flags            = 0;
-       switch (fh->btv->tvnorm) {
-       case 1: /* NTSC */
-               start0 = 10;
-               start1 = 273;
-               break;
-       case 0: /* PAL */
-       case 2: /* SECAM */
-       default:
-               start0 = 7;
-               start1 = 320;
-       }
 
-       count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0;
-       count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1;
-       count  = max(count0,count1);
-       if (count > VBI_MAXLINES)
-               count = VBI_MAXLINES;
-       if (count < 1)
-               count = 1;
+       /* s64 to prevent overflow. */
+       count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
+               - tvnorm->vbistart[0];
+       count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
+               - tvnorm->vbistart[1];
+       count  = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES);
 
-       f->fmt.vbi.start[0] = start0;
-       f->fmt.vbi.start[1] = start1;
+       f->fmt.vbi.start[0] = tvnorm->vbistart[0];
+       f->fmt.vbi.start[1] = tvnorm->vbistart[1];
        f->fmt.vbi.count[0] = count;
        f->fmt.vbi.count[1] = count;
+
+       f->fmt.vbi.reserved[0] = 0;
+       f->fmt.vbi.reserved[1] = 0;
 }
 
 void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
@@ -209,21 +205,12 @@ void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
        f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
        f->fmt.vbi.samples_per_line = 2048;
        f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset           = 244;
+       f->fmt.vbi.offset           = VBI_OFFSET;
+       f->fmt.vbi.start[0]         = tvnorm->vbistart[0];
+       f->fmt.vbi.start[1]         = tvnorm->vbistart[1];
        f->fmt.vbi.count[0]         = fh->lines;
        f->fmt.vbi.count[1]         = fh->lines;
        f->fmt.vbi.flags            = 0;
-       switch (fh->btv->tvnorm) {
-       case 1: /* NTSC */
-               f->fmt.vbi.start[0] = 10;
-               f->fmt.vbi.start[1] = 273;
-               break;
-       case 0: /* PAL */
-       case 2: /* SECAM */
-       default:
-               f->fmt.vbi.start[0] = 7;
-               f->fmt.vbi.start[1] = 319;
-       }
 }
 
 /* ----------------------------------------------------------------------- */
index 93298f06e0199b4776b010c93bbc8c58008c15d8..9feaa6bab2074906a374e4aecb2493b749a2c598 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <linux/videodev.h>
 #include <linux/i2c.h>
+#include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
 
 /* ---------------------------------------------------------- */
 /* exported by bttv-cards.c                                   */
 #define BTTV_BOARD_OSPREY440               0x8c
 #define BTTV_BOARD_ASOUND_SKYEYE          0x8d
 #define BTTV_BOARD_SABRENT_TVFM           0x8e
+#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB     0x8f
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -210,6 +213,34 @@ struct bttv_core {
 
 struct bttv;
 
+
+struct bttv_ir {
+       struct input_dev        *dev;
+       struct ir_input_state   ir;
+       char                    name[32];
+       char                    phys[32];
+
+       /* Usual gpio signalling */
+
+       u32                     mask_keycode;
+       u32                     mask_keydown;
+       u32                     mask_keyup;
+       u32                     polling;
+       u32                     last_gpio;
+       struct work_struct      work;
+       struct timer_list       timer;
+
+       /* RC5 gpio */
+       u32 rc5_gpio;
+       struct timer_list timer_end;    /* timer_end for code completion */
+       struct timer_list timer_keyup;  /* timer_end for key release */
+       u32 last_rc5;                   /* last good rc5 code */
+       u32 last_bit;                   /* last raw bit seen */
+       u32 code;                       /* raw code under construction */
+       struct timeval base_time;       /* time of last seen code */
+       int active;                     /* building raw code */
+};
+
 struct tvcard
 {
        char *name;
@@ -235,7 +266,6 @@ struct tvcard
        unsigned int has_dvb:1;
        unsigned int has_remote:1;
        unsigned int no_gpioirq:1;
-       unsigned int any_irq:1;
 
        /* other settings */
        unsigned int pll;
@@ -335,7 +365,6 @@ struct bttv_sub_driver {
        struct device_driver   drv;
        char                   wanted[BUS_ID_SIZE];
        void                   (*gpio_irq)(struct bttv_sub_device *sub);
-       int                    (*any_irq)(struct bttv_sub_device *sub);
 };
 #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
 
@@ -363,6 +392,10 @@ extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
                         unsigned char b2, int both);
 extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
 
+extern int bttv_input_init(struct bttv *dev);
+extern void bttv_input_fini(struct bttv *dev);
+extern void bttv_input_irq(struct bttv *dev);
+
 #endif /* _BTTV_H_ */
 /*
  * Local variables:
index 1e6a5632c3c71a48ca479d69efdc4514376608d0..dd00c20ab95efb54c605117a20b6ddc7784f87d5 100644 (file)
@@ -73,6 +73,8 @@
 
 #define UNSET (-1U)
 
+#define clamp(x, low, high) min (max (low, x), high)
+
 /* ---------------------------------------------------------- */
 
 struct bttv_tvnorm {
@@ -88,6 +90,9 @@ struct bttv_tvnorm {
        u8    vbipack;
        u16   vtotal;
        int   sram;
+       /* ITU-R frame line number of the first VBI line we can
+          capture, of the first and second field. */
+       u16   vbistart[2];
 };
 extern const struct bttv_tvnorm bttv_tvnorms[];
 
@@ -209,7 +214,6 @@ extern struct bus_type bttv_sub_bus_type;
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
 void bttv_gpio_irq(struct bttv_core *core);
-int bttv_any_irq(struct bttv_core *core);
 
 
 /* ---------------------------------------------------------- */
@@ -270,12 +274,13 @@ struct bttv {
        /* card configuration info */
        unsigned int cardid;   /* pci subsystem id (bt878 based ones) */
        unsigned int tuner_type;  /* tuner chip type */
-       unsigned int pinnacle_id;
+       unsigned int tda9887_conf;
        unsigned int svhs;
        struct bttv_pll_info pll;
        int triton1;
        int gpioirq;
-       int any_irq;
+       int (*custom_irq)(struct bttv *btv);
+
        int use_i2c_hw;
 
        /* old gpio interface */
@@ -300,7 +305,7 @@ struct bttv {
 
        /* infrared remote */
        int has_remote;
-       struct bttv_input *remote;
+       struct bttv_ir *remote;
 
        /* locking */
        spinlock_t s_lock;
index 0065d0c240d1465f5d93251430a1a8aa07f0e939..6bad93ef969fd402d6131a1a9c0d0a594c769d3b 100644 (file)
@@ -875,6 +875,7 @@ static struct file_operations qcam_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = qcam_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .read           = qcam_read,
        .llseek         = no_llseek,
 };
index 75442ec49f352b0a4e9c2cbf245abc3a930b71f7..9976db4f6da8f77d6f41961bc6115a23c82a25f2 100644 (file)
@@ -687,6 +687,7 @@ static struct file_operations qcam_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = qcam_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .read           = qcam_read,
        .llseek         = no_llseek,
 };
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
new file mode 100644 (file)
index 0000000..6194b01
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ *     Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
+ *
+ * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs
+ * Copyright (C) 2003       Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2005       Philippe De Muyter (phdm@macqel.be)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * ioctls.
+ */
+
+#include <linux/config.h>
+#include <linux/compat.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+
+#ifdef CONFIG_COMPAT
+struct video_tuner32 {
+       compat_int_t tuner;
+       char name[32];
+       compat_ulong_t rangelow, rangehigh;
+       u32 flags;      /* It is really u32 in videodev.h */
+       u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
+{
+       if(get_user(kp->tuner, &up->tuner))
+               return -EFAULT;
+       __copy_from_user(kp->name, up->name, 32);
+       __get_user(kp->rangelow, &up->rangelow);
+       __get_user(kp->rangehigh, &up->rangehigh);
+       __get_user(kp->flags, &up->flags);
+       __get_user(kp->mode, &up->mode);
+       __get_user(kp->signal, &up->signal);
+       return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
+{
+       if(put_user(kp->tuner, &up->tuner))
+               return -EFAULT;
+       __copy_to_user(up->name, kp->name, 32);
+       __put_user(kp->rangelow, &up->rangelow);
+       __put_user(kp->rangehigh, &up->rangehigh);
+       __put_user(kp->flags, &up->flags);
+       __put_user(kp->mode, &up->mode);
+       __put_user(kp->signal, &up->signal);
+       return 0;
+}
+
+struct video_buffer32 {
+       compat_caddr_t base;
+       compat_int_t height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
+{
+       u32 tmp;
+
+       if (get_user(tmp, &up->base))
+               return -EFAULT;
+
+       /* This is actually a physical address stored
+        * as a void pointer.
+        */
+       kp->base = (void *)(unsigned long) tmp;
+
+       __get_user(kp->height, &up->height);
+       __get_user(kp->width, &up->width);
+       __get_user(kp->depth, &up->depth);
+       __get_user(kp->bytesperline, &up->bytesperline);
+       return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
+{
+       u32 tmp = (u32)((unsigned long)kp->base);
+
+       if(put_user(tmp, &up->base))
+               return -EFAULT;
+       __put_user(kp->height, &up->height);
+       __put_user(kp->width, &up->width);
+       __put_user(kp->depth, &up->depth);
+       __put_user(kp->bytesperline, &up->bytesperline);
+       return 0;
+}
+
+struct video_clip32 {
+       s32 x, y, width, height;        /* Its really s32 in videodev.h */
+       compat_caddr_t next;
+};
+
+struct video_window32 {
+       u32 x, y, width, height, chromakey, flags;
+       compat_caddr_t clips;
+       compat_int_t clipcount;
+};
+
+static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret = -ENOIOCTLCMD;
+
+       if (file->f_op->unlocked_ioctl)
+               ret = file->f_op->unlocked_ioctl(file, cmd, arg);
+       else if (file->f_op->ioctl) {
+               lock_kernel();
+               ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
+               unlock_kernel();
+       }
+
+       return ret;
+}
+
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
+{
+       if(put_user(kp->x, &up->x))
+               return -EFAULT;
+       __put_user(kp->y, &up->y);
+       __put_user(kp->width, &up->width);
+       __put_user(kp->height, &up->height);
+       __put_user(kp->chromakey, &up->chromakey);
+       __put_user(kp->flags, &up->flags);
+       __put_user(kp->clipcount, &up->clipcount);
+       return 0;
+}
+
+struct v4l2_clip32
+{
+       struct v4l2_rect        c;
+       compat_caddr_t          next;
+};
+
+struct v4l2_window32
+{
+       struct v4l2_rect        w;
+       enum v4l2_field         field;
+       __u32                   chromakey;
+       compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
+       __u32                   clipcount;
+       compat_caddr_t          bitmap;
+};
+
+static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+{
+       if (copy_from_user(&kp->w, &up->w, sizeof(up->w)))
+               return -EFAULT;
+       __get_user(kp->field, &up->field);
+       __get_user(kp->chromakey, &up->chromakey);
+       __get_user(kp->clipcount, &up->clipcount);
+       if (kp->clipcount > 2048)
+               return -EINVAL;
+       if (kp->clipcount) {
+               struct v4l2_clip32 *uclips = compat_ptr(up->clips);
+               struct v4l2_clip *kclips;
+               int n = kp->clipcount;
+
+               kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
+               kp->clips = kclips;
+               while (--n >= 0) {
+                       copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c));
+                       kclips->next = n ? kclips + 1 : 0;
+                       uclips += 1;
+                       kclips += 1;
+               }
+       } else
+               kp->clips = 0;
+       return 0;
+}
+
+static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+{
+       if (copy_to_user(&up->w, &kp->w, sizeof(up->w)))
+               return -EFAULT;
+       __put_user(kp->field, &up->field);
+       __put_user(kp->chromakey, &up->chromakey);
+       __put_user(kp->clipcount, &up->clipcount);
+       return 0;
+}
+
+static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+{
+       return copy_from_user(kp, up, sizeof(struct v4l2_pix_format));
+}
+
+static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+{
+       return copy_to_user(up, kp, sizeof(struct v4l2_pix_format));
+}
+
+static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+{
+       return copy_from_user(kp, up, sizeof(struct v4l2_vbi_format));
+}
+
+static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+{
+       return copy_to_user(up, kp, sizeof(struct v4l2_vbi_format));
+}
+
+struct v4l2_format32
+{
+       enum v4l2_buf_type type;
+       union
+       {
+               struct v4l2_pix_format  pix;  // V4L2_BUF_TYPE_VIDEO_CAPTURE
+               struct v4l2_window32    win;  // V4L2_BUF_TYPE_VIDEO_OVERLAY
+               struct v4l2_vbi_format  vbi;  // V4L2_BUF_TYPE_VBI_CAPTURE
+               __u8    raw_data[200];        // user-defined
+       } fmt;
+};
+
+static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+       if(get_user(kp->type, &up->type))
+               return -EFAULT;
+       switch (kp->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+       default:
+               printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n",
+                                                               kp->type);
+               return -ENXIO;
+       }
+}
+
+static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+       if(put_user(kp->type, &up->type))
+               return -EFAULT;
+       switch (kp->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+       default:
+               return -ENXIO;
+       }
+}
+
+struct v4l2_standard32
+{
+       __u32                index;
+       __u32                id[2]; /* __u64 would get the alignment wrong */
+       __u8                 name[24];
+       struct v4l2_fract    frameperiod; /* Frames, not fields */
+       __u32                framelines;
+       __u32                reserved[4];
+};
+
+static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+{
+       /* other fields are not set by the user, nor used by the driver */
+       return get_user(kp->index, &up->index);
+}
+
+static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+{
+       if(put_user(kp->index, &up->index))
+               return -EFAULT;
+       __copy_to_user(up->id, &kp->id, sizeof(__u64));
+       __copy_to_user(up->name, kp->name, 24);
+       __put_user(kp->frameperiod, &up->frameperiod);
+       __put_user(kp->framelines, &up->framelines);
+       __copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32));
+       return 0;
+}
+
+struct v4l2_buffer32
+{
+       __u32                   index;
+       enum v4l2_buf_type      type;
+       __u32                   bytesused;
+       __u32                   flags;
+       enum v4l2_field         field;
+       struct compat_timeval   timestamp;
+       struct v4l2_timecode    timecode;
+       __u32                   sequence;
+
+       /* memory location */
+       enum v4l2_memory        memory;
+       union {
+               __u32           offset;
+               compat_long_t   userptr;
+       } m;
+       __u32                   length;
+       __u32                   input;
+       __u32                   reserved;
+};
+
+static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+{
+
+       if (get_user(kp->index, &up->index))
+               return -EFAULT;
+       __get_user(kp->type, &up->type);
+       __get_user(kp->flags, &up->flags);
+       __get_user(kp->memory, &up->memory);
+       __get_user(kp->input, &up->input);
+       switch(kp->memory) {
+       case V4L2_MEMORY_MMAP:
+               break;
+       case V4L2_MEMORY_USERPTR:
+               {
+               unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr);
+
+               __get_user(kp->length, &up->length);
+               __get_user(kp->m.userptr, &tmp);
+               }
+               break;
+       case V4L2_MEMORY_OVERLAY:
+               __get_user(kp->m.offset, &up->m.offset);
+               break;
+       }
+       return 0;
+}
+
+static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+{
+       if (put_user(kp->index, &up->index))
+               return -EFAULT;
+       __put_user(kp->type, &up->type);
+       __put_user(kp->flags, &up->flags);
+       __put_user(kp->memory, &up->memory);
+       __put_user(kp->input, &up->input);
+       switch(kp->memory) {
+       case V4L2_MEMORY_MMAP:
+               __put_user(kp->length, &up->length);
+               __put_user(kp->m.offset, &up->m.offset);
+               break;
+       case V4L2_MEMORY_USERPTR:
+               __put_user(kp->length, &up->length);
+               __put_user(kp->m.userptr, &up->m.userptr);
+               break;
+       case V4L2_MEMORY_OVERLAY:
+               __put_user(kp->m.offset, &up->m.offset);
+               break;
+       }
+       __put_user(kp->bytesused, &up->bytesused);
+       __put_user(kp->field, &up->field);
+       __put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec);
+       __put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec);
+       __copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode));
+       __put_user(kp->sequence, &up->sequence);
+       __put_user(kp->reserved, &up->reserved);
+       return 0;
+}
+
+struct v4l2_framebuffer32
+{
+       __u32                   capability;
+       __u32                   flags;
+       compat_caddr_t          base;
+       struct v4l2_pix_format  fmt;
+};
+
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+{
+       u32 tmp;
+
+       if (get_user(tmp, &up->base))
+               return -EFAULT;
+       kp->base = compat_ptr(tmp);
+       __get_user(kp->capability, &up->capability);
+       __get_user(kp->flags, &up->flags);
+       get_v4l2_pix_format(&kp->fmt, &up->fmt);
+       return 0;
+}
+
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+{
+       u32 tmp = (u32)((unsigned long)kp->base);
+
+       if(put_user(tmp, &up->base))
+               return -EFAULT;
+       __put_user(kp->capability, &up->capability);
+       __put_user(kp->flags, &up->flags);
+       put_v4l2_pix_format(&kp->fmt, &up->fmt);
+       return 0;
+}
+
+struct v4l2_input32    /* identical layout, but different size */
+{
+       __u32        index;             /*  Which input */
+       __u8         name[32];          /*  Label */
+       __u32        type;              /*  Type of input */
+       __u32        audioset;          /*  Associated audios (bitfield) */
+       __u32        tuner;             /*  Associated tuner */
+       __u32        std[2];            /* __u64 would get the padding wrong */
+       __u32        status;
+       __u32        reserved[4];
+};
+
+#define VIDIOCGTUNER32         _IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32         _IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32           _IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32           _IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32          _IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32          _IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32          _IOR('v',14, u32)
+#define VIDIOCSFREQ32          _IOW('v',15, u32)
+
+#define VIDIOC_G_FMT32         _IOWR ('V',  4, struct v4l2_format32)
+#define VIDIOC_S_FMT32         _IOWR ('V',  5, struct v4l2_format32)
+#define VIDIOC_QUERYBUF32      _IOWR ('V',  9, struct v4l2_buffer32)
+#define VIDIOC_G_FBUF32                _IOR  ('V', 10, struct v4l2_framebuffer32)
+#define VIDIOC_S_FBUF32                _IOW  ('V', 11, struct v4l2_framebuffer32)
+/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
+#define VIDIOC_OVERLAY32       _IOWR ('V', 14, compat_int_t)
+#define VIDIOC_QBUF32          _IOWR ('V', 15, struct v4l2_buffer32)
+#define VIDIOC_DQBUF32         _IOWR ('V', 17, struct v4l2_buffer32)
+#define VIDIOC_STREAMON32      _IOW  ('V', 18, compat_int_t)
+#define VIDIOC_STREAMOFF32     _IOW  ('V', 19, compat_int_t)
+#define VIDIOC_ENUMSTD32       _IOWR ('V', 25, struct v4l2_standard32)
+#define VIDIOC_ENUMINPUT32     _IOWR ('V', 26, struct v4l2_input32)
+/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
+#define VIDIOC_S_CTRL32                _IOW  ('V', 28, struct v4l2_control)
+#define VIDIOC_G_INPUT32       _IOR  ('V', 38, compat_int_t)
+#define VIDIOC_S_INPUT32       _IOWR ('V', 39, compat_int_t)
+#define VIDIOC_TRY_FMT32       _IOWR ('V', 64, struct v4l2_format32)
+
+enum {
+       MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
+};
+
+static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct video_window32 __user *up = compat_ptr(arg);
+       struct video_window __user *vw;
+       struct video_clip __user *p;
+       int nclips;
+       u32 n;
+
+       if (get_user(nclips, &up->clipcount))
+               return -EFAULT;
+
+       /* Peculiar interface... */
+       if (nclips < 0)
+               nclips = VIDEO_CLIPMAP_SIZE;
+
+       if (nclips > MaxClips)
+               return -ENOMEM;
+
+       vw = compat_alloc_user_space(sizeof(struct video_window) +
+                                   nclips * sizeof(struct video_clip));
+
+       p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
+
+       if (get_user(n, &up->x) || put_user(n, &vw->x) ||
+           get_user(n, &up->y) || put_user(n, &vw->y) ||
+           get_user(n, &up->width) || put_user(n, &vw->width) ||
+           get_user(n, &up->height) || put_user(n, &vw->height) ||
+           get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
+           get_user(n, &up->flags) || put_user(n, &vw->flags) ||
+           get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
+           get_user(n, &up->clips) || put_user(p, &vw->clips))
+               return -EFAULT;
+
+       if (nclips) {
+               struct video_clip32 __user *u = compat_ptr(n);
+               int i;
+               if (!u)
+                       return -EINVAL;
+               for (i = 0; i < nclips; i++, u++, p++) {
+                       s32 v;
+                       if (get_user(v, &u->x) ||
+                           put_user(v, &p->x) ||
+                           get_user(v, &u->y) ||
+                           put_user(v, &p->y) ||
+                           get_user(v, &u->width) ||
+                           put_user(v, &p->width) ||
+                           get_user(v, &u->height) ||
+                           put_user(v, &p->height) ||
+                           put_user(NULL, &p->next))
+                               return -EFAULT;
+               }
+       }
+
+       return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
+}
+
+static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       union {
+               struct video_tuner vt;
+               struct video_buffer vb;
+               struct video_window vw;
+               struct v4l2_format v2f;
+               struct v4l2_buffer v2b;
+               struct v4l2_framebuffer v2fb;
+               struct v4l2_standard v2s;
+               unsigned long vx;
+       } karg;
+       void __user *up = compat_ptr(arg);
+       int compatible_arg = 1;
+       int err = 0;
+
+       /* First, convert the command. */
+       switch(cmd) {
+       case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+       case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+       case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+       case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+       case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+       case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+       case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+       case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
+       case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
+       case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
+       case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
+       case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
+       case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
+       case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
+       case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
+       case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
+       case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
+       case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
+       case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
+       case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break;
+       case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
+       case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
+       case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
+       };
+
+       switch(cmd) {
+       case VIDIOCSTUNER:
+       case VIDIOCGTUNER:
+               err = get_video_tuner32(&karg.vt, up);
+               compatible_arg = 0;
+
+               break;
+
+       case VIDIOCSFBUF:
+               err = get_video_buffer32(&karg.vb, up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOCSFREQ:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_OVERLAY:
+       case VIDIOC_STREAMON:
+       case VIDIOC_STREAMOFF:
+               err = get_user(karg.vx, (u32 __user *)up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOC_S_FBUF:
+               err = get_v4l2_framebuffer32(&karg.v2fb, up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOC_G_FMT:
+       case VIDIOC_S_FMT:
+       case VIDIOC_TRY_FMT:
+               err = get_v4l2_format32(&karg.v2f, up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOC_QUERYBUF:
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF:
+               err = get_v4l2_buffer32(&karg.v2b, up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOC_ENUMSTD:
+               err = get_v4l2_standard32(&karg.v2s, up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOCGWIN:
+       case VIDIOCGFBUF:
+       case VIDIOCGFREQ:
+       case VIDIOC_G_FBUF:
+       case VIDIOC_G_INPUT:
+               compatible_arg = 0;
+       };
+
+       if(err)
+               goto out;
+
+       if(compatible_arg)
+               err = native_ioctl(file, cmd, (unsigned long)up);
+       else {
+               mm_segment_t old_fs = get_fs();
+
+               set_fs(KERNEL_DS);
+               err = native_ioctl(file, cmd, (unsigned long)&karg);
+               set_fs(old_fs);
+       }
+       if(err == 0) {
+               switch(cmd) {
+               case VIDIOCGTUNER:
+                       err = put_video_tuner32(&karg.vt, up);
+                       break;
+
+               case VIDIOCGWIN:
+                       err = put_video_window32(&karg.vw, up);
+                       break;
+
+               case VIDIOCGFBUF:
+                       err = put_video_buffer32(&karg.vb, up);
+                       break;
+
+               case VIDIOC_G_FBUF:
+                       err = put_v4l2_framebuffer32(&karg.v2fb, up);
+                       break;
+
+               case VIDIOC_G_FMT:
+               case VIDIOC_S_FMT:
+               case VIDIOC_TRY_FMT:
+                       err = put_v4l2_format32(&karg.v2f, up);
+                       break;
+
+               case VIDIOC_QUERYBUF:
+               case VIDIOC_QBUF:
+               case VIDIOC_DQBUF:
+                       err = put_v4l2_buffer32(&karg.v2b, up);
+                       break;
+
+               case VIDIOC_ENUMSTD:
+                       err = put_v4l2_standard32(&karg.v2s, up);
+                       break;
+
+               case VIDIOCGFREQ:
+               case VIDIOC_G_INPUT:
+                       err = put_user(((u32)karg.vx), (u32 __user *)up);
+                       break;
+               };
+       }
+out:
+       return err;
+}
+
+long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret = -ENOIOCTLCMD;
+
+       if (!file->f_op->ioctl)
+               return ret;
+
+       switch (cmd) {
+       case VIDIOCSWIN32:
+               ret = do_set_window(file, cmd, arg);
+               break;
+       case VIDIOCGTUNER32:
+       case VIDIOCSTUNER32:
+       case VIDIOCGWIN32:
+       case VIDIOCGFBUF32:
+       case VIDIOCSFBUF32:
+       case VIDIOCGFREQ32:
+       case VIDIOCSFREQ32:
+       case VIDIOC_QUERYCAP:
+       case VIDIOC_ENUM_FMT:
+       case VIDIOC_G_FMT32:
+       case VIDIOC_S_FMT32:
+       case VIDIOC_REQBUFS:
+       case VIDIOC_QUERYBUF32:
+       case VIDIOC_G_FBUF32:
+       case VIDIOC_S_FBUF32:
+       case VIDIOC_OVERLAY32:
+       case VIDIOC_QBUF32:
+       case VIDIOC_DQBUF32:
+       case VIDIOC_STREAMON32:
+       case VIDIOC_STREAMOFF32:
+       case VIDIOC_G_PARM:
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_ENUMSTD32:
+       case VIDIOC_ENUMINPUT32:
+       case VIDIOC_G_CTRL:
+       case VIDIOC_S_CTRL32:
+       case VIDIOC_QUERYCTRL:
+       case VIDIOC_G_INPUT32:
+       case VIDIOC_S_INPUT32:
+       case VIDIOC_TRY_FMT32:
+               ret = do_video_ioctl(file, cmd, arg);
+               break;
+
+       /* Little v, the video4linux ioctls (conflict?) */
+       case VIDIOCGCAP:
+       case VIDIOCGCHAN:
+       case VIDIOCSCHAN:
+       case VIDIOCGPICT:
+       case VIDIOCSPICT:
+       case VIDIOCCAPTURE:
+       case VIDIOCKEY:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+       case VIDIOCSYNC:
+       case VIDIOCMCAPTURE:
+       case VIDIOCGMBUF:
+       case VIDIOCGUNIT:
+       case VIDIOCGCAPTURE:
+       case VIDIOCSCAPTURE:
+
+       /* BTTV specific... */
+       case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
+       case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
+       case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
+       case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
+       case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
+       case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
+       case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
+       case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
+               ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+               break;
+       }
+       return ret;
+}
+#else
+long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+#endif
+EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
+
+MODULE_LICENSE("GPL");
index b7ec9bf45085ea6e31ba526938654eb24a32f647..9f59541155d9bfbd004d22d2aed584b5173f8677 100644 (file)
@@ -3807,6 +3807,7 @@ static struct file_operations cpia_fops = {
        .read           = cpia_read,
        .mmap           = cpia_mmap,
        .ioctl          = cpia_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 643ead1a87eea504324110193e5b5daf35fce6d2..b421068f7ea30bc3bf778cdd747b1e45284f9fc3 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
 MODULE_AUTHOR("Martin Vaughan");
@@ -39,21 +39,6 @@ module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
 
-#define cs53l32a_dbg(fmt, arg...) \
-       do { \
-               if (debug) \
-                       printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-                              client->driver->driver.name, \
-                              i2c_adapter_id(client->adapter), client->addr , ## arg); \
-       } while (0)
-
-#define cs53l32a_err(fmt, arg...) do { \
-       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define cs53l32a_info(fmt, arg...) do { \
-       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
 static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
 
 
@@ -74,50 +59,59 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg)
 static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
                            void *arg)
 {
-       int *input = arg;
+       struct v4l2_audio *input = arg;
+       struct v4l2_control *ctrl = arg;
 
        switch (cmd) {
-       case AUDC_SET_INPUT:
-               switch (*input) {
-               case AUDIO_TUNER:
-                       cs53l32a_write(client, 0x01, 0x01);
-                       break;
-               case AUDIO_EXTERN:
-                       cs53l32a_write(client, 0x01, 0x21);
-                       break;
-               case AUDIO_MUTE:
-                       cs53l32a_write(client, 0x03, 0xF0);
-                       break;
-               case AUDIO_UNMUTE:
-                       cs53l32a_write(client, 0x03, 0x30);
-                       break;
-               default:
-                       cs53l32a_err("Invalid input %d.\n", *input);
+       case VIDIOC_S_AUDIO:
+               /* There are 2 physical inputs, but the second input can be
+                  placed in two modes, the first mode bypasses the PGA (gain),
+                  the second goes through the PGA. Hence there are three
+                  possible inputs to choose from. */
+               if (input->index > 2) {
+                       v4l_err(client, "Invalid input %d.\n", input->index);
                        return -EINVAL;
                }
+               cs53l32a_write(client, 0x01, 0x01 + (input->index << 4));
+               break;
+
+       case VIDIOC_G_AUDIO:
+               memset(input, 0, sizeof(*input));
+               input->index = (cs53l32a_read(client, 0x01) >> 4) & 3;
+               break;
+
+       case VIDIOC_G_CTRL:
+               if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+                       ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
+                       break;
+               }
+               if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+                       return -EINVAL;
+               ctrl->value = (s8)cs53l32a_read(client, 0x04);
                break;
 
        case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-
-                       if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-                               return -EINVAL;
-                       if (ctrl->value > 12 || ctrl->value < -90)
-                               return -EINVAL;
-                       cs53l32a_write(client, 0x04, (u8) ctrl->value);
-                       cs53l32a_write(client, 0x05, (u8) ctrl->value);
+               if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+                       cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
                        break;
                }
+               if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+                       return -EINVAL;
+               if (ctrl->value > 12 || ctrl->value < -96)
+                       return -EINVAL;
+               cs53l32a_write(client, 0x04, (u8) ctrl->value);
+               cs53l32a_write(client, 0x05, (u8) ctrl->value);
+               break;
 
        case VIDIOC_LOG_STATUS:
                {
                        u8 v = cs53l32a_read(client, 0x01);
                        u8 m = cs53l32a_read(client, 0x03);
+                       s8 vol = cs53l32a_read(client, 0x04);
 
-                       cs53l32a_info("Input: %s%s\n",
-                                     v == 0x21 ? "external line in" : "tuner",
+                       v4l_info(client, "Input:  %d%s\n", (v >> 4) & 3,
                                      (m & 0xC0) ? " (muted)" : "");
+                       v4l_info(client, "Volume: %d dB\n", vol);
                        break;
                }
 
@@ -157,12 +151,12 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
        client->driver = &i2c_driver;
        snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
 
-       cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
 
        for (i = 1; i <= 7; i++) {
                u8 v = cs53l32a_read(client, i);
 
-               cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+               v4l_dbg(1, client, "Read Reg %d %02x\n", i, v);
        }
 
        /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
@@ -180,7 +174,7 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
        for (i = 1; i <= 7; i++) {
                u8 v = cs53l32a_read(client, i);
 
-               cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+               v4l_dbg(1, client, "Read Reg %d %02x\n", i, v);
        }
 
        i2c_attach_client(client);
@@ -190,11 +184,7 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
 
 static int cs53l32a_probe(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-       if (adapter->id == I2C_HW_B_BT848)
-#endif
                return i2c_probe(adapter, &addr_data, cs53l32a_attach);
        return 0;
 }
index 740908f8027d050ad1810d3f497b1a0ff2f3a253..cb9a7981e4081bc9ac284b2ff26c47b6f84fdd23 100644 (file)
 
 #include "cx25840.h"
 
-inline static int set_audclk_freq(struct i2c_client *client,
-                                enum v4l2_audio_clock_freq freq)
+static int set_audclk_freq(struct i2c_client *client, u32 freq)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
 
+       if (freq != 32000 && freq != 44100 && freq != 48000)
+               return -EINVAL;
+
        /* assert soft reset */
        cx25840_and_or(client, 0x810, ~0x1, 0x01);
 
@@ -35,10 +37,9 @@ inline static int set_audclk_freq(struct i2c_client *client,
        /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
        cx25840_write(client, 0x127, 0x50);
 
-       switch (state->audio_input) {
-       case AUDIO_TUNER:
+       if (state->aud_input != CX25840_AUDIO_SERIAL) {
                switch (freq) {
-               case V4L2_AUDCLK_32_KHZ:
+               case 32000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040610);
 
@@ -51,7 +52,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write4(client, 0x90c, 0x7ff70108);
                        break;
 
-               case V4L2_AUDCLK_441_KHZ:
+               case 44100:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040910);
 
@@ -64,7 +65,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write4(client, 0x90c, 0x596d0108);
                        break;
 
-               case V4L2_AUDCLK_48_KHZ:
+               case 48000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040a10);
 
@@ -77,14 +78,9 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write4(client, 0x90c, 0xaa4f0108);
                        break;
                }
-               break;
-
-       case AUDIO_EXTERN_1:
-       case AUDIO_EXTERN_2:
-       case AUDIO_INTERN:
-       case AUDIO_RADIO:
+       } else {
                switch (freq) {
-               case V4L2_AUDCLK_32_KHZ:
+               case 32000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f04081e);
 
@@ -103,7 +99,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write(client, 0x127, 0x54);
                        break;
 
-               case V4L2_AUDCLK_441_KHZ:
+               case 44100:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040918);
 
@@ -119,7 +115,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write4(client, 0x90c, 0x85730108);
                        break;
 
-               case V4L2_AUDCLK_48_KHZ:
+               case 48000:
                        /* VID_PLL and AUX_PLL */
                        cx25840_write4(client, 0x108, 0x0f040a18);
 
@@ -135,7 +131,6 @@ inline static int set_audclk_freq(struct i2c_client *client,
                        cx25840_write4(client, 0x90c, 0x55550108);
                        break;
                }
-               break;
        }
 
        /* deassert soft reset */
@@ -146,51 +141,36 @@ inline static int set_audclk_freq(struct i2c_client *client,
        return 0;
 }
 
-static int set_input(struct i2c_client *client, int audio_input)
+void cx25840_audio_set_path(struct i2c_client *client)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
 
-       cx25840_dbg("set audio input (%d)\n", audio_input);
-
        /* stop microcontroller */
        cx25840_and_or(client, 0x803, ~0x10, 0);
 
        /* Mute everything to prevent the PFFT! */
        cx25840_write(client, 0x8d3, 0x1f);
 
-       switch (audio_input) {
-       case AUDIO_TUNER:
-               /* Set Path1 to Analog Demod Main Channel */
-               cx25840_write4(client, 0x8d0, 0x7038061f);
-
-               /* When the microcontroller detects the
-                * audio format, it will unmute the lines */
-               cx25840_and_or(client, 0x803, ~0x10, 0x10);
-               break;
-
-       case AUDIO_EXTERN_1:
-       case AUDIO_EXTERN_2:
-       case AUDIO_INTERN:
-       case AUDIO_RADIO:
+       if (state->aud_input == CX25840_AUDIO_SERIAL) {
                /* Set Path1 to Serial Audio Input */
                cx25840_write4(client, 0x8d0, 0x12100101);
 
                /* The microcontroller should not be started for the
                 * non-tuner inputs: autodetection is specific for
                 * TV audio. */
-               break;
+       } else {
+               /* Set Path1 to Analog Demod Main Channel */
+               cx25840_write4(client, 0x8d0, 0x7038061f);
 
-       default:
-               cx25840_dbg("Invalid audio input selection %d\n", audio_input);
-               return -EINVAL;
+               /* When the microcontroller detects the
+                * audio format, it will unmute the lines */
+               cx25840_and_or(client, 0x803, ~0x10, 0x10);
        }
 
-       state->audio_input = audio_input;
-
-       return set_audclk_freq(client, state->audclk_freq);
+       set_audclk_freq(client, state->audclk_freq);
 }
 
-inline static int get_volume(struct i2c_client *client)
+static int get_volume(struct i2c_client *client)
 {
        /* Volume runs +18dB to -96dB in 1/2dB steps
         * change to fit the msp3400 -114dB to +12dB range */
@@ -201,7 +181,7 @@ inline static int get_volume(struct i2c_client *client)
        return vol << 9;
 }
 
-inline static void set_volume(struct i2c_client *client, int volume)
+static void set_volume(struct i2c_client *client, int volume)
 {
        /* First convert the volume to msp3400 values (0-127) */
        int vol = volume >> 9;
@@ -218,7 +198,7 @@ inline static void set_volume(struct i2c_client *client, int volume)
        cx25840_write(client, 0x8d4, 228 - (vol * 2));
 }
 
-inline static int get_bass(struct i2c_client *client)
+static int get_bass(struct i2c_client *client)
 {
        /* bass is 49 steps +12dB to -12dB */
 
@@ -228,13 +208,13 @@ inline static int get_bass(struct i2c_client *client)
        return bass;
 }
 
-inline static void set_bass(struct i2c_client *client, int bass)
+static void set_bass(struct i2c_client *client, int bass)
 {
        /* PATH1_EQ_BASS_VOL */
        cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
 }
 
-inline static int get_treble(struct i2c_client *client)
+static int get_treble(struct i2c_client *client)
 {
        /* treble is 49 steps +12dB to -12dB */
 
@@ -244,13 +224,13 @@ inline static int get_treble(struct i2c_client *client)
        return treble;
 }
 
-inline static void set_treble(struct i2c_client *client, int treble)
+static void set_treble(struct i2c_client *client, int treble)
 {
        /* PATH1_EQ_TREBLE_VOL */
        cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
 }
 
-inline static int get_balance(struct i2c_client *client)
+static int get_balance(struct i2c_client *client)
 {
        /* balance is 7 bit, 0 to -96dB */
 
@@ -264,7 +244,7 @@ inline static int get_balance(struct i2c_client *client)
        return balance << 8;
 }
 
-inline static void set_balance(struct i2c_client *client, int balance)
+static void set_balance(struct i2c_client *client, int balance)
 {
        int bal = balance >> 8;
        if (bal > 0x80) {
@@ -280,17 +260,17 @@ inline static void set_balance(struct i2c_client *client, int balance)
        }
 }
 
-inline static int get_mute(struct i2c_client *client)
+static int get_mute(struct i2c_client *client)
 {
        /* check SRC1_MUTE_EN */
        return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
 }
 
-inline static void set_mute(struct i2c_client *client, int mute)
+static void set_mute(struct i2c_client *client, int mute)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
 
-       if (state->audio_input == AUDIO_TUNER) {
+       if (state->aud_input != CX25840_AUDIO_SERIAL) {
                /* Must turn off microcontroller in order to mute sound.
                 * Not sure if this is the best method, but it does work.
                 * If the microcontroller is running, then it will undo any
@@ -314,10 +294,9 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
        struct v4l2_control *ctrl = arg;
 
        switch (cmd) {
-       case AUDC_SET_INPUT:
-               return set_input(client, *(int *)arg);
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+               return set_audclk_freq(client, *(u32 *)arg);
+
        case VIDIOC_G_CTRL:
                switch (ctrl->id) {
                case V4L2_CID_AUDIO_VOLUME:
@@ -339,6 +318,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
                        return -EINVAL;
                }
                break;
+
        case VIDIOC_S_CTRL:
                switch (ctrl->id) {
                case V4L2_CID_AUDIO_VOLUME:
@@ -360,6 +340,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
                        return -EINVAL;
                }
                break;
+
        default:
                return -EINVAL;
        }
index 3b09f46dddf68028fab1f486954897df846fce1d..d45237d508c45e868dafa4b3afef8103756ea72f 100644 (file)
@@ -43,11 +43,11 @@ MODULE_LICENSE("GPL");
 static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
 
-int cx25840_debug = 0;
+int debug = 0;
 
-module_param(cx25840_debug, bool, 0644);
+module_param(debug, bool, 0644);
 
-MODULE_PARM_DESC(cx25840_debug, "Debugging messages [0=Off (default) 1=On]");
+MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
 
 I2C_CLIENT_INSMOD;
 
@@ -115,13 +115,13 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
 
 /* ----------------------------------------------------------------------- */
 
-static int set_input(struct i2c_client *, enum cx25840_input);
-static void input_change(struct i2c_client *);
+static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+                                               enum cx25840_audio_input aud_input);
 static void log_status(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 
-static inline void init_dll1(struct i2c_client *client)
+static void init_dll1(struct i2c_client *client)
 {
        /* This is the Hauppauge sequence used to
         * initialize the Delay Lock Loop 1 (ADC DLL). */
@@ -135,7 +135,7 @@ static inline void init_dll1(struct i2c_client *client)
        cx25840_write(client, 0x15b, 0x10);
 }
 
-static inline void init_dll2(struct i2c_client *client)
+static void init_dll2(struct i2c_client *client)
 {
        /* This is the Hauppauge sequence used to
         * initialize the Delay Lock Loop 2 (ADC DLL). */
@@ -195,10 +195,8 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw)
        /* AC97 shift */
        cx25840_write(client, 0x8cf, 0x0f);
 
-       /* (re)set video input */
-       set_input(client, state->input);
-       /* (re)set audio input */
-       cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input);
+       /* (re)set input */
+       set_input(client, state->vid_input, state->aud_input);
 
        /* start microcontroller */
        cx25840_and_or(client, 0x803, ~0x10, 0x10);
@@ -223,7 +221,7 @@ static void input_change(struct i2c_client *client)
                cx25840_write(client, 0x80b, 0x10);
        } else if (std & V4L2_STD_NTSC) {
                /* NTSC */
-               if (state->cardtype == CARDTYPE_PVR150_WORKAROUND) {
+               if (state->pvr150_workaround) {
                        /* Certain Hauppauge PVR150 models have a hardware bug
                           that causes audio to drop out. For these models the
                           audio standard must be set explicitly.
@@ -259,72 +257,68 @@ static void input_change(struct i2c_client *client)
        }
 }
 
-static int set_input(struct i2c_client *client, enum cx25840_input input)
+static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+                                               enum cx25840_audio_input aud_input)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
+       u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
+                          vid_input <= CX25840_COMPOSITE8);
+       u8 reg;
 
-       cx25840_dbg("decoder set input (%d)\n", input);
+       v4l_dbg(1, client, "decoder set video input %d, audio input %d\n",
+                       vid_input, aud_input);
 
-       switch (input) {
-       case CX25840_TUNER:
-               cx25840_dbg("now setting Tuner input\n");
-
-               if (state->cardtype == CARDTYPE_PVR150 ||
-                   state->cardtype == CARDTYPE_PVR150_WORKAROUND) {
-                       /* CH_SEL_ADC2=1 */
-                       cx25840_and_or(client, 0x102, ~0x2, 0x02);
-               }
-
-               /* Video Input Control */
-               if (state->cardtype == CARDTYPE_PG600) {
-                       cx25840_write(client, 0x103, 0x11);
-               } else {
-                       cx25840_write(client, 0x103, 0x46);
-               }
-
-               /* INPUT_MODE=0 */
-               cx25840_and_or(client, 0x401, ~0x6, 0x00);
-               break;
-
-       case CX25840_COMPOSITE0:
-       case CX25840_COMPOSITE1:
-               cx25840_dbg("now setting Composite input\n");
+       if (is_composite) {
+               reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
+       } else {
+               int luma = vid_input & 0xf0;
+               int chroma = vid_input & 0xf00;
 
-               /* Video Input Control */
-               if (state->cardtype == CARDTYPE_PG600) {
-                       cx25840_write(client, 0x103, 0x00);
-               } else {
-                       cx25840_write(client, 0x103, 0x02);
+               if ((vid_input & ~0xff0) ||
+                   luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
+                   chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
+                       v4l_err(client, "0x%04x is not a valid video input!\n", vid_input);
+                       return -EINVAL;
                }
-
-               /* INPUT_MODE=0 */
-               cx25840_and_or(client, 0x401, ~0x6, 0x00);
-               break;
-
-       case CX25840_SVIDEO0:
-       case CX25840_SVIDEO1:
-               cx25840_dbg("now setting S-Video input\n");
-
-               /* CH_SEL_ADC2=0 */
-               cx25840_and_or(client, 0x102, ~0x2, 0x00);
-
-               /* Video Input Control */
-               if (state->cardtype == CARDTYPE_PG600) {
-                       cx25840_write(client, 0x103, 0x02);
+               reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
+               if (chroma >= CX25840_SVIDEO_CHROMA7) {
+                       reg &= 0x3f;
+                       reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2;
                } else {
-                       cx25840_write(client, 0x103, 0x10);
+                       reg &= 0xcf;
+                       reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4;
                }
+       }
 
-               /* INPUT_MODE=1 */
-               cx25840_and_or(client, 0x401, ~0x6, 0x02);
+       switch (aud_input) {
+       case CX25840_AUDIO_SERIAL:
+               /* do nothing, use serial audio input */
                break;
+       case CX25840_AUDIO4: reg &= ~0x30; break;
+       case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+       case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+       case CX25840_AUDIO7: reg &= ~0xc0; break;
+       case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
 
        default:
-               cx25840_err("%d is not a valid input!\n", input);
+               v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input);
                return -EINVAL;
        }
 
-       state->input = input;
+       cx25840_write(client, 0x103, reg);
+       /* Set INPUT_MODE to Composite (0) or S-Video (1) */
+       cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
+       /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+       cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+       /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
+       if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+               cx25840_and_or(client, 0x102, ~0x4, 4);
+       else
+               cx25840_and_or(client, 0x102, ~0x4, 0);
+
+       state->vid_input = vid_input;
+       state->aud_input = aud_input;
+       cx25840_audio_set_path(client);
        input_change(client);
        return 0;
 }
@@ -395,23 +389,14 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        struct cx25840_state *state = i2c_get_clientdata(client);
 
        switch (ctrl->id) {
-       case CX25840_CID_CARDTYPE:
-               switch (ctrl->value) {
-               case CARDTYPE_PVR150:
-               case CARDTYPE_PVR150_WORKAROUND:
-               case CARDTYPE_PG600:
-                       state->cardtype = ctrl->value;
-                       break;
-               default:
-                       return -ERANGE;
-               }
-
-               set_input(client, state->input);
+       case CX25840_CID_ENABLE_PVR150_WORKAROUND:
+               state->pvr150_workaround = ctrl->value;
+               set_input(client, state->vid_input, state->aud_input);
                break;
 
        case V4L2_CID_BRIGHTNESS:
                if (ctrl->value < 0 || ctrl->value > 255) {
-                       cx25840_err("invalid brightness setting %d\n",
+                       v4l_err(client, "invalid brightness setting %d\n",
                                    ctrl->value);
                        return -ERANGE;
                }
@@ -421,7 +406,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 
        case V4L2_CID_CONTRAST:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       cx25840_err("invalid contrast setting %d\n",
+                       v4l_err(client, "invalid contrast setting %d\n",
                                    ctrl->value);
                        return -ERANGE;
                }
@@ -431,7 +416,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 
        case V4L2_CID_SATURATION:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       cx25840_err("invalid saturation setting %d\n",
+                       v4l_err(client, "invalid saturation setting %d\n",
                                    ctrl->value);
                        return -ERANGE;
                }
@@ -442,7 +427,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 
        case V4L2_CID_HUE:
                if (ctrl->value < -127 || ctrl->value > 127) {
-                       cx25840_err("invalid hue setting %d\n", ctrl->value);
+                       v4l_err(client, "invalid hue setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
@@ -455,6 +440,9 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_MUTE:
                return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
+
+       default:
+               return -EINVAL;
        }
 
        return 0;
@@ -465,11 +453,11 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        struct cx25840_state *state = i2c_get_clientdata(client);
 
        switch (ctrl->id) {
-       case CX25840_CID_CARDTYPE:
-               ctrl->value = state->cardtype;
+       case CX25840_CID_ENABLE_PVR150_WORKAROUND:
+               ctrl->value = state->pvr150_workaround;
                break;
        case V4L2_CID_BRIGHTNESS:
-               ctrl->value = cx25840_read(client, 0x414) + 128;
+               ctrl->value = (s8)cx25840_read(client, 0x414) + 128;
                break;
        case V4L2_CID_CONTRAST:
                ctrl->value = cx25840_read(client, 0x415) >> 1;
@@ -478,7 +466,7 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
                ctrl->value = cx25840_read(client, 0x420) >> 1;
                break;
        case V4L2_CID_HUE:
-               ctrl->value = cx25840_read(client, 0x422);
+               ctrl->value = (s8)cx25840_read(client, 0x422);
                break;
        case V4L2_CID_AUDIO_VOLUME:
        case V4L2_CID_AUDIO_BASS:
@@ -527,7 +515,7 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 
                if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
                    (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
-                       cx25840_err("%dx%d is not a valid size!\n",
+                       v4l_err(client, "%dx%d is not a valid size!\n",
                                    pix->width, pix->height);
                        return -ERANGE;
                }
@@ -545,7 +533,7 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
                else
                        filter = 3;
 
-               cx25840_dbg("decoder set size %dx%d -> scale  %ux%u\n",
+               v4l_dbg(1, client, "decoder set size %dx%d -> scale  %ux%u\n",
                            pix->width, pix->height, HSC, VSC);
 
                /* HSCALE=HSC */
@@ -574,17 +562,98 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 
 /* ----------------------------------------------------------------------- */
 
+static struct v4l2_queryctrl cx25840_qctrl[] = {
+       {
+               .id            = V4L2_CID_BRIGHTNESS,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Brightness",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 128,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_CONTRAST,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Contrast",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 64,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_SATURATION,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Saturation",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 64,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_HUE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Hue",
+               .minimum       = -128,
+               .maximum       = 127,
+               .step          = 1,
+               .default_value = 0,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_AUDIO_VOLUME,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Volume",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 58880,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_AUDIO_BALANCE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Balance",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_AUDIO_MUTE,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+               .name          = "Mute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 1,
+               .default_value = 1,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_AUDIO_BASS,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Bass",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+       }, {
+               .id            = V4L2_CID_AUDIO_TREBLE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Treble",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+       },
+};
+
+/* ----------------------------------------------------------------------- */
+
 static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                           void *arg)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
        struct v4l2_tuner *vt = arg;
-       int result = 0;
 
        switch (cmd) {
-       case 0:
-               break;
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        /* ioctls to allow direct access to the
         * cx25840 registers for testing */
@@ -615,18 +684,16 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                return cx25840_vbi(client, cmd, arg);
 
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-       case AUDC_SET_INPUT:
-               result = cx25840_audio(client, cmd, arg);
-               break;
+               return cx25840_audio(client, cmd, arg);
 
        case VIDIOC_STREAMON:
-               cx25840_dbg("enable output\n");
+               v4l_dbg(1, client, "enable output\n");
                cx25840_write(client, 0x115, 0x8c);
                cx25840_write(client, 0x116, 0x07);
                break;
 
        case VIDIOC_STREAMOFF:
-               cx25840_dbg("disable output\n");
+               v4l_dbg(1, client, "disable output\n");
                cx25840_write(client, 0x115, 0x00);
                cx25840_write(client, 0x116, 0x00);
                break;
@@ -636,28 +703,58 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                break;
 
        case VIDIOC_G_CTRL:
-               result = get_v4lctrl(client, (struct v4l2_control *)arg);
-               break;
+               return get_v4lctrl(client, (struct v4l2_control *)arg);
 
        case VIDIOC_S_CTRL:
-               result = set_v4lctrl(client, (struct v4l2_control *)arg);
-               break;
+               return set_v4lctrl(client, (struct v4l2_control *)arg);
+
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *qc = arg;
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++)
+                       if (qc->id && qc->id == cx25840_qctrl[i].id) {
+                               memcpy(qc, &cx25840_qctrl[i], sizeof(*qc));
+                               return 0;
+                       }
+               return -EINVAL;
+       }
 
        case VIDIOC_G_STD:
                *(v4l2_std_id *)arg = cx25840_get_v4lstd(client);
                break;
 
        case VIDIOC_S_STD:
-               result = set_v4lstd(client, *(v4l2_std_id *)arg);
+               state->radio = 0;
+               return set_v4lstd(client, *(v4l2_std_id *)arg);
+
+       case AUDC_SET_RADIO:
+               state->radio = 1;
                break;
 
        case VIDIOC_G_INPUT:
-               *(int *)arg = state->input;
+               *(int *)arg = state->vid_input;
                break;
 
        case VIDIOC_S_INPUT:
-               result = set_input(client, *(int *)arg);
+               return set_input(client, *(enum cx25840_video_input *)arg, state->aud_input);
+
+       case VIDIOC_S_AUDIO:
+       {
+               struct v4l2_audio *input = arg;
+
+               return set_input(client, state->vid_input, input->index);
+       }
+
+       case VIDIOC_G_AUDIO:
+       {
+               struct v4l2_audio *input = arg;
+
+               memset(input, 0, sizeof(*input));
+               input->index = state->aud_input;
                break;
+       }
 
        case VIDIOC_S_FREQUENCY:
                input_change(client);
@@ -670,6 +767,9 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                u8 vpres = cx25840_read(client, 0x80a) & 0x10;
                int val = 0;
 
+               if (state->radio)
+                       break;
+
                vt->capability |=
                    V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
                    V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
@@ -724,12 +824,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                break;
 
        case VIDIOC_G_FMT:
-               result = get_v4lfmt(client, (struct v4l2_format *)arg);
-               break;
+               return get_v4lfmt(client, (struct v4l2_format *)arg);
 
        case VIDIOC_S_FMT:
-               result = set_v4lfmt(client, (struct v4l2_format *)arg);
-               break;
+               return set_v4lfmt(client, (struct v4l2_format *)arg);
 
        case VIDIOC_INT_RESET:
                cx25840_initialize(client, 0);
@@ -741,11 +839,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                break;
 
        default:
-               cx25840_err("invalid ioctl %x\n", cmd);
                return -EINVAL;
        }
 
-       return result;
+       return 0;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -775,7 +872,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        client->driver = &i2c_driver_cx25840;
        snprintf(client->name, sizeof(client->name) - 1, "cx25840");
 
-       cx25840_dbg("detecting cx25840 client on address 0x%x\n", address << 1);
+       v4l_dbg(1, client, "detecting cx25840 client on address 0x%x\n", address << 1);
 
        device_id = cx25840_read(client, 0x101) << 8;
        device_id |= cx25840_read(client, 0x100);
@@ -783,12 +880,12 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        /* The high byte of the device ID should be
         * 0x84 if chip is present */
        if ((device_id & 0xff00) != 0x8400) {
-               cx25840_dbg("cx25840 not found\n");
+               v4l_dbg(1, client, "cx25840 not found\n");
                kfree(client);
                return 0;
        }
 
-       cx25840_info("cx25%3x-2%x found @ 0x%x (%s)\n",
+       v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
                    (device_id & 0xfff0) >> 4,
                    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
                    address << 1, adapter->name);
@@ -801,10 +898,10 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 
        i2c_set_clientdata(client, state);
        memset(state, 0, sizeof(struct cx25840_state));
-       state->input = CX25840_TUNER;
-       state->audclk_freq = V4L2_AUDCLK_48_KHZ;
-       state->audio_input = AUDIO_TUNER;
-       state->cardtype = CARDTYPE_PVR150;
+       state->vid_input = CX25840_COMPOSITE7;
+       state->aud_input = CX25840_AUDIO8;
+       state->audclk_freq = 48000;
+       state->pvr150_workaround = 0;
 
        cx25840_initialize(client, 1);
 
@@ -815,11 +912,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 
 static int cx25840_attach_adapter(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-       if (adapter->id == I2C_HW_B_BT848)
-#endif
                return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
        return 0;
 }
@@ -846,9 +939,7 @@ static struct i2c_driver i2c_driver_cx25840 = {
        .driver = {
                .name = "cx25840",
        },
-
        .id = I2C_DRIVERID_CX25840,
-
        .attach_adapter = cx25840_attach_adapter,
        .detach_client = cx25840_detach_client,
        .command = cx25840_command,
@@ -892,11 +983,13 @@ static void log_status(struct i2c_client *client)
        u8 pref_mode = cx25840_read(client, 0x809);
        u8 afc0 = cx25840_read(client, 0x80b);
        u8 mute_ctl = cx25840_read(client, 0x8d3);
+       int vid_input = state->vid_input;
+       int aud_input = state->aud_input;
        char *p;
 
-       cx25840_info("Video signal:              %spresent\n",
+       v4l_info(client, "Video signal:              %spresent\n",
                    (microctrl_vidfmt & 0x10) ? "" : "not ");
-       cx25840_info("Detected format:           %s\n",
+       v4l_info(client, "Detected format:           %s\n",
                    fmt_strs[gen_stat1 & 0xf]);
 
        switch (mod_det_stat0) {
@@ -911,7 +1004,7 @@ static void log_status(struct i2c_client *client)
        case 0xfe: p = "forced mode"; break;
        default: p = "not defined";
        }
-       cx25840_info("Detected audio mode:       %s\n", p);
+       v4l_info(client, "Detected audio mode:       %s\n", p);
 
        switch (mod_det_stat1) {
        case 0x00: p = "not defined"; break;
@@ -937,10 +1030,10 @@ static void log_status(struct i2c_client *client)
        case 0xff: p = "no detected audio standard"; break;
        default: p = "not defined";
        }
-       cx25840_info("Detected audio standard:   %s\n", p);
-       cx25840_info("Audio muted:               %s\n",
+       v4l_info(client, "Detected audio standard:   %s\n", p);
+       v4l_info(client, "Audio muted:               %s\n",
                    (mute_ctl & 0x2) ? "yes" : "no");
-       cx25840_info("Audio microcontroller:     %s\n",
+       v4l_info(client, "Audio microcontroller:     %s\n",
                    (download_ctl & 0x10) ? "running" : "stopped");
 
        switch (audio_config >> 4) {
@@ -962,7 +1055,7 @@ static void log_status(struct i2c_client *client)
        case 0x0f: p = "automatic detection"; break;
        default: p = "undefined";
        }
-       cx25840_info("Configured audio standard: %s\n", p);
+       v4l_info(client, "Configured audio standard: %s\n", p);
 
        if ((audio_config >> 4) < 0xF) {
                switch (audio_config & 0xF) {
@@ -979,7 +1072,7 @@ static void log_status(struct i2c_client *client)
                case 0x0a: p = "SAP"; break;
                default: p = "undefined";
                }
-               cx25840_info("Configured audio mode:     %s\n", p);
+               v4l_info(client, "Configured audio mode:     %s\n", p);
        } else {
                switch (audio_config & 0xF) {
                case 0x00: p = "BG"; break;
@@ -995,30 +1088,27 @@ static void log_status(struct i2c_client *client)
                case 0x0f: p = "automatic standard and mode detection"; break;
                default: p = "undefined";
                }
-               cx25840_info("Configured audio system:   %s\n", p);
+               v4l_info(client, "Configured audio system:   %s\n", p);
        }
 
-       cx25840_info("Specified standard:        %s\n",
+       v4l_info(client, "Specified standard:        %s\n",
                    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
 
-       switch (state->input) {
-       case CX25840_COMPOSITE0: p = "Composite 0"; break;
-       case CX25840_COMPOSITE1: p = "Composite 1"; break;
-       case CX25840_SVIDEO0: p = "S-Video 0"; break;
-       case CX25840_SVIDEO1: p = "S-Video 1"; break;
-       case CX25840_TUNER: p = "Tuner"; break;
+       if (vid_input >= CX25840_COMPOSITE1 &&
+           vid_input <= CX25840_COMPOSITE8) {
+               v4l_info(client, "Specified video input:     Composite %d\n",
+                       vid_input - CX25840_COMPOSITE1 + 1);
+       } else {
+               v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
+                       (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
        }
-       cx25840_info("Specified input:           %s\n", p);
-       cx25840_info("Specified audio input:     %s\n",
-                   state->audio_input == 0 ? "Tuner" : "External");
-
-       switch (state->audclk_freq) {
-       case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break;
-       case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break;
-       case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break;
-       default: p = "undefined";
+       if (aud_input) {
+               v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
+       } else {
+               v4l_info(client, "Specified audio input:     External\n");
        }
-       cx25840_info("Specified audioclock freq: %s\n", p);
+
+       v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
 
        switch (pref_mode & 0xf) {
        case 0: p = "mono/language A"; break;
@@ -1031,7 +1121,7 @@ static void log_status(struct i2c_client *client)
        case 7: p = "language AB"; break;
        default: p = "undefined";
        }
-       cx25840_info("Preferred audio mode:      %s\n", p);
+       v4l_info(client, "Preferred audio mode:      %s\n", p);
 
        if ((audio_config & 0xf) == 0xf) {
                switch ((afc0 >> 3) & 0x3) {
@@ -1040,7 +1130,7 @@ static void log_status(struct i2c_client *client)
                case 2: p = "autodetect"; break;
                default: p = "undefined";
                }
-               cx25840_info("Selected 65 MHz format:    %s\n", p);
+               v4l_info(client, "Selected 65 MHz format:    %s\n", p);
 
                switch (afc0 & 0x7) {
                case 0: p = "chroma"; break;
@@ -1050,6 +1140,6 @@ static void log_status(struct i2c_client *client)
                case 4: p = "autodetect"; break;
                default: p = "undefined";
                }
-               cx25840_info("Selected 45 MHz format:    %s\n", p);
+               v4l_info(client, "Selected 45 MHz format:    %s\n", p);
        }
 }
index df9d50a75542461c22ee79535ed84d63196bc95a..e1a7823d82cdeee0e81d3d44b664a72f8da1a93d 100644 (file)
@@ -15,7 +15,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -38,7 +37,7 @@ module_param(firmware, charp, 0444);
 MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]");
 MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
 
-static inline void set_i2c_delay(struct i2c_client *client, int delay)
+static void set_i2c_delay(struct i2c_client *client, int delay)
 {
        struct i2c_algo_bit_data *algod = client->adapter->algo_data;
 
@@ -52,7 +51,7 @@ static inline void set_i2c_delay(struct i2c_client *client, int delay)
        }
 }
 
-static inline void start_fw_load(struct i2c_client *client)
+static void start_fw_load(struct i2c_client *client)
 {
        /* DL_ADDR_LB=0 DL_ADDR_HB=0 */
        cx25840_write(client, 0x800, 0x00);
@@ -66,7 +65,7 @@ static inline void start_fw_load(struct i2c_client *client)
                set_i2c_delay(client, 3);
 }
 
-static inline void end_fw_load(struct i2c_client *client)
+static void end_fw_load(struct i2c_client *client)
 {
        if (fastfw)
                set_i2c_delay(client, 10);
@@ -77,38 +76,47 @@ static inline void end_fw_load(struct i2c_client *client)
        cx25840_write(client, 0x803, 0x03);
 }
 
-static inline int check_fw_load(struct i2c_client *client, int size)
+static int check_fw_load(struct i2c_client *client, int size)
 {
        /* DL_ADDR_HB DL_ADDR_LB */
        int s = cx25840_read(client, 0x801) << 8;
        s |= cx25840_read(client, 0x800);
 
        if (size != s) {
-               cx25840_err("firmware %s load failed\n", firmware);
+               v4l_err(client, "firmware %s load failed\n", firmware);
                return -EINVAL;
        }
 
-       cx25840_info("loaded %s firmware (%d bytes)\n", firmware, size);
+       v4l_info(client, "loaded %s firmware (%d bytes)\n", firmware, size);
        return 0;
 }
 
-static inline int fw_write(struct i2c_client *client, u8 * data, int size)
+static int fw_write(struct i2c_client *client, u8 * data, int size)
 {
-       if (i2c_master_send(client, data, size) < size) {
+       int sent;
+
+       if ((sent = i2c_master_send(client, data, size)) < size) {
 
                if (fastfw) {
-                       cx25840_err("333MHz i2c firmware load failed\n");
+                       v4l_err(client, "333MHz i2c firmware load failed\n");
                        fastfw = 0;
                        set_i2c_delay(client, 10);
 
+                       if (sent > 2) {
+                               u16 dl_addr = cx25840_read(client, 0x801) << 8;
+                               dl_addr |= cx25840_read(client, 0x800);
+                               dl_addr -= sent - 2;
+                               cx25840_write(client, 0x801, dl_addr >> 8);
+                               cx25840_write(client, 0x800, dl_addr & 0xff);
+                       }
+
                        if (i2c_master_send(client, data, size) < size) {
-                               cx25840_err
-                                   ("100MHz i2c firmware load failed\n");
+                               v4l_err(client, "100MHz i2c firmware load failed\n");
                                return -ENOSYS;
                        }
 
                } else {
-                       cx25840_err("firmware load i2c failure\n");
+                       v4l_err(client, "firmware load i2c failure\n");
                        return -ENOSYS;
                }
 
@@ -124,7 +132,7 @@ int cx25840_loadfw(struct i2c_client *client)
        int size, send, retval;
 
        if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
-               cx25840_err("unable to open firmware %s\n", firmware);
+               v4l_err(client, "unable to open firmware %s\n", firmware);
                return -EINVAL;
        }
 
index 13ba4e15ddea9ae10ae25597d7d3039cc4552c9d..04d879da7d63f9e3ecc6094bec9d08662d184d43 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "cx25840.h"
 
-static inline int odd_parity(u8 c)
+static int odd_parity(u8 c)
 {
        c ^= (c >> 4);
        c ^= (c >> 2);
@@ -31,7 +31,7 @@ static inline int odd_parity(u8 c)
        return c & 1;
 }
 
-static inline int decode_vps(u8 * dst, u8 * p)
+static int decode_vps(u8 * dst, u8 * p)
 {
        static const u8 biphase_tbl[] = {
                0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
index 40aa59f9c52595b6142f8a1f2483d2347c8bb927..fd22f30dcc1bf6ed1155b3f651bd0e2875f5b71d 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 
-extern int cx25840_debug;
-
-#define cx25840_dbg(fmt, arg...) do { if (cx25840_debug) \
-       printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-              client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define cx25840_err(fmt, arg...) do { \
-       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define cx25840_info(fmt, arg...) do { \
-       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0)
-
-/* The CARDTYPE_PVR150_WORKAROUND cardtype activates a workaround for a
-   hardware bug that is present in PVR150 (and possible PVR500) cards that
-   have certain NTSC tuners (tveeprom model numbers 85, 99 and 112). The
+/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
+   present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
+   certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
    audio autodetect fails on some channels for these models and the workaround
    is to select the audio standard explicitly. Many thanks to Hauppauge for
    providing this information. */
-enum cx25840_cardtype {
-       CARDTYPE_PVR150,
-       CARDTYPE_PG600,
-       CARDTYPE_PVR150_WORKAROUND,
+#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
+
+enum cx25840_video_input {
+       /* Composite video inputs In1-In8 */
+       CX25840_COMPOSITE1 = 1,
+       CX25840_COMPOSITE2,
+       CX25840_COMPOSITE3,
+       CX25840_COMPOSITE4,
+       CX25840_COMPOSITE5,
+       CX25840_COMPOSITE6,
+       CX25840_COMPOSITE7,
+       CX25840_COMPOSITE8,
+
+       /* S-Video inputs consist of one luma input (In1-In4) ORed with one
+          chroma input (In5-In8) */
+       CX25840_SVIDEO_LUMA1 = 0x10,
+       CX25840_SVIDEO_LUMA2 = 0x20,
+       CX25840_SVIDEO_LUMA3 = 0x30,
+       CX25840_SVIDEO_LUMA4 = 0x40,
+       CX25840_SVIDEO_CHROMA4 = 0x400,
+       CX25840_SVIDEO_CHROMA5 = 0x500,
+       CX25840_SVIDEO_CHROMA6 = 0x600,
+       CX25840_SVIDEO_CHROMA7 = 0x700,
+       CX25840_SVIDEO_CHROMA8 = 0x800,
+
+       /* S-Video aliases for common luma/chroma combinations */
+       CX25840_SVIDEO1 = 0x510,
+       CX25840_SVIDEO2 = 0x620,
+       CX25840_SVIDEO3 = 0x730,
+       CX25840_SVIDEO4 = 0x840,
 };
 
-enum cx25840_input {
-       CX25840_TUNER,
-       CX25840_COMPOSITE0,
-       CX25840_COMPOSITE1,
-       CX25840_SVIDEO0,
-       CX25840_SVIDEO1
+enum cx25840_audio_input {
+       /* Audio inputs: serial or In4-In8 */
+       CX25840_AUDIO_SERIAL,
+       CX25840_AUDIO4 = 4,
+       CX25840_AUDIO5,
+       CX25840_AUDIO6,
+       CX25840_AUDIO7,
+       CX25840_AUDIO8,
 };
 
 struct cx25840_state {
-       enum cx25840_cardtype cardtype;
-       enum cx25840_input input;
-       int audio_input;
-       enum v4l2_audio_clock_freq audclk_freq;
+       int pvr150_workaround;
+       int radio;
+       enum cx25840_video_input vid_input;
+       enum cx25840_audio_input aud_input;
+       u32 audclk_freq;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -84,6 +96,7 @@ int cx25840_loadfw(struct i2c_client *client);
 /* ----------------------------------------------------------------------- */
 /* cx25850-audio.c                                                         */
 int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg);
+void cx25840_audio_set_path(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 /* cx25850-vbi.c                                                           */
index 85ba4106dc79456621e090da7aba453808b9f0d5..76fcb4e995c92d86f14e864f762106aab4ed6e8e 100644 (file)
@@ -29,6 +29,21 @@ config VIDEO_CX88_DVB
          You must also select one or more DVB/ATSC demodulators.
          If you are unsure which you need, choose all of them.
 
+config VIDEO_CX88_ALSA
+       tristate "ALSA DMA audio support"
+       depends on VIDEO_CX88 && SND
+       select SND_PCM_OSS
+       ---help---
+         This is a video4linux driver for direct (DMA) audio on
+         Conexant 2388x based TV cards.
+         It only works with boards with function 01 enabled.
+         To check if your board supports, use lspci -n.
+         If supported, you should see 1471:8801 or 1471:8811
+         PCI device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cx88-alsa.
+
 config VIDEO_CX88_DVB_ALL_FRONTENDS
        bool "Build all supported frontends for cx2388x based TV cards"
        default y
@@ -38,6 +53,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
        select DVB_CX22702
        select DVB_LGDT330X
        select DVB_NXT200X
+       select DVB_CX24123
        ---help---
          This builds cx88-dvb with all currently supported frontend
          demodulators.  If you wish to tweak your configuration, and
@@ -89,3 +105,12 @@ config VIDEO_CX88_DVB_NXT200X
        ---help---
          This adds ATSC 8VSB and QAM64/256 support for cards based on the
          Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
+
+config VIDEO_CX88_DVB_CX24123
+       bool "Conexant CX24123 DVB-S Support"
+       default y
+       depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+       select DVB_CX24123
+       ---help---
+         This adds DVB-S support for cards based on the
+         Connexant 2388x chip and the CX24123 demodulator.
index 54401b02b7ce75c13dfc24df48c3b85c8d9196a7..e4b2134fe567ee8725125cd11d0907537e1e8189 100644 (file)
@@ -4,7 +4,7 @@ cx8800-objs     := cx88-video.o cx88-vbi.o
 cx8802-objs    := cx88-mpeg.o
 
 obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o
-obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
+obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o cx88-vp3054-i2c.o
 
 EXTRA_CFLAGS += -I$(src)/..
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
@@ -16,5 +16,7 @@ extra-cflags-$(CONFIG_DVB_OR51132)   += -DHAVE_OR51132=1
 extra-cflags-$(CONFIG_DVB_LGDT330X)  += -DHAVE_LGDT330X=1
 extra-cflags-$(CONFIG_DVB_MT352)     += -DHAVE_MT352=1
 extra-cflags-$(CONFIG_DVB_NXT200X)   += -DHAVE_NXT200X=1
+extra-cflags-$(CONFIG_DVB_CX24123)   += -DHAVE_CX24123=1
+extra-cflags-$(CONFIG_VIDEO_CX88_DVB)+= -DHAVE_VP3054_I2C=1
 
 EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
new file mode 100644 (file)
index 0000000..7695b52
--- /dev/null
@@ -0,0 +1,848 @@
+/*
+ *
+ *  Support for audio capture
+ *  PCI function #1 of the cx2388x.
+ *
+ *    (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
+ *    (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ *    Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
+ *    Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
+ *
+ *  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/device.h>
+#include <linux/interrupt.h>
+#include <asm/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+#include "cx88.h"
+#include "cx88-reg.h"
+
+#define dprintk(level,fmt, arg...)     if (debug >= level) \
+       printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg)
+
+#define dprintk_core(level,fmt, arg...)        if (debug >= level) \
+       printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
+
+
+/****************************************************************************
+       Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
+
+/* These can be replaced after done */
+#define MIXER_ADDR_LAST MAX_CX88_INPUT
+
+struct cx88_audio_dev {
+       struct cx88_core           *core;
+       struct cx88_dmaqueue       q;
+
+       /* pci i/o */
+       struct pci_dev             *pci;
+       unsigned char              pci_rev,pci_lat;
+
+       /* audio controls */
+       int                        irq;
+
+       snd_card_t                 *card;
+
+       spinlock_t                 reg_lock;
+
+       unsigned int               dma_size;
+       unsigned int               period_size;
+       unsigned int               num_periods;
+
+       struct videobuf_dmabuf dma_risc;
+
+       int                        mixer_volume[MIXER_ADDR_LAST+1][2];
+       int                        capture_source[MIXER_ADDR_LAST+1][2];
+
+       long int read_count;
+       long int read_offset;
+
+       struct cx88_buffer   *buf;
+
+       long opened;
+       snd_pcm_substream_t *substream;
+
+};
+typedef struct cx88_audio_dev snd_cx88_card_t;
+
+
+
+/****************************************************************************
+                       Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+static snd_card_t *snd_cx88_cards[SNDRV_CARDS];
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
+
+
+/****************************************************************************
+                               Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Ricardo Cerqueira");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
+                       "{{Conexant,23882},"
+                       "{{Conexant,23883}");
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+/****************************************************************************
+                       Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+int _cx88_start_audio_dma(snd_cx88_card_t *chip)
+{
+       struct cx88_buffer   *buf = chip->buf;
+       struct cx88_core *core=chip->core;
+       struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
+
+
+       dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start);
+
+       /* setup fifo + format - out channel */
+       cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25],
+                               buf->bpl, buf->risc.dma);
+
+       /* sets bpl size */
+       cx_write(MO_AUDD_LNGTH, buf->bpl);
+
+       /* reset counter */
+       cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET);
+
+       dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02));
+       /* enable irqs */
+       cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02);
+
+
+       /* Enables corresponding bits at AUD_INT_STAT */
+       cx_write(MO_AUD_INTMSK,
+                       (1<<16)|
+                       (1<<12)|
+                       (1<<4)|
+                       (1<<0)
+                       );
+
+       /* start dma */
+       cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+       cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
+
+       if (debug)
+               cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+
+       return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
+{
+       struct cx88_core *core=chip->core;
+       dprintk(1, "Stopping audio DMA\n");
+
+       /* stop dma */
+       cx_clear(MO_AUD_DMACNTRL, 0x11);
+
+       /* disable irqs */
+       cx_clear(MO_PCI_INTMSK, 0x02);
+       cx_clear(MO_AUD_INTMSK,
+                       (1<<16)|
+                       (1<<12)|
+                       (1<<4)|
+                       (1<<0)
+                       );
+
+       if (debug)
+               cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+
+       return 0;
+}
+
+#define MAX_IRQ_LOOP 10
+
+/*
+ * BOARD Specific: IRQ dma bits
+ */
+static char *cx88_aud_irqs[32] = {
+       "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
+       NULL,                                     /* reserved */
+       "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
+       NULL,                                     /* reserved */
+       "dnf_of", "upf_uf", "rds_dnf_uf",         /* 8-10 */
+       NULL,                                     /* reserved */
+       "dn_sync", "up_sync", "rds_dn_sync",      /* 12-14 */
+       NULL,                                     /* reserved */
+       "opc_err", "par_err", "rip_err",          /* 16-18 */
+       "pci_abort", "ber_irq", "mchg_irq"        /* 19-21 */
+};
+
+/*
+ * BOARD Specific: Threats IRQ audio specific calls
+ */
+static void cx8801_aud_irq(snd_cx88_card_t *chip)
+{
+       struct cx88_core *core = chip->core;
+       u32 status, mask;
+       u32 count;
+
+       status = cx_read(MO_AUD_INTSTAT);
+       mask   = cx_read(MO_AUD_INTMSK);
+       if (0 == (status & mask)) {
+               spin_unlock(&chip->reg_lock);
+               return;
+       }
+       cx_write(MO_AUD_INTSTAT, status);
+       if (debug > 1  ||  (status & mask & ~0xff))
+               cx88_print_irqbits(core->name, "irq aud",
+                                  cx88_aud_irqs, status, mask);
+       /* risc op code error */
+       if (status & (1 << 16)) {
+               printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
+               cx_clear(MO_AUD_DMACNTRL, 0x11);
+               cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
+       }
+
+       /* risc1 downstream */
+       if (status & 0x01) {
+               spin_lock(&chip->reg_lock);
+               count = cx_read(MO_AUDD_GPCNT);
+               spin_unlock(&chip->reg_lock);
+               if (chip->read_count == 0)
+                       chip->read_count += chip->dma_size;
+       }
+
+       if  (chip->read_count >= chip->period_size) {
+               dprintk(2, "Elapsing period\n");
+               snd_pcm_period_elapsed(chip->substream);
+       }
+
+       dprintk(3,"Leaving audio IRQ handler...\n");
+
+       /* FIXME: Any other status should deserve a special handling? */
+}
+
+/*
+ * BOARD Specific: Handles IRQ calls
+ */
+static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       snd_cx88_card_t *chip = dev_id;
+       struct cx88_core *core = chip->core;
+       u32 status;
+       int loop, handled = 0;
+
+       for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
+               status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
+               if (0 == status)
+                       goto out;
+               dprintk( 3, "cx8801_irq\n" );
+               dprintk( 3, "    loop: %d/%d\n", loop, MAX_IRQ_LOOP );
+               dprintk( 3, "    status: %d\n", status );
+               handled = 1;
+               cx_write(MO_PCI_INTSTAT, status);
+
+               if (status & 0x02)
+               {
+                       dprintk( 2, "    ALSA IRQ handling\n" );
+                       cx8801_aud_irq(chip);
+               }
+       };
+
+       if (MAX_IRQ_LOOP == loop) {
+               dprintk( 0, "clearing mask\n" );
+               dprintk(1,"%s/0: irq loop -- clearing mask\n",
+                      core->name);
+               cx_clear(MO_PCI_INTMSK,0x02);
+       }
+
+ out:
+       return IRQ_RETVAL(handled);
+}
+
+
+static int dsp_buffer_free(snd_cx88_card_t *chip)
+{
+       BUG_ON(!chip->dma_size);
+
+       dprintk(2,"Freeing buffer\n");
+       videobuf_dma_pci_unmap(chip->pci, &chip->dma_risc);
+       videobuf_dma_free(&chip->dma_risc);
+       btcx_riscmem_free(chip->pci,&chip->buf->risc);
+       kfree(chip->buf);
+
+       chip->dma_size = 0;
+
+       return 0;
+}
+
+/****************************************************************************
+                               ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+static snd_pcm_hardware_t snd_cx88_digital_hw = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+       .rates =                SNDRV_PCM_RATE_48000,
+       .rate_min =             48000,
+       .rate_max =             48000,
+       .channels_min = 1,
+       .channels_max = 2,
+       .buffer_bytes_max = (2*2048),
+       .period_bytes_min = 256,
+       .period_bytes_max = 2048,
+       .periods_min = 2,
+       .periods_max = 16,
+};
+
+/*
+ * audio pcm capture runtime free
+ */
+static void snd_card_cx88_runtime_free(snd_pcm_runtime_t *runtime)
+{
+}
+/*
+ * audio pcm capture open callback
+ */
+static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
+{
+       snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       int err;
+
+       if (test_and_set_bit(0, &chip->opened))
+               return -EBUSY;
+
+       err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0)
+               goto _error;
+
+       chip->substream = substream;
+
+       chip->read_count = 0;
+       chip->read_offset = 0;
+
+       runtime->private_free = snd_card_cx88_runtime_free;
+       runtime->hw = snd_cx88_digital_hw;
+
+       return 0;
+_error:
+       dprintk(1,"Error opening PCM!\n");
+       clear_bit(0, &chip->opened);
+       smp_mb__after_clear_bit();
+       return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx88_close(snd_pcm_substream_t *substream)
+{
+       snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+       clear_bit(0, &chip->opened);
+       smp_mb__after_clear_bit();
+
+       return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx88_hw_params(snd_pcm_substream_t * substream,
+                                snd_pcm_hw_params_t * hw_params)
+{
+       snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+       struct cx88_buffer *buf;
+
+       if (substream->runtime->dma_area) {
+               dsp_buffer_free(chip);
+               substream->runtime->dma_area = NULL;
+       }
+
+
+       chip->period_size = params_period_bytes(hw_params);
+       chip->num_periods = params_periods(hw_params);
+       chip->dma_size = chip->period_size * params_periods(hw_params);
+
+       BUG_ON(!chip->dma_size);
+
+       dprintk(1,"Setting buffer\n");
+
+       buf = kmalloc(sizeof(*buf),GFP_KERNEL);
+       if (NULL == buf)
+               return -ENOMEM;
+       memset(buf,0,sizeof(*buf));
+
+
+       buf->vb.memory = V4L2_MEMORY_MMAP;
+       buf->vb.width  = chip->period_size;
+       buf->vb.height = chip->num_periods;
+       buf->vb.size   = chip->dma_size;
+       buf->vb.field  = V4L2_FIELD_NONE;
+
+       videobuf_dma_init(&buf->vb.dma);
+       videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
+                       (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+
+       videobuf_dma_pci_map(chip->pci,&buf->vb.dma);
+
+
+       cx88_risc_databuffer(chip->pci, &buf->risc,
+                       buf->vb.dma.sglist,
+                       buf->vb.width, buf->vb.height);
+
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+       buf->vb.state = STATE_PREPARED;
+
+       buf->bpl = chip->period_size;
+       chip->buf = buf;
+       chip->dma_risc = buf->vb.dma;
+
+       dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages);
+       substream->runtime->dma_area = chip->dma_risc.vmalloc;
+       return 0;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx88_hw_free(snd_pcm_substream_t * substream)
+{
+
+       snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+       if (substream->runtime->dma_area) {
+               dsp_buffer_free(chip);
+               substream->runtime->dma_area = NULL;
+       }
+
+       return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx88_prepare(snd_pcm_substream_t *substream)
+{
+       return 0;
+}
+
+
+/*
+ * trigger callback
+ */
+static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+       snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+       int err;
+
+       spin_lock(&chip->reg_lock);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               err=_cx88_start_audio_dma(chip);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               err=_cx88_stop_audio_dma(chip);
+               break;
+       default:
+               err=-EINVAL;
+               break;
+       }
+
+       spin_unlock(&chip->reg_lock);
+
+       return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream)
+{
+       snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+
+       if (chip->read_count) {
+               chip->read_count -= snd_pcm_lib_period_bytes(substream);
+               chip->read_offset += snd_pcm_lib_period_bytes(substream);
+               if (chip->read_offset == chip->dma_size)
+                       chip->read_offset = 0;
+       }
+
+       dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count);
+       return bytes_to_frames(runtime, chip->read_offset);
+
+}
+
+/*
+ * operators
+ */
+static snd_pcm_ops_t snd_cx88_pcm_ops = {
+       .open = snd_cx88_pcm_open,
+       .close = snd_cx88_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_cx88_hw_params,
+       .hw_free = snd_cx88_hw_free,
+       .prepare = snd_cx88_prepare,
+       .trigger = snd_cx88_card_trigger,
+       .pointer = snd_cx88_pointer,
+};
+
+/*
+ * create a PCM device
+ */
+static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
+{
+       int err;
+       snd_pcm_t *pcm;
+
+       err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+       if (err < 0)
+               return err;
+       pcm->private_data = chip;
+       strcpy(pcm->name, name);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
+
+       return 0;
+}
+
+/****************************************************************************
+                               CONTROL INTERFACE
+ ****************************************************************************/
+static int snd_cx88_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 1;
+       info->value.integer.min = 0;
+       info->value.integer.max = 0x3f;
+
+       return 0;
+}
+
+/* OK - TODO: test it */
+static int snd_cx88_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core=chip->core;
+
+       value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+
+       return 0;
+}
+
+/* OK - TODO: test it */
+static int snd_cx88_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core=chip->core;
+       int v;
+       u32 old_control;
+
+       spin_lock_irq(&chip->reg_lock);
+       old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+       v = 0x3f - (value->value.integer.value[0] & 0x3f);
+       cx_andor(AUD_VOL_CTL, 0x3f, v);
+       spin_unlock_irq(&chip->reg_lock);
+
+       return v != old_control;
+}
+
+static snd_kcontrol_new_t snd_cx88_capture_volume = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Volume",
+       .info = snd_cx88_capture_volume_info,
+       .get = snd_cx88_capture_volume_get,
+       .put = snd_cx88_capture_volume_put,
+};
+
+
+/****************************************************************************
+                       Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
+ * Only boards with eeprom and byte 1 at eeprom=1 have it
+ */
+
+struct pci_device_id cx88_audio_pci_tbl[] = {
+       {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+       {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+       {0, }
+};
+MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
+
+/*
+ * Chip-specific destructor
+ */
+
+static int snd_cx88_free(snd_cx88_card_t *chip)
+{
+
+       if (chip->irq >= 0){
+               synchronize_irq(chip->irq);
+               free_irq(chip->irq, chip);
+       }
+
+       cx88_core_put(chip->core,chip->pci);
+
+       pci_disable_device(chip->pci);
+       return 0;
+}
+
+/*
+ * Component Destructor
+ */
+static void snd_cx88_dev_free(snd_card_t * card)
+{
+       snd_cx88_card_t *chip = card->private_data;
+
+       snd_cx88_free(chip);
+}
+
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+static int devno=0;
+static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
+                                   snd_cx88_card_t **rchip)
+{
+       snd_cx88_card_t   *chip;
+       struct cx88_core  *core;
+       int               err;
+
+       *rchip = NULL;
+
+       err = pci_enable_device(pci);
+       if (err < 0)
+               return err;
+
+       pci_set_master(pci);
+
+       chip = (snd_cx88_card_t *) card->private_data;
+
+       core = cx88_core_get(pci);
+
+       if (!pci_dma_supported(pci,0xffffffff)) {
+               dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
+               err = -EIO;
+               cx88_core_put(core,pci);
+               return err;
+       }
+
+
+       /* pci init */
+       chip->card = card;
+       chip->pci = pci;
+       chip->irq = -1;
+       spin_lock_init(&chip->reg_lock);
+
+       cx88_reset(core);
+       if (NULL == core) {
+               err = -EINVAL;
+               kfree (chip);
+               return err;
+       }
+       chip->core = core;
+
+       /* get irq */
+       err = request_irq(chip->pci->irq, cx8801_irq,
+                         SA_SHIRQ | SA_INTERRUPT, chip->core->name, chip);
+       if (err < 0) {
+               dprintk(0, "%s: can't get IRQ %d\n",
+                      chip->core->name, chip->pci->irq);
+               return err;
+       }
+
+       /* print pci info */
+       pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev);
+       pci_read_config_byte(pci, PCI_LATENCY_TIMER,  &chip->pci_lat);
+
+       dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
+              "latency: %d, mmio: 0x%lx\n", core->name, devno,
+              pci_name(pci), chip->pci_rev, pci->irq,
+              chip->pci_lat,pci_resource_start(pci,0));
+
+       chip->irq = pci->irq;
+       synchronize_irq(chip->irq);
+
+       snd_card_set_dev(card, &pci->dev);
+
+       *rchip = chip;
+
+       return 0;
+}
+
+static int __devinit cx88_audio_initdev(struct pci_dev *pci,
+                                   const struct pci_device_id *pci_id)
+{
+       snd_card_t       *card;
+       snd_cx88_card_t  *chip;
+       int              err;
+
+       if (devno >= SNDRV_CARDS)
+               return (-ENODEV);
+
+       if (!enable[devno]) {
+               ++devno;
+               return (-ENOENT);
+       }
+
+       card = snd_card_new(index[devno], id[devno], THIS_MODULE, sizeof(snd_cx88_card_t));
+       if (!card)
+               return (-ENOMEM);
+
+       card->private_free = snd_cx88_dev_free;
+
+       err = snd_cx88_create(card, pci, &chip);
+       if (err < 0)
+               return (err);
+
+       err = snd_cx88_pcm(chip, 0, "CX88 Digital");
+
+       if (err < 0) {
+               snd_card_free(card);
+               return (err);
+       }
+
+       err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip));
+       if (err < 0) {
+               snd_card_free(card);
+               return (err);
+       }
+
+       strcpy (card->driver, "CX88x");
+       sprintf(card->shortname, "Conexant CX%x", pci->device);
+       sprintf(card->longname, "%s at %#lx",
+               card->shortname, pci_resource_start(pci, 0));
+       strcpy (card->mixername, "CX88");
+
+       dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
+              card->driver,devno);
+
+       err = snd_card_register(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return (err);
+       }
+       snd_cx88_cards[devno] = card;
+
+       pci_set_drvdata(pci,card);
+
+       devno++;
+       return 0;
+}
+/*
+ * ALSA destructor
+ */
+static void __devexit cx88_audio_finidev(struct pci_dev *pci)
+{
+       struct cx88_audio_dev *card = pci_get_drvdata(pci);
+
+       snd_card_free((void *)card);
+
+       pci_set_drvdata(pci, NULL);
+
+       devno--;
+}
+
+/*
+ * PCI driver definition
+ */
+
+static struct pci_driver cx88_audio_pci_driver = {
+       .name     = "cx88_audio",
+       .id_table = cx88_audio_pci_tbl,
+       .probe    = cx88_audio_initdev,
+       .remove   = cx88_audio_finidev,
+       SND_PCI_PM_CALLBACKS
+};
+
+/****************************************************************************
+                               LINUX MODULE INIT
+ ****************************************************************************/
+
+/*
+ * module init
+ */
+static int cx88_audio_init(void)
+{
+       printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
+              (CX88_VERSION_CODE >> 16) & 0xff,
+              (CX88_VERSION_CODE >>  8) & 0xff,
+              CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+       return pci_register_driver(&cx88_audio_pci_driver);
+}
+
+/*
+ * module remove
+ */
+static void cx88_audio_fini(void)
+{
+
+       pci_unregister_driver(&cx88_audio_pci_driver);
+}
+
+module_init(cx88_audio_init);
+module_exit(cx88_audio_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index 74e57a53116ff58d5b5bbecc9ad7f9ef3f977db8..a490621193132bbf294f5211c279f28542a20fc0 100644 (file)
 #include <linux/firmware.h>
 
 #include "cx88.h"
+#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
-MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
 static unsigned int mpegbufs = 32;
@@ -1375,7 +1375,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
        struct cx88_core  *core = dev->core;
 
        if (debug > 1)
-               cx88_print_ioctl(core->name,cmd);
+               v4l_print_ioctl(core->name,cmd);
 
        switch (cmd) {
 
@@ -1689,6 +1689,18 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
        memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
        memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
 
+       if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) {
+
+               if (core->tuner_formats & V4L2_STD_525_60) {
+                       dev->height = 480;
+                       dev->params.vi_frame_rate = 30;
+               } else {
+                       dev->height = 576;
+                       dev->params.vi_frame_rate = 25;
+               }
+
+       }
+
        err = cx8802_init_common(dev);
        if (0 != err)
                goto fail_free;
index 951709aa88ba37e77fe63f901162736f0306d300..a76d54503b6f45d094bcf0fe8eb68b5a3b387c55 100644 (file)
@@ -611,12 +611,12 @@ struct cx88_board cx88_boards[] = {
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-                       .gpio0  = 0xed12,  /* internal decoder */
+                       .gpio0  = 0xed1a,
                        .gpio2  = 0x00ff,
                },{
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 0,
-                       .gpio0  = 0xff01,  /* mono from tuner chip */
+                       .gpio0  = 0xff01,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
@@ -708,7 +708,7 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
                .name           = "DViCO FusionHDTV 3 Gold-T",
-               .tuner_type     = TUNER_THOMSON_DTT7611,
+               .tuner_type     = TUNER_THOMSON_DTT761X,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -897,6 +897,158 @@ struct cx88_board cx88_boards[] = {
                        .gpio3  = 0x0000,
                }},
        },
+       [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
+               .name           = "Hauppauge Nova-S-Plus DVB-S",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+               }},
+               .dvb            = 1,
+       },
+       [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
+               .name           = "Hauppauge Nova-SE2 DVB-S",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               }},
+               .dvb            = 1,
+       },
+       [CX88_BOARD_KWORLD_DVBS_100] = {
+               .name           = "KWorld DVB-S 100",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+               }},
+               .dvb            = 1,
+       },
+       [CX88_BOARD_HAUPPAUGE_HVR1100] = {
+               .name           = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid",
+               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+               }},
+               /* fixme: Add radio support */
+               .dvb            = 1,
+       },
+       [CX88_BOARD_HAUPPAUGE_HVR1100LP] = {
+               .name           = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
+               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+               }},
+               /* fixme: Add radio support */
+               .dvb            = 1,
+       },
+       [CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = {
+               .name           = "digitalnow DNTV Live! DVB-T Pro",
+               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+                                 TDA9887_PORT2_ACTIVE,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0xf80808,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0xf80808,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0xf80808,
+               }},
+               .radio = {
+                        .type  = CX88_RADIO,
+                        .gpio0 = 0xf80808,
+               },
+               .dvb            = 1,
+       },
+       [CX88_BOARD_KWORLD_DVB_T_CX22702] = {
+               /* Kworld V-stream Xpert DVB-T with Thomson tuner */
+               /* DTT 7579 Conexant CX22702-19 Conexant CX2388x  */
+               /* Manenti Marco <marco_manenti@colman.it> */
+               .name           = "KWorld/VStream XPert DVB-T with cx22702",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0700,
+                       .gpio2  = 0x0101,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0700,
+                       .gpio2  = 0x0101,
+               }},
+               .dvb            = 1,
+       },
+       [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
+               .name           = "DViCO FusionHDTV DVB-T Dual Digital",
+               .tuner_type     = TUNER_ABSENT, /* No analog tuner */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x000027df,
+                },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x000027df,
+               }},
+               .dvb            = 1,
+       },
+
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -1044,6 +1196,54 @@ struct cx88_subid cx88_subids[] = {
                .subvendor = 0x1461,
                .subdevice = 0x000a,
                .card      = CX88_BOARD_AVERTV_303,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9200,
+               .card      = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9201,
+               .card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9202,
+               .card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
+       },{
+               .subvendor = 0x17de,
+               .subdevice = 0x08b2,
+               .card      = CX88_BOARD_KWORLD_DVBS_100,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9400,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR1100,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9402,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR1100,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9800,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9802,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9001,
+               .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
+       },{
+               .subvendor = 0x1822,
+               .subdevice = 0x0025,
+               .card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+       },{
+               .subvendor = 0x17de,
+               .subdevice = 0x08a1,
+               .card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
+       },{
+               .subvendor = 0x18ac,
+               .subdevice = 0xdb50,
+               .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
        },
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1075,20 +1275,19 @@ static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
               core->name, core->tuner_type, eeprom_data[0]);
 }
 
-
-/* ----------------------------------------------------------------------- */
-
 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
        struct tveeprom tv;
 
        tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data);
        core->tuner_type = tv.tuner_type;
+       core->tuner_formats = tv.tuner_formats;
        core->has_radio  = tv.has_radio;
 
        /* Make sure we support the board model */
        switch (tv.model)
        {
+       case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
        case 90002: /* Nova-T-PCI (9002) */
        case 92001: /* Nova-S-Plus (Video and IR) */
        case 92002: /* Nova-S-Plus (Video and IR) */
@@ -1096,7 +1295,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
        case 90500: /* Nova-T-PCI (oem) */
        case 90501: /* Nova-T-PCI (oem/IR) */
        case 92000: /* Nova-SE2 (OEM, No Video or IR) */
-
+       case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
+       case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
+       case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
                /* known */
                break;
        default:
@@ -1211,12 +1412,21 @@ void cx88_card_setup(struct cx88_core *core)
                if (0 == core->i2c_rc)
                        leadtek_eeprom(core,eeprom);
                break;
+       case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+       case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
+       case CX88_BOARD_HAUPPAUGE_HVR1100:
+       case CX88_BOARD_HAUPPAUGE_HVR1100LP:
                if (0 == core->i2c_rc)
                        hauppauge_eeprom(core,eeprom);
                break;
+       case CX88_BOARD_KWORLD_DVBS_100:
+               cx_write(MO_GP0_IO, 0x000007f8);
+               cx_write(MO_GP1_IO, 0x00000001);
+               break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
                /* GPIO0:0 is hooked to mt352 reset pin */
                cx_set(MO_GP0_IO, 0x00000101);
                cx_clear(MO_GP0_IO, 0x00000001);
@@ -1232,6 +1442,9 @@ void cx88_card_setup(struct cx88_core *core)
                cx_clear(MO_GP0_IO, 0x00000007);
                cx_set(MO_GP2_IO, 0x00000101);
                break;
+       case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+               cx_write(MO_GP0_IO, 0x00080808);
+               break;
        case CX88_BOARD_ATI_HDTVWONDER:
                if (0 == core->i2c_rc) {
                        /* enable tuner */
index bb6eb54e19ceddcb4726ee9dfc5117baa8c73ef1..9975be1aca38979340b70a7a061d56702f7a1b41 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/videodev2.h>
 
 #include "cx88.h"
+#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -76,60 +77,6 @@ static unsigned int cx88_devcount;
 static LIST_HEAD(cx88_devlist);
 static DECLARE_MUTEX(devlist);
 
-/* ------------------------------------------------------------------ */
-/* debug help functions                                               */
-
-static const char *v4l1_ioctls[] = {
-       "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
-       "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
-       "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
-       "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
-       "SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
-       "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
-       "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
-       "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
-       "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
-       "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
-       "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
-       "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
-       "44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
-       "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
-       "S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void cx88_print_ioctl(char *name, unsigned int cmd)
-{
-       char *dir;
-
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:              dir = "--"; break;
-       case _IOC_READ:              dir = "r-"; break;
-       case _IOC_WRITE:             dir = "-w"; break;
-       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-       default:                     dir = "??"; break;
-       }
-       switch (_IOC_TYPE(cmd)) {
-       case 'v':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
-                      name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-                      v4l1_ioctls[_IOC_NR(cmd)] : "???");
-               break;
-       case 'V':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
-                      name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
-                      v4l2_ioctls[_IOC_NR(cmd)] : "???");
-               break;
-       default:
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
-                      name, cmd, dir, _IOC_NR(cmd));
-       }
-}
-
-/* ------------------------------------------------------------------ */
 #define NO_SYNC_LINE (-1U)
 
 static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
@@ -291,9 +238,9 @@ cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
  *    channel  22    (u video)  -  2.0k
  *    channel  23    (v video)  -  2.0k
  *    channel  24    (vbi)      -  4.0k
- *    channels 25+26 (audio)    -  0.5k
+ *    channels 25+26 (audio)    -  4.0k
  *    channel  28    (mpeg)     -  4.0k
- *    TOTAL                     = 25.5k
+ *    TOTAL                     = 29.0k
  *
  * Every channel has 160 bytes control data (64 bytes instruction
  * queue and 6 CDT entries), which is close to 2k total.
@@ -359,7 +306,7 @@ struct sram_channel cx88_sram_channels[] = {
                .ctrl_start = 0x180680,
                .cdt        = 0x180680 + 64,
                .fifo_start = 0x185400,
-               .fifo_size  = 0x000200,
+               .fifo_size  = 0x001000,
                .ptr1_reg   = MO_DMA25_PTR1,
                .ptr2_reg   = MO_DMA25_PTR2,
                .cnt1_reg   = MO_DMA25_CNT1,
@@ -371,7 +318,7 @@ struct sram_channel cx88_sram_channels[] = {
                .ctrl_start = 0x180720,
                .cdt        = 0x180680 + 64,  /* same as audio IN */
                .fifo_start = 0x185400,       /* same as audio IN */
-               .fifo_size  = 0x000200,       /* same as audio IN */
+               .fifo_size  = 0x001000,       /* same as audio IN */
                .ptr1_reg   = MO_DMA26_PTR1,
                .ptr2_reg   = MO_DMA26_PTR2,
                .cnt1_reg   = MO_DMA26_CNT1,
@@ -382,7 +329,7 @@ struct sram_channel cx88_sram_channels[] = {
                .cmds_start = 0x180200,
                .ctrl_start = 0x1807C0,
                .cdt        = 0x1807C0 + 64,
-               .fifo_start = 0x185600,
+               .fifo_start = 0x186400,
                .fifo_size  = 0x001000,
                .ptr1_reg   = MO_DMA28_PTR1,
                .ptr2_reg   = MO_DMA28_PTR2,
@@ -848,7 +795,6 @@ int cx88_start_audio_dma(struct cx88_core *core)
 
        /* start dma */
        cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
-
        return 0;
 }
 
@@ -1208,7 +1154,6 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
 
 /* ------------------------------------------------------------------ */
 
-EXPORT_SYMBOL(cx88_print_ioctl);
 EXPORT_SYMBOL(cx88_print_irqbits);
 
 EXPORT_SYMBOL(cx88_core_irq);
index 99ea955f5987c058a50dabacee8b2377c3fbc75a..42c012aaa849de3314182fce35a435f8a9f9043f 100644 (file)
@@ -3,7 +3,7 @@
  * device driver for Conexant 2388x based TV cards
  * MPEG Transport Stream (DVB) routines
  *
- * (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ * (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
  * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
  *  This program is free software; you can redistribute it and/or modify
 
 #include "cx88.h"
 #include "dvb-pll.h"
+#include <media/v4l2-common.h>
 
 #ifdef HAVE_MT352
 # include "mt352.h"
 # include "mt352_priv.h"
+# ifdef HAVE_VP3054_I2C
+#  include "cx88-vp3054-i2c.h"
+# endif
 #endif
 #ifdef HAVE_CX22702
 # include "cx22702.h"
@@ -48,6 +52,9 @@
 #ifdef HAVE_NXT200X
 # include "nxt200x.h"
 #endif
+#ifdef HAVE_CX24123
+# include "cx24123.h"
+#endif
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -125,6 +132,27 @@ static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
+static int dvico_dual_demod_init(struct dvb_frontend *fe)
+{
+       static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
+       static u8 reset []         = { RESET,      0x80 };
+       static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+       static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+       static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+       static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+       mt352_write(fe, clock_config,   sizeof(clock_config));
+       udelay(200);
+       mt352_write(fe, reset,          sizeof(reset));
+       mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+       mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+       mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+       mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+       return 0;
+}
+
 static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { 0x89, 0x38, 0x39 };
@@ -172,6 +200,98 @@ static struct mt352_config dntv_live_dvbt_config = {
        .demod_init    = dntv_live_dvbt_demod_init,
        .pll_set       = mt352_pll_set,
 };
+
+static struct mt352_config dvico_fusionhdtv_dual = {
+       .demod_address = 0x0F,
+       .demod_init    = dvico_dual_demod_init,
+       .pll_set       = mt352_pll_set,
+};
+
+#ifdef HAVE_VP3054_I2C
+static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
+{
+       static u8 clock_config []  = { 0x89, 0x38, 0x38 };
+       static u8 reset []         = { 0x50, 0x80 };
+       static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+       static u8 agc_cfg []       = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
+                                      0x00, 0xFF, 0x00, 0x40, 0x40 };
+       static u8 dntv_extra[]     = { 0xB5, 0x7A };
+       static u8 capt_range_cfg[] = { 0x75, 0x32 };
+
+       mt352_write(fe, clock_config,   sizeof(clock_config));
+       udelay(2000);
+       mt352_write(fe, reset,          sizeof(reset));
+       mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+       mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+       udelay(2000);
+       mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
+       mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+       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 ((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_pll_set(struct dvb_frontend* fe,
+                                     struct dvb_frontend_parameters* params,
+                                     u8* pllbuf)
+{
+       struct cx8802_dev *dev= fe->dvb->priv;
+       struct i2c_msg msg =
+               { .addr = dev->core->pll_addr, .flags = 0,
+                 .buf = pllbuf+1, .len = 4 };
+       int err;
+
+       /* Switch PLL to DVB mode */
+       err = philips_fmd1216_pll_init(fe);
+       if (err)
+               return err;
+
+       /* Tune PLL */
+       pllbuf[0] = dev->core->pll_addr << 1;
+       dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+                         params->frequency,
+                         params->u.ofdm.bandwidth);
+       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__, pllbuf[0], pllbuf[1], 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,
+       .demod_init    = dntv_live_dvbt_pro_demod_init,
+       .pll_set       = dntv_live_dvbt_pro_pll_set,
+};
+#endif
 #endif
 
 #ifdef HAVE_CX22702
@@ -188,6 +308,12 @@ static struct cx22702_config hauppauge_novat_config = {
        .pll_address   = 0x61,
        .pll_desc      = &dvb_pll_thomson_dtt759x,
 };
+static struct cx22702_config hauppauge_hvr1100_config = {
+       .demod_address = 0x63,
+       .output_mode   = CX22702_SERIAL_OUTPUT,
+       .pll_address   = 0x61,
+       .pll_desc      = &dvb_pll_fmd1216me,
+};
 #endif
 
 #ifdef HAVE_OR51132
@@ -314,6 +440,40 @@ static struct nxt200x_config ati_hdtvwonder = {
 };
 #endif
 
+#ifdef HAVE_CX24123
+static int cx24123_set_ts_param(struct dvb_frontend* fe,
+       int is_punctured)
+{
+       struct cx8802_dev *dev= fe->dvb->priv;
+       dev->ts_gen_cntrl = 0x2;
+       return 0;
+}
+
+static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on)
+{
+       struct cx8802_dev *dev= fe->dvb->priv;
+       struct cx88_core *core = dev->core;
+
+       if (on)
+               cx_write(MO_GP0_IO, 0x000006f9);
+       else
+               cx_write(MO_GP0_IO, 0x000006fB);
+}
+
+static struct cx24123_config hauppauge_novas_config = {
+       .demod_address          = 0x55,
+       .use_isl6421            = 1,
+       .set_ts_params          = cx24123_set_ts_param,
+};
+
+static struct cx24123_config kworld_dvbs_100_config = {
+       .demod_address          = 0x15,
+       .use_isl6421            = 0,
+       .set_ts_params          = cx24123_set_ts_param,
+       .enable_lnb_voltage     = cx24123_enable_lnb_voltage,
+};
+#endif
+
 static int dvb_register(struct cx8802_dev *dev)
 {
        /* init struct videobuf_dvb */
@@ -329,10 +489,16 @@ static int dvb_register(struct cx8802_dev *dev)
                break;
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
        case CX88_BOARD_CONEXANT_DVB_T1:
+       case CX88_BOARD_KWORLD_DVB_T_CX22702:
        case CX88_BOARD_WINFAST_DTV1000:
                dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
                                                   &dev->core->i2c_adap);
                break;
+       case CX88_BOARD_HAUPPAUGE_HVR1100:
+       case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+               dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
+                                                  &dev->core->i2c_adap);
+               break;
 #endif
 #ifdef HAVE_MT352
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -355,6 +521,24 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
                                                 &dev->core->i2c_adap);
                break;
+       case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+#ifdef HAVE_VP3054_I2C
+               dev->core->pll_addr = 0x61;
+               dev->core->pll_desc = &dvb_pll_fmd1216me;
+               dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
+                       &((struct vp3054_i2c_state *)dev->card_priv)->adap);
+#else
+               printk("%s: built without vp3054 support\n", dev->core->name);
+#endif
+               break;
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+               /* The tin box says DEE1601, but it seems to be DTT7579
+                * compatible, with a slightly different MT352 AGC gain. */
+               dev->core->pll_addr = 0x61;
+               dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
+               dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+                                                &dev->core->i2c_adap);
+               break;
 #endif
 #ifdef HAVE_OR51132
        case CX88_BOARD_PCHDTV_HD3000:
@@ -393,7 +577,7 @@ static int dvb_register(struct cx8802_dev *dev)
                cx_set(MO_GP0_IO, 9);
                mdelay(200);
                dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_thomson_dtt7611;
+               dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
                dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
                                                    &dev->core->i2c_adap);
                }
@@ -420,6 +604,17 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
                                                 &dev->core->i2c_adap);
                break;
+#endif
+#ifdef HAVE_CX24123
+       case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+       case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+               dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
+                       &dev->core->i2c_adap);
+               break;
+       case CX88_BOARD_KWORLD_DVBS_100:
+               dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
+                       &dev->core->i2c_adap);
+               break;
 #endif
        default:
                printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
@@ -473,6 +668,12 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
        if (0 != err)
                goto fail_free;
 
+#ifdef HAVE_VP3054_I2C
+       err = vp3054_i2c_probe(dev);
+       if (0 != err)
+               goto fail_free;
+#endif
+
        /* dvb stuff */
        printk("%s/2: cx2388x based dvb card\n", core->name);
        videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops,
@@ -484,6 +685,9 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
        err = dvb_register(dev);
        if (0 != err)
                goto fail_fini;
+
+       /* Maintain a reference to cx88-video can query the 8802 device. */
+       core->dvbdev = dev;
        return 0;
 
  fail_fini:
@@ -499,9 +703,16 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev)
 {
        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 
+       /* Destroy any 8802 reference. */
+       dev->core->dvbdev = NULL;
+
        /* dvb */
        videobuf_dvb_unregister(&dev->dvb);
 
+#ifdef HAVE_VP3054_I2C
+       vp3054_i2c_remove(dev);
+#endif
+
        /* common */
        cx8802_fini_common(dev);
        cx88_core_put(dev->core,dev->pci);
index 4a8fb161b16a935c205340ee85814c1c3991760b..f720901e963866bec677d1bed8354c7d71a77535 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/io.h>
 
 #include "cx88.h"
+#include <media/v4l2-common.h>
 
 static unsigned int i2c_debug = 0;
 module_param(i2c_debug, int, 0644);
@@ -135,7 +136,17 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
 {
        if (0 != core->i2c_rc)
                return;
-       i2c_clients_command(&core->i2c_adap, cmd, arg);
+
+       if (core->dvbdev) {
+               if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
+                       core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+
+               i2c_clients_command(&core->i2c_adap, cmd, arg);
+
+               if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
+                       core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+       } else
+               i2c_clients_command(&core->i2c_adap, cmd, arg);
 }
 
 static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
index 461019dca90101262f502c6dc44dcfea45882b27..286c85b6bdf9a507232eadd2a44bc0e287067ecb 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 2003 Pavel Machek
  * Copyright (c) 2004 Gerd Knorr
- * Copyright (c) 2004 Chris Pascoe
+ * Copyright (c) 2004, 2005 Chris Pascoe
  *
  * 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
@@ -29,9 +29,8 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
-#include <media/ir-common.h>
-
 #include "cx88.h"
+#include <media/ir-common.h>
 
 /* ---------------------------------------------------------------------- */
 
@@ -258,6 +257,114 @@ static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
 
 /* ---------------------------------------------------------------------- */
 
+/* AVERTV STUDIO 303 Remote */
+static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
+       [ 0x2a ] = KEY_KP1,
+       [ 0x32 ] = KEY_KP2,
+       [ 0x3a ] = KEY_KP3,
+       [ 0x4a ] = KEY_KP4,
+       [ 0x52 ] = KEY_KP5,
+       [ 0x5a ] = KEY_KP6,
+       [ 0x6a ] = KEY_KP7,
+       [ 0x72 ] = KEY_KP8,
+       [ 0x7a ] = KEY_KP9,
+       [ 0x0e ] = KEY_KP0,
+
+       [ 0x02 ] = KEY_POWER,
+       [ 0x22 ] = KEY_VIDEO,
+       [ 0x42 ] = KEY_AUDIO,
+       [ 0x62 ] = KEY_ZOOM,
+       [ 0x0a ] = KEY_TV,
+       [ 0x12 ] = KEY_CD,
+       [ 0x1a ] = KEY_TEXT,
+
+       [ 0x16 ] = KEY_SUBTITLE,
+       [ 0x1e ] = KEY_REWIND,
+       [ 0x06 ] = KEY_PRINT,
+
+       [ 0x2e ] = KEY_SEARCH,
+       [ 0x36 ] = KEY_SLEEP,
+       [ 0x3e ] = KEY_SHUFFLE,
+       [ 0x26 ] = KEY_MUTE,
+
+       [ 0x4e ] = KEY_RECORD,
+       [ 0x56 ] = KEY_PAUSE,
+       [ 0x5e ] = KEY_STOP,
+       [ 0x46 ] = KEY_PLAY,
+
+       [ 0x6e ] = KEY_RED,
+       [ 0x0b ] = KEY_GREEN,
+       [ 0x66 ] = KEY_YELLOW,
+       [ 0x03 ] = KEY_BLUE,
+
+       [ 0x76 ] = KEY_LEFT,
+       [ 0x7e ] = KEY_RIGHT,
+       [ 0x13 ] = KEY_DOWN,
+       [ 0x1b ] = KEY_UP,
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* DigitalNow DNTV Live! DVB-T Pro Remote */
+static IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
+       [ 0x16 ] = KEY_POWER,
+       [ 0x5b ] = KEY_HOME,
+
+       [ 0x55 ] = KEY_TV,              /* live tv */
+       [ 0x58 ] = KEY_TUNER,           /* digital Radio */
+       [ 0x5a ] = KEY_RADIO,           /* FM radio */
+       [ 0x59 ] = KEY_DVD,             /* dvd menu */
+       [ 0x03 ] = KEY_1,
+       [ 0x01 ] = KEY_2,
+       [ 0x06 ] = KEY_3,
+       [ 0x09 ] = KEY_4,
+       [ 0x1d ] = KEY_5,
+       [ 0x1f ] = KEY_6,
+       [ 0x0d ] = KEY_7,
+       [ 0x19 ] = KEY_8,
+       [ 0x1b ] = KEY_9,
+       [ 0x0c ] = KEY_CANCEL,
+       [ 0x15 ] = KEY_0,
+       [ 0x4a ] = KEY_CLEAR,
+       [ 0x13 ] = KEY_BACK,
+       [ 0x00 ] = KEY_TAB,
+       [ 0x4b ] = KEY_UP,
+       [ 0x4e ] = KEY_LEFT,
+       [ 0x4f ] = KEY_OK,
+       [ 0x52 ] = KEY_RIGHT,
+       [ 0x51 ] = KEY_DOWN,
+       [ 0x1e ] = KEY_VOLUMEUP,
+       [ 0x0a ] = KEY_VOLUMEDOWN,
+       [ 0x02 ] = KEY_CHANNELDOWN,
+       [ 0x05 ] = KEY_CHANNELUP,
+       [ 0x11 ] = KEY_RECORD,
+       [ 0x14 ] = KEY_PLAY,
+       [ 0x4c ] = KEY_PAUSE,
+       [ 0x1a ] = KEY_STOP,
+       [ 0x40 ] = KEY_REWIND,
+       [ 0x12 ] = KEY_FASTFORWARD,
+       [ 0x41 ] = KEY_PREVIOUSSONG,    /* replay |< */
+       [ 0x42 ] = KEY_NEXTSONG,        /* skip >| */
+       [ 0x54 ] = KEY_CAMERA,          /* capture */
+       [ 0x50 ] = KEY_LANGUAGE,        /* sap */
+       [ 0x47 ] = KEY_TV2,             /* pip */
+       [ 0x4d ] = KEY_SCREEN,
+       [ 0x43 ] = KEY_SUBTITLE,
+       [ 0x10 ] = KEY_MUTE,
+       [ 0x49 ] = KEY_AUDIO,           /* l/r */
+       [ 0x07 ] = KEY_SLEEP,
+       [ 0x08 ] = KEY_VIDEO,           /* a/v */
+       [ 0x0e ] = KEY_PREVIOUS,        /* recall */
+       [ 0x45 ] = KEY_ZOOM,            /* zoom + */
+       [ 0x46 ] = KEY_ANGLE,           /* zoom - */
+       [ 0x56 ] = KEY_RED,
+       [ 0x57 ] = KEY_GREEN,
+       [ 0x5c ] = KEY_YELLOW,
+       [ 0x5d ] = KEY_BLUE,
+};
+
+/* ---------------------------------------------------------------------- */
+
 struct cx88_IR {
        struct cx88_core *core;
        struct input_dev *input;
@@ -266,7 +373,7 @@ struct cx88_IR {
        char phys[32];
 
        /* sample from gpio pin 16 */
-       int sampling;
+       u32 sampling;
        u32 samples[16];
        int scount;
        unsigned long release;
@@ -384,10 +491,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
                ir_codes = ir_codes_cinergy_1400;
                ir_type = IR_TYPE_PD;
-               ir->sampling = 1;
+               ir->sampling = 0xeb04; /* address */
                break;
        case CX88_BOARD_HAUPPAUGE:
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
+       case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+       case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+       case CX88_BOARD_HAUPPAUGE_HVR1100:
                ir_codes = ir_codes_hauppauge_new;
                ir_type = IR_TYPE_RC5;
                ir->sampling = 1;
@@ -427,6 +537,19 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->mask_keyup = 0x40;
                ir->polling = 1; /* ms */
                break;
+       case CX88_BOARD_AVERTV_303:
+       case CX88_BOARD_AVERTV_STUDIO_303:
+               ir_codes         = ir_codes_avertv_303;
+               ir->gpio_addr    = MO_GP2_IO;
+               ir->mask_keycode = 0xfb;
+               ir->mask_keydown = 0x02;
+               ir->polling      = 50; /* ms */
+               break;
+       case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+               ir_codes = ir_codes_dntv_live_dvbt_pro;
+               ir_type = IR_TYPE_PD;
+               ir->sampling = 0xff00; /* address */
+               break;
        }
 
        if (NULL == ir_codes) {
@@ -484,6 +607,10 @@ int cx88_ir_fini(struct cx88_core *core)
        if (NULL == ir)
                return 0;
 
+       if (ir->sampling) {
+               cx_write(MO_DDSCFG_IO, 0x0);
+               core->pci_irqmask &= ~(1 << 18);
+       }
        if (ir->polling) {
                del_timer(&ir->timer);
                flush_scheduled_work();
@@ -535,6 +662,7 @@ void cx88_ir_irq(struct cx88_core *core)
        /* decode it */
        switch (core->board) {
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
+       case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
                ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
 
                if (ircode == 0xffffffff) { /* decoding error */
@@ -550,7 +678,7 @@ void cx88_ir_irq(struct cx88_core *core)
                        break;
                }
 
-               if ((ircode & 0xffff) != 0xeb04) { /* wrong address */
+               if ((ircode & 0xffff) != (ir->sampling & 0xffff)) { /* wrong address */
                        ir_dprintk("pulse distance decoded wrong address\n");
                        break;
                }
@@ -567,6 +695,8 @@ void cx88_ir_irq(struct cx88_core *core)
                break;
        case CX88_BOARD_HAUPPAUGE:
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
+       case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+       case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
                if ((ircode & 0xfffff000) != 0x3000)
index 35e6d0c2b872b8d2650e723d5ae1126b32c59792..c79cc1d2bf8b1f95c27d7151189b52195ab9b401 100644 (file)
@@ -78,6 +78,11 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
                case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
                        cx_write(TS_SOP_STAT, 1<<13);
                        break;
+               case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+               case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+                       cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
+                       udelay(100);
+                       break;
                default:
                        cx_write(TS_SOP_STAT, 0x00);
                        break;
index a1b120c8a9b51f9adc4188f49c420b3b4dc44f8f..24118e43e73a7c46d8319954c5a749813dd14ce1 100644 (file)
@@ -132,14 +132,22 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
 {
        u32 volume;
 
+#ifndef USING_CX88_ALSA
        /* restart dma; This avoids buzz in NICAM and is good in others  */
        cx88_stop_audio_dma(core);
+#endif
        cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
+#ifndef USING_CX88_ALSA
        cx88_start_audio_dma(core);
+#endif
 
        if (cx88_boards[core->board].blackbird) {
                /* sets sound input from external adc */
-               cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+               if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN)
+                       cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+               else
+                       cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+
                cx_write(AUD_I2SINPUTCNTL, 4);
                cx_write(AUD_BAUDRATE, 1);
                /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
index 24a48f8a48c18a16be2dd96e278703ae7f153753..9a02515fe18bc440b6c7a26fc32faf9e7f03ec14 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/div64.h>
 
 #include "cx88.h"
+#include <media/v4l2-common.h>
 
 /* Include V4L1 specific functions. Should be removed soon */
 #include <linux/videodev.h>
@@ -240,7 +241,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0,
                        .maximum       = 0xff,
                        .step          = 1,
-                       .default_value = 0,
+                       .default_value = 0x3f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .off                   = 0,
@@ -271,7 +272,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0,
                        .maximum       = 0xff,
                        .step          = 1,
-                       .default_value = 0,
+                       .default_value = 0x7f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .off                   = 0,
@@ -285,6 +286,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .name          = "Mute",
                        .minimum       = 0,
                        .maximum       = 1,
+                       .default_value = 1,
                        .type          = V4L2_CTRL_TYPE_BOOLEAN,
                },
                .reg                   = AUD_VOL_CTL,
@@ -298,7 +300,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0,
                        .maximum       = 0x3f,
                        .step          = 1,
-                       .default_value = 0,
+                       .default_value = 0x1f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .reg                   = AUD_VOL_CTL,
@@ -917,6 +919,9 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
                ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
                break;
        }
+       printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+                                       ctl->id, c->reg, ctl->value,
+                                       c->mask, c->sreg ? " [shadowed]" : "");
        return 0;
 }
 
@@ -925,13 +930,13 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
 {
        /* struct cx88_core *core = dev->core; */
        struct cx88_ctrl *c = NULL;
-       u32 v_sat_value;
-       u32 value;
+       u32 value,mask;
        int i;
-
-       for (i = 0; i < CX8800_CTLS; i++)
-               if (cx8800_ctls[i].v.id == ctl->id)
+       for (i = 0; i < CX8800_CTLS; i++) {
+               if (cx8800_ctls[i].v.id == ctl->id) {
                        c = &cx8800_ctls[i];
+               }
+       }
        if (NULL == c)
                return -EINVAL;
 
@@ -939,6 +944,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
                ctl->value = c->v.minimum;
        if (ctl->value > c->v.maximum)
                ctl->value = c->v.maximum;
+       mask=c->mask;
        switch (ctl->id) {
        case V4L2_CID_AUDIO_BALANCE:
                value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value;
@@ -948,56 +954,44 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
                break;
        case V4L2_CID_SATURATION:
                /* special v_sat handling */
-               v_sat_value = ctl->value - (0x7f - 0x5a);
-               if (v_sat_value > 0xff)
-                       v_sat_value = 0xff;
-               if (v_sat_value < 0x00)
-                       v_sat_value = 0x00;
-               cx_andor(MO_UV_SATURATION, 0xff00, v_sat_value << 8);
-               /* fall through to default route for u_sat */
+
+               value = ((ctl->value - c->off) << c->shift) & c->mask;
+
+               if (core->tvnorm->id & V4L2_STD_SECAM) {
+                       /* For SECAM, both U and V sat should be equal */
+                       value=value<<8|value;
+               } else {
+                       /* Keeps U Saturation proportional to V Sat */
+                       value=(value*0x5a)/0x7f<<8|value;
+               }
+               mask=0xffff;
+               break;
        default:
                value = ((ctl->value - c->off) << c->shift) & c->mask;
                break;
        }
-       dprintk(1,"set_control id=0x%X reg=0x%x val=0x%x%s\n",
-               ctl->id, c->reg, value, c->sreg ? " [shadowed]" : "");
+       printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+                                       ctl->id, c->reg, value,
+                                       mask, c->sreg ? " [shadowed]" : "");
        if (c->sreg) {
-               cx_sandor(c->sreg, c->reg, c->mask, value);
+               cx_sandor(c->sreg, c->reg, mask, value);
        } else {
-               cx_andor(c->reg, c->mask, value);
+               cx_andor(c->reg, mask, value);
        }
        return 0;
 }
 
-/* static void init_controls(struct cx8800_dev *dev) */
 static void init_controls(struct cx88_core *core)
 {
-       static struct v4l2_control mute = {
-               .id    = V4L2_CID_AUDIO_MUTE,
-               .value = 1,
-       };
-       static struct v4l2_control volume = {
-               .id    = V4L2_CID_AUDIO_VOLUME,
-               .value = 0x3f,
-       };
-       static struct v4l2_control hue = {
-               .id    = V4L2_CID_HUE,
-               .value = 0x80,
-       };
-       static struct v4l2_control contrast = {
-               .id    = V4L2_CID_CONTRAST,
-               .value = 0x80,
-       };
-       static struct v4l2_control brightness = {
-               .id    = V4L2_CID_BRIGHTNESS,
-               .value = 0x80,
-       };
+       struct v4l2_control ctrl;
+       int i;
 
-       set_control(core,&mute);
-       set_control(core,&volume);
-       set_control(core,&hue);
-       set_control(core,&contrast);
-       set_control(core,&brightness);
+       for (i = 0; i < CX8800_CTLS; i++) {
+               ctrl.id=cx8800_ctls[i].v.id;
+               ctrl.value=cx8800_ctls[i].v.default_value
+                               +cx8800_ctls[i].off;
+               set_control(core, &ctrl);
+       }
 }
 
 /* ------------------------------------------------------------------ */
@@ -1125,7 +1119,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
        int err;
 
        if (video_debug > 1)
-               cx88_print_ioctl(core->name,cmd);
+               v4l_print_ioctl(core->name,cmd);
        switch (cmd) {
 
        /* --- capabilities ------------------------------------------ */
@@ -1261,7 +1255,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 
        dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
        if (video_debug > 1)
-               cx88_print_ioctl(core->name,cmd);
+               v4l_print_ioctl(core->name,cmd);
 
        switch (cmd) {
        /* ---------- tv norms ---------- */
@@ -1481,7 +1475,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
        struct cx88_core  *core = dev->core;
 
        if (video_debug > 1)
-               cx88_print_ioctl(core->name,cmd);
+               v4l_print_ioctl(core->name,cmd);
 
        switch (cmd) {
        case VIDIOC_QUERYCAP:
@@ -1740,6 +1734,7 @@ static struct file_operations video_fops =
        .poll          = video_poll,
        .mmap          = video_mmap,
        .ioctl         = video_ioctl,
+       .compat_ioctl  = v4l_compat_ioctl32,
        .llseek        = no_llseek,
 };
 
@@ -1767,6 +1762,7 @@ static struct file_operations radio_fops =
        .open          = video_open,
        .release       = video_release,
        .ioctl         = radio_ioctl,
+       .compat_ioctl  = v4l_compat_ioctl32,
        .llseek        = no_llseek,
 };
 
@@ -1928,8 +1924,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 
        /* initial device configuration */
        down(&core->lock);
-       init_controls(core);
        cx88_set_tvnorm(core,tvnorms);
+       init_controls(core);
        video_mux(core,0);
        up(&core->lock);
 
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
new file mode 100644 (file)
index 0000000..372cd29
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+
+    cx88-vp3054-i2c.c  --  support for the secondary I2C bus of the
+                          DNTV Live! DVB-T Pro (VP-3054), wired as:
+                          GPIO[0] -> SCL, GPIO[1] -> SDA
+
+    (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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/moduleparam.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "cx88.h"
+#include "cx88-vp3054-i2c.h"
+
+
+/* ----------------------------------------------------------------------- */
+
+static void vp3054_bit_setscl(void *data, int state)
+{
+       struct cx8802_dev *dev = data;
+       struct cx88_core *core = dev->core;
+       struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+       if (state) {
+               vp3054_i2c->state |=  0x0001;   /* SCL high */
+               vp3054_i2c->state &= ~0x0100;   /* external pullup */
+       } else {
+               vp3054_i2c->state &= ~0x0001;   /* SCL low */
+               vp3054_i2c->state |=  0x0100;   /* drive pin */
+       }
+       cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state);
+       cx_read(MO_GP0_IO);
+}
+
+static void vp3054_bit_setsda(void *data, int state)
+{
+       struct cx8802_dev *dev = data;
+       struct cx88_core *core = dev->core;
+       struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+       if (state) {
+               vp3054_i2c->state |=  0x0002;   /* SDA high */
+               vp3054_i2c->state &= ~0x0200;   /* tristate pin */
+       } else {
+               vp3054_i2c->state &= ~0x0002;   /* SDA low */
+               vp3054_i2c->state |=  0x0200;   /* drive pin */
+       }
+       cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state);
+       cx_read(MO_GP0_IO);
+}
+
+static int vp3054_bit_getscl(void *data)
+{
+       struct cx8802_dev *dev = data;
+       struct cx88_core *core = dev->core;
+       u32 state;
+
+       state = cx_read(MO_GP0_IO);
+       return (state & 0x01) ? 1 : 0;
+}
+
+static int vp3054_bit_getsda(void *data)
+{
+       struct cx8802_dev *dev = data;
+       struct cx88_core *core = dev->core;
+       u32 state;
+
+       state = cx_read(MO_GP0_IO);
+       return (state & 0x02) ? 1 : 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+       .setsda  = vp3054_bit_setsda,
+       .setscl  = vp3054_bit_setscl,
+       .getsda  = vp3054_bit_getsda,
+       .getscl  = vp3054_bit_getscl,
+       .udelay  = 16,
+       .mdelay  = 10,
+       .timeout = 200,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter vp3054_i2c_adap_template = {
+       .name              = "cx2388x",
+       .owner             = THIS_MODULE,
+       .id                = I2C_HW_B_CX2388x,
+};
+
+static struct i2c_client vp3054_i2c_client_template = {
+       .name   = "VP-3054",
+};
+
+int vp3054_i2c_probe(struct cx8802_dev *dev)
+{
+       struct cx88_core *core = dev->core;
+       struct vp3054_i2c_state *vp3054_i2c;
+       int rc;
+
+       if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+               return 0;
+
+       dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
+       if (dev->card_priv == NULL)
+               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));
+       memcpy(&vp3054_i2c->client, &vp3054_i2c_client_template,
+              sizeof(vp3054_i2c->client));
+
+       vp3054_i2c->adap.class |= I2C_CLASS_TV_DIGITAL;
+
+       vp3054_i2c->adap.dev.parent = &dev->pci->dev;
+       strlcpy(vp3054_i2c->adap.name, core->name,
+               sizeof(vp3054_i2c->adap.name));
+       vp3054_i2c->algo.data = dev;
+       i2c_set_adapdata(&vp3054_i2c->adap, dev);
+       vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
+       vp3054_i2c->client.adapter = &vp3054_i2c->adap;
+
+       vp3054_bit_setscl(dev,1);
+       vp3054_bit_setsda(dev,1);
+
+       rc = i2c_bit_add_bus(&vp3054_i2c->adap);
+       if (0 != rc) {
+               printk("%s: vp3054_i2c register FAILED\n", core->name);
+
+               kfree(dev->card_priv);
+               dev->card_priv = NULL;
+       }
+
+       return rc;
+}
+
+void vp3054_i2c_remove(struct cx8802_dev *dev)
+{
+       struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+       if (vp3054_i2c == NULL ||
+           dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+               return;
+
+       i2c_bit_del_bus(&vp3054_i2c->adap);
+       kfree(vp3054_i2c);
+}
+
+EXPORT_SYMBOL(vp3054_i2c_probe);
+EXPORT_SYMBOL(vp3054_i2c_remove);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h
new file mode 100644 (file)
index 0000000..b7a0a04
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+
+    cx88-vp3054-i2c.h  --  support for the secondary I2C bus of the
+                          DNTV Live! DVB-T Pro (VP-3054), wired as:
+                          GPIO[0] -> SCL, GPIO[1] -> SDA
+
+    (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+*/
+
+/* ----------------------------------------------------------------------- */
+struct vp3054_i2c_state {
+       struct i2c_adapter         adap;
+       struct i2c_algo_bit_data   algo;
+       struct i2c_client          client;
+       u32                        state;
+};
+
+/* ----------------------------------------------------------------------- */
+int  vp3054_i2c_probe(struct cx8802_dev *dev);
+void vp3054_i2c_remove(struct cx8802_dev *dev);
index 77beafc5c32764c81d67f89bdf3cfd784935a842..e9fd55b57fa61d3b691ee757f8f9388fcd1c1bd3 100644 (file)
@@ -179,6 +179,14 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_ATI_HDTVWONDER          34
 #define CX88_BOARD_WINFAST_DTV1000         35
 #define CX88_BOARD_AVERTV_303              36
+#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1  37
+#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1    38
+#define CX88_BOARD_KWORLD_DVBS_100         39
+#define CX88_BOARD_HAUPPAUGE_HVR1100       40
+#define CX88_BOARD_HAUPPAUGE_HVR1100LP     41
+#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO     42
+#define CX88_BOARD_KWORLD_DVB_T_CX22702    43
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -280,6 +288,9 @@ struct cx88_core {
        unsigned int               tda9887_conf;
        unsigned int               has_radio;
 
+       /* Supported V4L _STD_ tuner formats */
+       unsigned int               tuner_formats;
+
        /* config info -- dvb */
        struct dvb_pll_desc        *pll_desc;
        unsigned int               pll_addr;
@@ -301,6 +312,9 @@ struct cx88_core {
 
        /* various v4l controls */
        u32                        freq;
+
+       /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
+       struct cx8802_dev          *dvbdev;
 };
 
 struct cx8800_dev;
@@ -411,6 +425,8 @@ struct cx8802_dev {
        struct videobuf_dvb        dvb;
        void*                      fe_handle;
        int                        (*fe_release)(void *handle);
+
+       void                       *card_priv;
        /* for switching modulation types */
        unsigned char              ts_gen_cntrl;
 
@@ -447,7 +463,6 @@ struct cx8802_dev {
 
 extern void cx88_print_irqbits(char *name, char *tag, char **strings,
                               u32 bits, u32 mask);
-extern void cx88_print_ioctl(char *name, unsigned int cmd);
 
 extern int cx88_core_irq(struct cx88_core *core, u32 status);
 extern void cx88_wakeup(struct cx88_core *core,
index 57779e63f35d344264ac94395542b532eec92b1a..58f7b4194a0d51a6359475923c93c84e6583dad5 100644 (file)
@@ -30,6 +30,7 @@
 #include <media/tuner.h>
 #include <media/audiochip.h>
 #include <media/tveeprom.h>
+#include <media/v4l2-common.h>
 #include "msp3400.h"
 
 #include "em28xx.h"
@@ -261,7 +262,6 @@ void em28xx_card_setup(struct em28xx *dev)
        /* request some modules */
        if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
                struct tveeprom tv;
-               struct v4l2_audioout ao;
 #ifdef CONFIG_MODULES
                request_module("tveeprom");
                request_module("ir-kbd-i2c");
@@ -274,12 +274,8 @@ void em28xx_card_setup(struct em28xx *dev)
 
                dev->tuner_type= tv.tuner_type;
                if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+                       dev->i2s_speed=2048000;
                        dev->has_msp34xx=1;
-                       memset (&ao,0,sizeof(ao));
-
-                       ao.index=2;
-                       ao.mode=V4L2_AUDMODE_32BITS;
-                       em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao);
                } else
                        dev->has_msp34xx=0;
        }
index 0cfe75416ec64a7af3242ccec6e8e4722796f35a..dff3893f32fdaa18d940f5309bd18354dbc8b3e5 100644 (file)
@@ -32,7 +32,7 @@
 
 /* #define ENABLE_DEBUG_ISOC_FRAMES */
 
-static unsigned int core_debug;
+static unsigned int core_debug = 0;
 module_param(core_debug,int,0644);
 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
                printk(KERN_INFO "%s %s :"fmt, \
                         dev->name, __FUNCTION__ , ##arg); } while (0)
 
-static unsigned int reg_debug;
+static unsigned int reg_debug = 0;
 module_param(reg_debug,int,0644);
 MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
 
@@ -50,7 +50,7 @@ MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
                printk(KERN_INFO "%s %s :"fmt, \
                         dev->name, __FUNCTION__ , ##arg); } while (0)
 
-static unsigned int isoc_debug;
+static unsigned int isoc_debug = 0;
 module_param(isoc_debug,int,0644);
 MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
 
@@ -63,59 +63,6 @@ static int alt = EM28XX_PINOUT;
 module_param(alt, int, 0644);
 MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 
-/* ------------------------------------------------------------------ */
-/* debug help functions                                               */
-
-static const char *v4l1_ioctls[] = {
-       "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
-       "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
-       "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
-       "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
-       "SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
-       "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
-       "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
-       "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
-       "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
-       "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
-       "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
-       "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
-       "44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
-       "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
-       "S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void em28xx_print_ioctl(char *name, unsigned int cmd)
-{
-       char *dir;
-
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:              dir = "--"; break;
-       case _IOC_READ:              dir = "r-"; break;
-       case _IOC_WRITE:             dir = "-w"; break;
-       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-       default:                     dir = "??"; break;
-       }
-       switch (_IOC_TYPE(cmd)) {
-       case 'v':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
-                      name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-                      v4l1_ioctls[_IOC_NR(cmd)] : "???");
-               break;
-       case 'V':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
-                      name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
-                      v4l2_ioctls[_IOC_NR(cmd)] : "???");
-               break;
-       default:
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
-                      name, cmd, dir, _IOC_NR(cmd));
-       }
-}
-
 
 /*
  * em28xx_request_buffers()
@@ -126,7 +73,7 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
        const size_t imagesize = PAGE_ALIGN(dev->frame_size);   /*needs to be page aligned cause the buffers can be mapped individually! */
        void *buff = NULL;
        u32 i;
-       em28xx_coredbg("requested %i buffers with size %zd", count, imagesize);
+       em28xx_coredbg("requested %i buffers with size %zi", count, imagesize);
        if (count > EM28XX_NUM_FRAMES)
                count = EM28XX_NUM_FRAMES;
 
index d14bcf4ceaeae621fad398f63cc4f7f74f139189..0591a705b7a1f9aed6f9f113610c16f7578479f8 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/video_decoder.h>
 
 #include "em28xx.h"
+#include <media/v4l2-common.h>
 #include <media/tuner.h>
 
 /* ----------------------------------------------------------- */
@@ -486,9 +487,7 @@ static struct i2c_adapter em28xx_adap_template = {
        .inc_use = inc_use,
        .dec_use = dec_use,
 #endif
-#ifdef I2C_CLASS_TV_ANALOG
        .class = I2C_CLASS_TV_ANALOG,
-#endif
        .name = "em28xx",
        .id = I2C_HW_B_EM28XX,
        .algo = &em28xx_algo,
index 3a56120397aeb45791f36fe23fd14480ca64c84a..fdc255918ddef1e11d8416cb170ceb1baecd1a3f 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "em28xx.h"
 #include <media/tuner.h>
+#include <media/v4l2-common.h>
 
 #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
                      "Markus Rechberger <mrechberger@gmail.com>, " \
@@ -106,7 +107,31 @@ static const unsigned char saa7114_i2c_init[] = {
 #define TVNORMS ARRAY_SIZE(tvnorms)
 
 /* supported controls */
+/* Common to all boards */
 static struct v4l2_queryctrl em28xx_qctrl[] = {
+       {
+               .id = V4L2_CID_AUDIO_VOLUME,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Volume",
+               .minimum = 0x0,
+               .maximum = 0x1f,
+               .step = 0x1,
+               .default_value = 0x1f,
+               .flags = 0,
+       },{
+               .id = V4L2_CID_AUDIO_MUTE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Mute",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 1,
+               .flags = 0,
+       }
+};
+
+/* FIXME: These are specific to saa711x - should be moved to its code */
+static struct v4l2_queryctrl saa711x_qctrl[] = {
        {
                .id = V4L2_CID_BRIGHTNESS,
                .type = V4L2_CTRL_TYPE_INTEGER,
@@ -134,24 +159,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
                .step = 0x1,
                .default_value = 0x10,
                .flags = 0,
-       },{
-               .id = V4L2_CID_AUDIO_VOLUME,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Volume",
-               .minimum = 0x0,
-               .maximum = 0x1f,
-               .step = 0x1,
-               .default_value = 0x1f,
-               .flags = 0,
-       },{
-               .id = V4L2_CID_AUDIO_MUTE,
-               .type = V4L2_CTRL_TYPE_BOOLEAN,
-               .name = "Mute",
-               .minimum = 0,
-               .maximum = 1,
-               .step = 1,
-               .default_value = 1,
-               .flags = 0,
        },{
                .id = V4L2_CID_RED_BALANCE,
                .type = V4L2_CTRL_TYPE_INTEGER,
@@ -179,7 +186,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
                .step = 0x1,
                .default_value = 0x20,
                .flags = 0,
-        }
+       }
 };
 
 static struct usb_driver em28xx_usb_driver;
@@ -280,6 +287,8 @@ static void video_mux(struct em28xx *dev, int index)
        em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
 
        if (dev->has_msp34xx) {
+               if (dev->i2s_speed)
+                       em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
                em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
                ainput = EM28XX_AUDIO_SRC_TUNER;
                em28xx_audio_source(dev, ainput);
@@ -674,7 +683,6 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
  */
 static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
 {
-       s32 tmp;
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                ctrl->value = dev->mute;
@@ -682,6 +690,16 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_VOLUME:
                ctrl->value = dev->volume;
                return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+/*FIXME: should be moved to saa711x */
+static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+       s32 tmp;
+       switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                if ((tmp = em28xx_brightness_get(dev)) < 0)
                        return -EIO;
@@ -731,6 +749,15 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_VOLUME:
                dev->volume = ctrl->value;
                return em28xx_audio_analog_set(dev);
+       default:
+               return -EINVAL;
+       }
+}
+
+/*FIXME: should be moved to saa711x */
+static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+       switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                return em28xx_brightness_set(dev, ctrl->value);
        case V4L2_CID_CONTRAST:
@@ -994,14 +1021,34 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
        case VIDIOC_QUERYCTRL:
                {
                        struct v4l2_queryctrl *qc = arg;
-                       u8 i, n;
-                       n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
-                       for (i = 0; i < n; i++)
-                               if (qc->id && qc->id == em28xx_qctrl[i].id) {
-                                       memcpy(qc, &(em28xx_qctrl[i]),
+                       int i, id=qc->id;
+
+                       memset(qc,0,sizeof(*qc));
+                       qc->id=id;
+
+                       if (!dev->has_msp34xx) {
+                               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+                                       if (qc->id && qc->id == em28xx_qctrl[i].id) {
+                                               memcpy(qc, &(em28xx_qctrl[i]),
+                                               sizeof(*qc));
+                                               return 0;
+                                       }
+                               }
+                       }
+                       if (dev->decoder == EM28XX_TVP5150) {
+                               em28xx_i2c_call_clients(dev,cmd,qc);
+                               if (qc->type)
+                                       return 0;
+                               else
+                                       return -EINVAL;
+                       }
+                       for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
+                               if (qc->id && qc->id == saa711x_qctrl[i].id) {
+                                       memcpy(qc, &(saa711x_qctrl[i]),
                                               sizeof(*qc));
                                        return 0;
                                }
+                       }
 
                        return -EINVAL;
                }
@@ -1009,29 +1056,64 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
        case VIDIOC_G_CTRL:
                {
                        struct v4l2_control *ctrl = arg;
+                       int retval=-EINVAL;
 
+                       if (!dev->has_msp34xx)
+                               retval=em28xx_get_ctrl(dev, ctrl);
+                       if (retval==-EINVAL) {
+                               if (dev->decoder == EM28XX_TVP5150) {
+                                       em28xx_i2c_call_clients(dev,cmd,arg);
+                                       return 0;
+                               }
 
-                       return em28xx_get_ctrl(dev, ctrl);
+                               return saa711x_get_ctrl(dev, ctrl);
+                       } else return retval;
                }
 
-       case VIDIOC_S_CTRL_OLD: /* ??? */
        case VIDIOC_S_CTRL:
                {
                        struct v4l2_control *ctrl = arg;
-                       u8 i, n;
-
-
-                       n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
-                       for (i = 0; i < n; i++)
-                               if (ctrl->id == em28xx_qctrl[i].id) {
-                                       if (ctrl->value <
-                                           em28xx_qctrl[i].minimum
-                                           || ctrl->value >
-                                           em28xx_qctrl[i].maximum)
-                                               return -ERANGE;
+                       u8 i;
+
+                       if (!dev->has_msp34xx){
+                               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+                                       if (ctrl->id == em28xx_qctrl[i].id) {
+                                               if (ctrl->value <
+                                               em28xx_qctrl[i].minimum
+                                               || ctrl->value >
+                                               em28xx_qctrl[i].maximum)
+                                                       return -ERANGE;
+                                               return em28xx_set_ctrl(dev, ctrl);
+                                       }
+                               }
+                       }
 
-                                       return em28xx_set_ctrl(dev, ctrl);
+                       if (dev->decoder == EM28XX_TVP5150) {
+                               em28xx_i2c_call_clients(dev,cmd,arg);
+                               return 0;
+                       } else if (!dev->has_msp34xx) {
+                               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+                                       if (ctrl->id == em28xx_qctrl[i].id) {
+                                               if (ctrl->value <
+                                               em28xx_qctrl[i].minimum
+                                               || ctrl->value >
+                                               em28xx_qctrl[i].maximum)
+                                                       return -ERANGE;
+                                               return em28xx_set_ctrl(dev, ctrl);
+                                       }
                                }
+                               for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
+                                       if (ctrl->id == saa711x_qctrl[i].id) {
+                                               if (ctrl->value <
+                                               saa711x_qctrl[i].minimum
+                                               || ctrl->value >
+                                               saa711x_qctrl[i].maximum)
+                                                       return -ERANGE;
+                                               return saa711x_set_ctrl(dev, ctrl);
+                                       }
+                               }
+                       }
+
                        return -EINVAL;
                }
 
@@ -1187,7 +1269,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
                return -ENODEV;
 
        if (video_debug > 1)
-               em28xx_print_ioctl(dev->name,cmd);
+               v4l_print_ioctl(dev->name,cmd);
 
        switch (cmd) {
 
@@ -1564,6 +1646,8 @@ static struct file_operations em28xx_v4l_fops = {
        .poll = em28xx_v4l2_poll,
        .mmap = em28xx_v4l2_mmap,
        .llseek = no_llseek,
+       .compat_ioctl   = v4l_compat_ioctl32,
+
 };
 
 /******************************** usb interface *****************************************/
@@ -1848,9 +1932,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
        struct em28xx *dev = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
 
+/*FIXME: IR should be disconnected */
+
        if (!dev)
                return;
 
+
        down_write(&em28xx_disconnect);
 
        down(&dev->lock);
index 5c7a41ce69f37c69daaa441134a4c0fab301f304..33de9d846af5ed1cd1311784ad19daf928c00298 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+   em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices
 
    Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
                      Ludovico Cavedon <cavedon@sssup.it>
@@ -216,6 +216,8 @@ struct em28xx {
        unsigned int has_msp34xx:1;
        unsigned int has_tda9887:1;
 
+       u32 i2s_speed;          /* I2S speed for audio digital stream */
+
        enum em28xx_decoder decoder;
 
        int tuner_type;         /* type of the tuner */
@@ -293,8 +295,6 @@ void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
 
 /* Provided by em28xx-core.c */
 
-void em28xx_print_ioctl(char *name, unsigned int cmd);
-
 u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
 void em28xx_queue_unusedframes(struct em28xx *dev);
 void em28xx_release_buffers(struct em28xx *dev);
index 3cc1d6a6019bf8f1b090c748e184ab0fe4072601..58b0e698282206e0e028423d202be8c24d5db35c 100644 (file)
@@ -279,7 +279,7 @@ static int ir_probe(struct i2c_adapter *adap);
 
 static struct i2c_driver driver = {
        .driver = {
-               .name   = "ir remote kbd driver",
+               .name   = "ir-kbd-i2c",
        },
        .id             = I2C_DRIVERID_INFRARED,
        .attach_adapter = ir_probe,
@@ -304,18 +304,20 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
        ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!ir || !input_dev) {
-               kfree(ir);
                input_free_device(input_dev);
+               kfree(ir);
                return -ENOMEM;
        }
+       memset(ir,0,sizeof(*ir));
 
        ir->c = client_template;
        ir->input = input_dev;
 
-       i2c_set_clientdata(&ir->c, ir);
        ir->c.adapter = adap;
        ir->c.addr    = addr;
 
+       i2c_set_clientdata(&ir->c, ir);
+
        switch(addr) {
        case 0x64:
                name        = "Pixelview";
@@ -378,13 +380,15 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                 ir->c.dev.bus_id);
 
        /* init + register input device */
-       ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
-       input_dev->id.bustype   = BUS_I2C;
-       input_dev->name         = ir->c.name;
-       input_dev->phys         = ir->phys;
+       ir_input_init(input_dev,&ir->ir,ir_type,ir->ir_codes);
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->name       = ir->c.name;
+       input_dev->phys       = ir->phys;
 
        /* register event device */
        input_register_device(ir->input);
+       printk(DEVNAME ": %s detected at %s [%s]\n",
+              ir->input->name,ir->input->phys,adap->name);
 
        /* start polling via eventd */
        INIT_WORK(&ir->work, ir_work, ir);
index 3f2a882bc20a6a6b31b00af7bef5278596f253db..2869464aee0d699677efccf99593dcdeb11526d3 100644 (file)
@@ -1754,6 +1754,7 @@ static struct file_operations meye_fops = {
        .release        = meye_release,
        .mmap           = meye_mmap,
        .ioctl          = meye_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .poll           = meye_poll,
        .llseek         = no_llseek,
 };
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
new file mode 100644 (file)
index 0000000..aa8c556
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+ * Programming the mspx4xx sound processor family
+ *
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * what works and what doesn't:
+ *
+ *  AM-Mono
+ *      Support for Hauppauge cards added (decoding handled by tuner) added by
+ *      Frederic Crozat <fcrozat@mail.dotcom.fr>
+ *
+ *  FM-Mono
+ *      should work. The stereo modes are backward compatible to FM-mono,
+ *      therefore FM-Mono should be allways available.
+ *
+ *  FM-Stereo (B/G, used in germany)
+ *      should work, with autodetect
+ *
+ *  FM-Stereo (satellite)
+ *      should work, no autodetect (i.e. default is mono, but you can
+ *      switch to stereo -- untested)
+ *
+ *  NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
+ *      should work, with autodetect. Support for NICAM was added by
+ *      Pekka Pietikainen <pp@netppl.fi>
+ *
+ * TODO:
+ *   - better SAT support
+ *
+ * 980623  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *         using soundcore instead of OSS
+ *
+ * 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+#include "msp3400.h"
+
+/* ---------------------------------------------------------------------- */
+
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
+/* module parameters */
+static int opmode   = OPMODE_AUTO;
+int debug    = 0;    /* debug output */
+int once     = 0;    /* no continous stereo monitoring */
+int amsound  = 0;    /* hard-wire AM sound at 6.5 Hz (france),
+                              the autoscan seems work well only with FM... */
+int standard = 1;    /* Override auto detect of audio standard, if needed. */
+int dolby    = 0;
+
+int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
+                                       (msp34xxg only) 0x00a0-0x03c0 */
+
+/* read-only */
+module_param(opmode,           int, 0444);
+
+/* read-write */
+module_param(once,             bool, 0644);
+module_param(debug,            int, 0644);
+module_param(stereo_threshold, int, 0644);
+module_param(standard,         int, 0644);
+module_param(amsound,          bool, 0644);
+module_param(dolby,            bool, 0644);
+
+MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
+MODULE_PARM_DESC(once, "No continuous stereo monitoring");
+MODULE_PARM_DESC(debug, "Enable debug messages [0-3]");
+MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
+MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
+MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
+MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
+
+/* ---------------------------------------------------------------------- */
+
+/* control subaddress */
+#define I2C_MSP_CONTROL 0x00
+/* demodulator unit subaddress */
+#define I2C_MSP_DEM     0x10
+/* DSP unit subaddress */
+#define I2C_MSP_DSP     0x12
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+/* functions for talking to the MSP3400C Sound processor                   */
+
+int msp_reset(struct i2c_client *client)
+{
+       /* reset and read revision code */
+       static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 };
+       static u8 reset_on[3]  = { I2C_MSP_CONTROL, 0x00, 0x00 };
+       static u8 write[3]     = { I2C_MSP_DSP + 1, 0x00, 0x1e };
+       u8 read[2];
+       struct i2c_msg reset[2] = {
+               { client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
+               { client->addr, I2C_M_IGNORE_NAK, 3, reset_on  },
+       };
+       struct i2c_msg test[2] = {
+               { client->addr, 0,        3, write },
+               { client->addr, I2C_M_RD, 2, read  },
+       };
+
+       v4l_dbg(3, client, "msp_reset\n");
+       if (i2c_transfer(client->adapter, &reset[0], 1) != 1 ||
+           i2c_transfer(client->adapter, &reset[1], 1) != 1 ||
+           i2c_transfer(client->adapter, test, 2) != 2) {
+               v4l_err(client, "chip reset failed\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int msp_read(struct i2c_client *client, int dev, int addr)
+{
+       int err, retval;
+       u8 write[3];
+       u8 read[2];
+       struct i2c_msg msgs[2] = {
+               { client->addr, 0,        3, write },
+               { client->addr, I2C_M_RD, 2, read  }
+       };
+
+       write[0] = dev + 1;
+       write[1] = addr >> 8;
+       write[2] = addr & 0xff;
+
+       for (err = 0; err < 3; err++) {
+               if (i2c_transfer(client->adapter, msgs, 2) == 2)
+                       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));
+       }
+       if (err == 3) {
+               v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+               msp_reset(client);
+               return -1;
+       }
+       retval = read[0] << 8 | read[1];
+       v4l_dbg(3, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+       return retval;
+}
+
+int msp_read_dem(struct i2c_client *client, int addr)
+{
+       return msp_read(client, I2C_MSP_DEM, addr);
+}
+
+int msp_read_dsp(struct i2c_client *client, int addr)
+{
+       return msp_read(client, I2C_MSP_DSP, addr);
+}
+
+static int msp_write(struct i2c_client *client, int dev, int addr, int val)
+{
+       int err;
+       u8 buffer[5];
+
+       buffer[0] = dev;
+       buffer[1] = addr >> 8;
+       buffer[2] = addr &  0xff;
+       buffer[3] = val  >> 8;
+       buffer[4] = val  &  0xff;
+
+       v4l_dbg(3, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
+       for (err = 0; err < 3; err++) {
+               if (i2c_master_send(client, buffer, 5) == 5)
+                       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));
+       }
+       if (err == 3) {
+               v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+               msp_reset(client);
+               return -1;
+       }
+       return 0;
+}
+
+int msp_write_dem(struct i2c_client *client, int addr, int val)
+{
+       return msp_write(client, I2C_MSP_DEM, addr, val);
+}
+
+int msp_write_dsp(struct i2c_client *client, int addr, int val)
+{
+       return msp_write(client, I2C_MSP_DSP, addr, val);
+}
+
+/* ----------------------------------------------------------------------- *
+ * bits  9  8  5 - SCART DSP input Select:
+ *       0  0  0 - SCART 1 to DSP input (reset position)
+ *       0  1  0 - MONO to DSP input
+ *       1  0  0 - SCART 2 to DSP input
+ *       1  1  1 - Mute DSP input
+ *
+ * bits 11 10  6 - SCART 1 Output Select:
+ *       0  0  0 - undefined (reset position)
+ *       0  1  0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
+ *       1  0  0 - MONO input to SCART 1 Output
+ *       1  1  0 - SCART 1 DA to SCART 1 Output
+ *       0  0  1 - SCART 2 DA to SCART 1 Output
+ *       0  1  1 - SCART 1 Input to SCART 1 Output
+ *       1  1  1 - Mute SCART 1 Output
+ *
+ * bits 13 12  7 - SCART 2 Output Select (for devices with 2 Output SCART):
+ *       0  0  0 - SCART 1 DA to SCART 2 Output (reset position)
+ *       0  1  0 - SCART 1 Input to SCART 2 Output
+ *       1  0  0 - MONO input to SCART 2 Output
+ *       0  0  1 - SCART 2 DA to SCART 2 Output
+ *       0  1  1 - SCART 2 Input to SCART 2 Output
+ *       1  1  0 - Mute SCART 2 Output
+ *
+ * Bits 4 to 0 should be zero.
+ * ----------------------------------------------------------------------- */
+
+static int scarts[3][9] = {
+       /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
+       /* SCART DSP Input select */
+       { 0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
+       /* SCART1 Output select */
+       { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+       /* SCART2 Output select */
+       { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+};
+
+static char *scart_names[] = {
+       "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+};
+
+void msp_set_scart(struct i2c_client *client, int in, int out)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       state->in_scart=in;
+
+       if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
+               if (-1 == scarts[out][in])
+                       return;
+
+               state->acb &= ~scarts[out][SCART_MASK];
+               state->acb |=  scarts[out][in];
+       } else
+               state->acb = 0xf60; /* Mute Input and SCART 1 Output */
+
+       v4l_dbg(1, client, "scart switch: %s => %d (ACB=0x%04x)\n",
+                                               scart_names[in], out, state->acb);
+       msp_write_dsp(client, 0x13, state->acb);
+
+       /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+       msp_write_dem(client, 0x40, state->i2s_mode);
+}
+
+void msp_set_mute(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       v4l_dbg(1, client, "mute audio\n");
+       msp_write_dsp(client, 0x0000, 0);
+       msp_write_dsp(client, 0x0007, 1);
+       if (state->has_scart2_out_volume)
+               msp_write_dsp(client, 0x0040, 1);
+       if (state->has_headphones)
+               msp_write_dsp(client, 0x0006, 0);
+}
+
+void msp_set_audio(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+       int bal = 0, bass, treble, loudness;
+       int val = 0;
+
+       if (!state->muted)
+               val = (state->volume * 0x7f / 65535) << 8;
+
+       v4l_dbg(1, client, "mute=%s volume=%d\n",
+               state->muted ? "on" : "off", state->volume);
+
+       msp_write_dsp(client, 0x0000, val);
+       msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1));
+       if (state->has_scart2_out_volume)
+               msp_write_dsp(client, 0x0040, state->muted ? 0x1 : (val | 0x1));
+       if (state->has_headphones)
+               msp_write_dsp(client, 0x0006, val);
+       if (!state->has_sound_processing)
+               return;
+
+       if (val)
+               bal = (u8)((state->balance / 256) - 128);
+       bass = ((state->bass - 32768) * 0x60 / 65535) << 8;
+       treble = ((state->treble - 32768) * 0x60 / 65535) << 8;
+       loudness = state->loudness ? ((5 * 4) << 8) : 0;
+
+       v4l_dbg(1, client, "balance=%d bass=%d treble=%d loudness=%d\n",
+               state->balance, state->bass, state->treble, state->loudness);
+
+       msp_write_dsp(client, 0x0001, bal << 8);
+       msp_write_dsp(client, 0x0002, bass);
+       msp_write_dsp(client, 0x0003, treble);
+       msp_write_dsp(client, 0x0004, loudness);
+       if (!state->has_headphones)
+               return;
+       msp_write_dsp(client, 0x0030, bal << 8);
+       msp_write_dsp(client, 0x0031, bass);
+       msp_write_dsp(client, 0x0032, treble);
+       msp_write_dsp(client, 0x0033, loudness);
+}
+
+int msp_modus(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       if (state->radio) {
+               v4l_dbg(1, client, "video mode selected to Radio\n");
+               return 0x0003;
+       }
+
+       if (state->v4l2_std & V4L2_STD_PAL) {
+               v4l_dbg(1, client, "video mode selected to PAL\n");
+
+#if 1
+               /* experimental: not sure this works with all chip versions */
+               return 0x7003;
+#else
+               /* previous value, try this if it breaks ... */
+               return 0x1003;
+#endif
+       }
+       if (state->v4l2_std & V4L2_STD_NTSC) {
+               v4l_dbg(1, client, "video mode selected to NTSC\n");
+               return 0x2003;
+       }
+       if (state->v4l2_std & V4L2_STD_SECAM) {
+               v4l_dbg(1, client, "video mode selected to SECAM\n");
+               return 0x0003;
+       }
+       return 0x0003;
+}
+
+/* ------------------------------------------------------------------------ */
+
+
+static void msp_wake_thread(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       if (NULL == state->kthread)
+               return;
+       msp_set_mute(client);
+       state->watch_stereo = 0;
+       state->restart = 1;
+       wake_up_interruptible(&state->wq);
+}
+
+int msp_sleep(struct msp_state *state, int timeout)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(&state->wq, &wait);
+       if (!kthread_should_stop()) {
+               if (timeout < 0) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule();
+               } else {
+                       schedule_timeout_interruptible
+                                               (msecs_to_jiffies(timeout));
+               }
+       }
+
+       remove_wait_queue(&state->wq, &wait);
+       try_to_freeze();
+       return state->restart;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int msp_mode_v4l2_to_v4l1(int rxsubchans)
+{
+       int mode = 0;
+
+       if (rxsubchans & V4L2_TUNER_SUB_STEREO)
+               mode |= VIDEO_SOUND_STEREO;
+       if (rxsubchans & V4L2_TUNER_SUB_LANG2)
+               mode |= VIDEO_SOUND_LANG2;
+       if (rxsubchans & V4L2_TUNER_SUB_LANG1)
+               mode |= VIDEO_SOUND_LANG1;
+       if (mode == 0)
+               mode |= VIDEO_SOUND_MONO;
+       return mode;
+}
+
+static int msp_mode_v4l1_to_v4l2(int mode)
+{
+       if (mode & VIDEO_SOUND_STEREO)
+               return V4L2_TUNER_MODE_STEREO;
+       if (mode & VIDEO_SOUND_LANG2)
+               return V4L2_TUNER_MODE_LANG2;
+       if (mode & VIDEO_SOUND_LANG1)
+               return V4L2_TUNER_MODE_LANG1;
+       return V4L2_TUNER_MODE_MONO;
+}
+
+static void msp_any_detect_stereo(struct i2c_client *client)
+{
+       struct msp_state *state  = i2c_get_clientdata(client);
+
+       switch (state->opmode) {
+       case OPMODE_MANUAL:
+       case OPMODE_AUTODETECT:
+               autodetect_stereo(client);
+               break;
+       case OPMODE_AUTOSELECT:
+               msp34xxg_detect_stereo(client);
+               break;
+       }
+}
+
+static struct v4l2_queryctrl msp_qctrl_std[] = {
+       {
+               .id            = V4L2_CID_AUDIO_VOLUME,
+               .name          = "Volume",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 58880,
+               .flags         = 0,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_AUDIO_MUTE,
+               .name          = "Mute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 1,
+               .default_value = 1,
+               .flags         = 0,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },
+};
+
+static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
+       {
+               .id            = V4L2_CID_AUDIO_BALANCE,
+               .name          = "Balance",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+               .flags         = 0,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_AUDIO_BASS,
+               .name          = "Bass",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_AUDIO_TREBLE,
+               .name          = "Treble",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_AUDIO_LOUDNESS,
+               .name          = "Loudness",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 1,
+               .default_value = 1,
+               .flags         = 0,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },
+};
+
+
+static void msp_any_set_audmode(struct i2c_client *client, int audmode)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       switch (state->opmode) {
+       case OPMODE_MANUAL:
+       case OPMODE_AUTODETECT:
+               state->watch_stereo = 0;
+               msp3400c_setstereo(client, audmode);
+               break;
+       case OPMODE_AUTOSELECT:
+               msp34xxg_set_audmode(client, audmode);
+               break;
+       }
+}
+
+static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               ctrl->value = state->volume;
+               break;
+
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = state->muted;
+               break;
+
+       case V4L2_CID_AUDIO_BALANCE:
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               ctrl->value = state->balance;
+               break;
+
+       case V4L2_CID_AUDIO_BASS:
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               ctrl->value = state->bass;
+               break;
+
+       case V4L2_CID_AUDIO_TREBLE:
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               ctrl->value = state->treble;
+               break;
+
+       case V4L2_CID_AUDIO_LOUDNESS:
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               ctrl->value = state->loudness;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               state->volume = ctrl->value;
+               if (state->volume == 0)
+                       state->balance = 32768;
+               break;
+
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value < 0 || ctrl->value >= 2)
+                       return -ERANGE;
+               state->muted = ctrl->value;
+               break;
+
+       case V4L2_CID_AUDIO_BASS:
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               state->bass = ctrl->value;
+               break;
+
+       case V4L2_CID_AUDIO_TREBLE:
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               state->treble = ctrl->value;
+               break;
+
+       case V4L2_CID_AUDIO_LOUDNESS:
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               state->loudness = ctrl->value;
+               break;
+
+       case V4L2_CID_AUDIO_BALANCE:
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               state->balance = ctrl->value;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       msp_set_audio(client);
+       return 0;
+}
+
+static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+       u16 *sarg = arg;
+       int scart = 0;
+
+       if (debug >= 2)
+               v4l_i2c_print_ioctl(client, cmd);
+
+       switch (cmd) {
+       case AUDC_SET_INPUT:
+               if (*sarg == state->input)
+                       break;
+               state->input = *sarg;
+               switch (*sarg) {
+               case AUDIO_RADIO:
+                       /* Hauppauge uses IN2 for the radio */
+                       state->mode = MSP_MODE_FM_RADIO;
+                       scart       = SCART_IN2;
+                       break;
+               case AUDIO_EXTERN_1:
+                       /* IN1 is often used for external input ... */
+                       state->mode = MSP_MODE_EXTERN;
+                       scart       = SCART_IN1;
+                       break;
+               case AUDIO_EXTERN_2:
+                       /* ... sometimes it is IN2 through ;) */
+                       state->mode = MSP_MODE_EXTERN;
+                       scart       = SCART_IN2;
+                       break;
+               case AUDIO_TUNER:
+                       state->mode = -1;
+                       break;
+               default:
+                       if (*sarg & AUDIO_MUTE)
+                               msp_set_scart(client, SCART_MUTE, 0);
+                       break;
+               }
+               if (scart) {
+                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       state->audmode = V4L2_TUNER_MODE_STEREO;
+                       msp_set_scart(client, scart, 0);
+                       msp_write_dsp(client, 0x000d, 0x1900);
+                       if (state->opmode != OPMODE_AUTOSELECT)
+                               msp3400c_setstereo(client, state->audmode);
+               }
+               msp_wake_thread(client);
+               break;
+
+       case AUDC_SET_RADIO:
+               if (state->radio)
+                       return 0;
+               state->radio = 1;
+               v4l_dbg(1, client, "switching to radio mode\n");
+               state->watch_stereo = 0;
+               switch (state->opmode) {
+               case OPMODE_MANUAL:
+                       /* set msp3400 to FM radio mode */
+                       msp3400c_setmode(client, MSP_MODE_FM_RADIO);
+                       msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+                                           MSP_CARRIER(10.7));
+                       msp_set_audio(client);
+                       break;
+               case OPMODE_AUTODETECT:
+               case OPMODE_AUTOSELECT:
+                       /* the thread will do for us */
+                       msp_wake_thread(client);
+                       break;
+               }
+               break;
+
+       /* --- v4l ioctls --- */
+       /* take care: bttv does userspace copying, we'll get a
+          kernel pointer here... */
+       case VIDIOCGAUDIO:
+       {
+               struct video_audio *va = arg;
+
+               va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE;
+               if (state->has_sound_processing)
+                       va->flags |= VIDEO_AUDIO_BALANCE |
+                               VIDEO_AUDIO_BASS |
+                               VIDEO_AUDIO_TREBLE;
+               if (state->muted)
+                       va->flags |= VIDEO_AUDIO_MUTE;
+               va->volume = state->volume;
+               va->balance = state->volume ? state->balance : 32768;
+               va->bass = state->bass;
+               va->treble = state->treble;
+
+               if (state->radio)
+                       break;
+               if (state->opmode == OPMODE_AUTOSELECT)
+                       msp_any_detect_stereo(client);
+               va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans);
+               break;
+       }
+
+       case VIDIOCSAUDIO:
+       {
+               struct video_audio *va = arg;
+
+               state->muted = (va->flags & VIDEO_AUDIO_MUTE);
+               state->volume = va->volume;
+               state->balance = va->balance;
+               state->bass = va->bass;
+               state->treble = va->treble;
+               msp_set_audio(client);
+
+               if (va->mode != 0 && state->radio == 0)
+                       msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));
+               break;
+       }
+
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *vc = arg;
+               int update = 0;
+               v4l2_std_id std;
+
+               if (state->radio)
+                       update = 1;
+               state->radio = 0;
+               if (vc->norm == VIDEO_MODE_PAL)
+                       std = V4L2_STD_PAL;
+               else if (vc->norm == VIDEO_MODE_SECAM)
+                       std = V4L2_STD_SECAM;
+               else
+                       std = V4L2_STD_NTSC;
+               if (std != state->v4l2_std) {
+                       state->v4l2_std = std;
+                       update = 1;
+               }
+               if (update)
+                       msp_wake_thread(client);
+               break;
+       }
+
+       case VIDIOCSFREQ:
+       case VIDIOC_S_FREQUENCY:
+       {
+               /* new channel -- kick audio carrier scan */
+               msp_wake_thread(client);
+               break;
+       }
+
+       /* msp34xx specific */
+       case MSP_SET_MATRIX:
+       {
+               struct msp_matrix *mspm = arg;
+
+               msp_set_scart(client, mspm->input, mspm->output);
+               break;
+       }
+
+       /* --- v4l2 ioctls --- */
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *id = arg;
+               int update = state->radio || state->v4l2_std != *id;
+
+               state->v4l2_std = *id;
+               state->radio = 0;
+               if (update)
+                       msp_wake_thread(client);
+               return 0;
+       }
+
+       case VIDIOC_ENUMINPUT:
+       {
+               struct v4l2_input *i = arg;
+
+               if (i->index != 0)
+                       return -EINVAL;
+
+               i->type = V4L2_INPUT_TYPE_TUNER;
+               switch (i->index) {
+               case AUDIO_RADIO:
+                       strcpy(i->name, "Radio");
+                       break;
+               case AUDIO_EXTERN_1:
+                       strcpy(i->name, "Extern 1");
+                       break;
+               case AUDIO_EXTERN_2:
+                       strcpy(i->name, "Extern 2");
+                       break;
+               case AUDIO_TUNER:
+                       strcpy(i->name, "Television");
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               return 0;
+       }
+
+       case VIDIOC_G_AUDIO:
+       {
+               struct v4l2_audio *a = arg;
+
+               memset(a, 0, sizeof(*a));
+
+               switch (a->index) {
+               case AUDIO_RADIO:
+                       strcpy(a->name, "Radio");
+                       break;
+               case AUDIO_EXTERN_1:
+                       strcpy(a->name, "Extern 1");
+                       break;
+               case AUDIO_EXTERN_2:
+                       strcpy(a->name, "Extern 2");
+                       break;
+               case AUDIO_TUNER:
+                       strcpy(a->name, "Television");
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               msp_any_detect_stereo(client);
+               if (state->audmode == V4L2_TUNER_MODE_STEREO) {
+                       a->capability = V4L2_AUDCAP_STEREO;
+               }
+
+               break;
+       }
+
+       case VIDIOC_S_AUDIO:
+       {
+               struct v4l2_audio *sarg = arg;
+
+               switch (sarg->index) {
+               case AUDIO_RADIO:
+                       /* Hauppauge uses IN2 for the radio */
+                       state->mode = MSP_MODE_FM_RADIO;
+                       scart       = SCART_IN2;
+                       break;
+               case AUDIO_EXTERN_1:
+                       /* IN1 is often used for external input ... */
+                       state->mode = MSP_MODE_EXTERN;
+                       scart       = SCART_IN1;
+                       break;
+               case AUDIO_EXTERN_2:
+                       /* ... sometimes it is IN2 through ;) */
+                       state->mode = MSP_MODE_EXTERN;
+                       scart       = SCART_IN2;
+                       break;
+               case AUDIO_TUNER:
+                       state->mode = -1;
+                       break;
+               }
+               if (scart) {
+                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       state->audmode = V4L2_TUNER_MODE_STEREO;
+                       msp_set_scart(client, scart, 0);
+                       msp_write_dsp(client, 0x000d, 0x1900);
+               }
+               if (sarg->capability == V4L2_AUDCAP_STEREO) {
+                       state->audmode = V4L2_TUNER_MODE_STEREO;
+               } else {
+                       state->audmode &= ~V4L2_TUNER_MODE_STEREO;
+               }
+               msp_any_set_audmode(client, state->audmode);
+               msp_wake_thread(client);
+               break;
+       }
+
+       case VIDIOC_G_TUNER:
+       {
+               struct v4l2_tuner *vt = arg;
+
+               if (state->radio)
+                       break;
+               if (state->opmode == OPMODE_AUTOSELECT)
+                       msp_any_detect_stereo(client);
+               vt->audmode    = state->audmode;
+               vt->rxsubchans = state->rxsubchans;
+               vt->capability = V4L2_TUNER_CAP_STEREO |
+                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+               break;
+       }
+
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+
+               if (state->radio)
+                       break;
+               /* only set audmode */
+               if (vt->audmode != -1 && vt->audmode != 0)
+                       msp_any_set_audmode(client, vt->audmode);
+               break;
+       }
+
+       case VIDIOC_G_AUDOUT:
+       {
+               struct v4l2_audioout *a = (struct v4l2_audioout *)arg;
+               int idx = a->index;
+
+               memset(a, 0, sizeof(*a));
+
+               switch (idx) {
+               case 0:
+                       strcpy(a->name, "Scart1 Out");
+                       break;
+               case 1:
+                       strcpy(a->name, "Scart2 Out");
+                       break;
+               case 2:
+                       strcpy(a->name, "I2S Out");
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       }
+
+       case VIDIOC_S_AUDOUT:
+       {
+               struct v4l2_audioout *a = (struct v4l2_audioout *)arg;
+
+               if (a->index < 0 || a->index > 2)
+                       return -EINVAL;
+
+               v4l_dbg(1, client, "Setting audio out on msp34xx to input %i\n", a->index);
+               msp_set_scart(client, state->in_scart, a->index + 1);
+
+               break;
+       }
+
+       case VIDIOC_INT_I2S_CLOCK_FREQ:
+       {
+               u32 *a = (u32 *)arg;
+
+               v4l_dbg(1, client, "Setting I2S speed to %d\n", *a);
+
+               switch (*a) {
+                       case 1024000:
+                               state->i2s_mode = 0;
+                               break;
+                       case 2048000:
+                               state->i2s_mode = 1;
+                               break;
+                       default:
+                               return -EINVAL;
+               }
+               break;
+       }
+
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *qc = arg;
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)
+                       if (qc->id && qc->id == msp_qctrl_std[i].id) {
+                               memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));
+                               return 0;
+                       }
+               if (!state->has_sound_processing)
+                       return -EINVAL;
+               for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)
+                       if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {
+                               memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));
+                               return 0;
+                       }
+               return -EINVAL;
+       }
+
+       case VIDIOC_G_CTRL:
+               return msp_get_ctrl(client, arg);
+
+       case VIDIOC_S_CTRL:
+               return msp_set_ctrl(client, arg);
+
+       case VIDIOC_LOG_STATUS:
+       {
+               const char *p;
+
+               if (state->opmode == OPMODE_AUTOSELECT)
+                       msp_any_detect_stereo(client);
+               v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
+                               client->name, state->rev1, state->rev2);
+               v4l_info(client, "Audio:    volume %d%s\n",
+                               state->volume, state->muted ? " (muted)" : "");
+               if (state->has_sound_processing) {
+                       v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",
+                                       state->balance, state->bass, state->treble,
+                                       state->loudness ? "on" : "off");
+               }
+               switch (state->mode) {
+               case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
+               case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
+               case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break;
+               case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
+               case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
+               case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
+               case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break;
+               case MSP_MODE_BTSC: p = "BTSC"; break;
+               case MSP_MODE_EXTERN: p = "External input"; break;
+               default: p = "unknown"; break;
+               }
+               if (state->opmode == OPMODE_MANUAL) {
+                       v4l_info(client, "Mode:     %s (%s%s)\n", p,
+                               (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
+                               (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
+               } else {
+                       v4l_info(client, "Mode:     %s\n", p);
+                       v4l_info(client, "Standard: %s (%s%s)\n",
+                               msp_standard_std_name(state->std),
+                               (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
+                               (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
+               }
+               v4l_info(client, "ACB:      0x%04x\n", state->acb);
+               break;
+       }
+
+       default:
+               /* nothing */
+               break;
+       }
+       return 0;
+}
+
+static int msp_suspend(struct device * dev, pm_message_t state)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+       v4l_dbg(1, client, "suspend\n");
+       msp_reset(client);
+       return 0;
+}
+
+static int msp_resume(struct device * dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+       v4l_dbg(1, client, "resume\n");
+       msp_wake_thread(client);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver;
+
+static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *client;
+       struct msp_state *state;
+       int (*thread_func)(void *data) = NULL;
+       int msp_hard;
+       int msp_family;
+       int msp_revision;
+       int msp_product, msp_prod_hi, msp_prod_lo;
+       int msp_rom;
+
+       client = kmalloc(sizeof(*client), GFP_KERNEL);
+       if (client == NULL)
+               return -ENOMEM;
+       memset(client, 0, sizeof(*client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver;
+       snprintf(client->name, sizeof(client->name) - 1, "msp3400");
+
+       if (msp_reset(client) == -1) {
+               v4l_dbg(1, client, "msp3400 not found\n");
+               kfree(client);
+               return -1;
+       }
+
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(client, state);
+
+       memset(state, 0, sizeof(*state));
+       state->v4l2_std = V4L2_STD_NTSC;
+       state->volume = 58880;  /* 0db gain */
+       state->balance = 32768; /* 0db gain */
+       state->bass = 32768;
+       state->treble = 32768;
+       state->loudness = 0;
+       state->input = -1;
+       state->muted = 0;
+       state->i2s_mode = 0;
+       init_waitqueue_head(&state->wq);
+
+       state->rev1 = msp_read_dsp(client, 0x1e);
+       if (state->rev1 != -1)
+               state->rev2 = msp_read_dsp(client, 0x1f);
+       v4l_dbg(1, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2);
+       if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
+               v4l_dbg(1, client, "not an msp3400 (cannot read chip version)\n");
+               kfree(state);
+               kfree(client);
+               return -1;
+       }
+
+       msp_set_audio(client);
+
+       msp_family = ((state->rev1 >> 4) & 0x0f) + 3;
+       msp_product = (state->rev2 >> 8) & 0xff;
+       msp_prod_hi = msp_product / 10;
+       msp_prod_lo = msp_product % 10;
+       msp_revision = (state->rev1 & 0x0f) + '@';
+       msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
+       msp_rom = state->rev2 & 0x1f;
+       snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
+                       msp_family, msp_product,
+                       msp_revision, msp_hard, msp_rom);
+
+       /* Has NICAM support: all mspx41x and mspx45x products have NICAM */
+       state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
+       /* Has radio support: was added with revision G */
+       state->has_radio = msp_revision >= 'G';
+       /* Has headphones output: not for stripped down products */
+       state->has_headphones = msp_prod_lo < 5;
+       /* Has scart4 input: not in pre D revisions, not in stripped D revs */
+       state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
+       /* Has scart2 and scart3 inputs and scart2 output: not in stripped
+          down products of the '3' family */
+       state->has_scart23_in_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
+       /* Has scart2 a volume control? Not in pre-D revisions. */
+       state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart23_in_scart2_out;
+       /* Has a configurable i2s out? */
+       state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7;
+       /* Has subwoofer output: not in pre-D revs and not in stripped down products */
+       state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
+       /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
+          stripped down products */
+       state->has_sound_processing = msp_prod_lo < 7;
+       /* Has Virtual Dolby Surround: only in msp34x1 */
+       state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
+       /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
+       state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
+
+       state->opmode = opmode;
+       if (state->opmode == OPMODE_AUTO) {
+               /* MSP revision G and up have both autodetect and autoselect */
+               if (msp_revision >= 'G')
+                       state->opmode = OPMODE_AUTOSELECT;
+               /* MSP revision D and up have autodetect */
+               else if (msp_revision >= 'D')
+                       state->opmode = OPMODE_AUTODETECT;
+               else
+                       state->opmode = OPMODE_MANUAL;
+       }
+
+       /* hello world :-) */
+       v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
+       v4l_info(client, "%s ", client->name);
+       if (state->has_nicam && state->has_radio)
+               printk("supports nicam and radio, ");
+       else if (state->has_nicam)
+               printk("supports nicam, ");
+       else if (state->has_radio)
+               printk("supports radio, ");
+       printk("mode is ");
+
+       /* version-specific initialization */
+       switch (state->opmode) {
+       case OPMODE_MANUAL:
+               printk("manual");
+               thread_func = msp3400c_thread;
+               break;
+       case OPMODE_AUTODETECT:
+               printk("autodetect");
+               thread_func = msp3410d_thread;
+               break;
+       case OPMODE_AUTOSELECT:
+               printk("autodetect and autoselect");
+               thread_func = msp34xxg_thread;
+               break;
+       }
+       printk("\n");
+
+       /* startup control thread if needed */
+       if (thread_func) {
+               state->kthread = kthread_run(thread_func, client, "msp34xx");
+
+               if (state->kthread == NULL)
+                       v4l_warn(client, "kernel_thread() failed\n");
+               msp_wake_thread(client);
+       }
+
+       /* done */
+       i2c_attach_client(client);
+
+       return 0;
+}
+
+static int msp_probe(struct i2c_adapter *adapter)
+{
+       if (adapter->class & I2C_CLASS_TV_ANALOG)
+               return i2c_probe(adapter, &addr_data, msp_attach);
+       return 0;
+}
+
+static int msp_detach(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+       int err;
+
+       /* shutdown control thread */
+       if (state->kthread) {
+               state->restart = 1;
+               kthread_stop(state->kthread);
+       }
+       msp_reset(client);
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(state);
+       kfree(client);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+       .id             = I2C_DRIVERID_MSP3400,
+       .attach_adapter = msp_probe,
+       .detach_client  = msp_detach,
+       .command        = msp_command,
+       .driver = {
+               .name    = "msp3400",
+               .suspend = msp_suspend,
+               .resume  = msp_resume,
+       },
+};
+
+static int __init msp3400_init_module(void)
+{
+       return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit msp3400_cleanup_module(void)
+{
+       i2c_del_driver(&i2c_driver);
+}
+
+module_init(msp3400_init_module);
+module_exit(msp3400_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
new file mode 100644 (file)
index 0000000..2b59b68
--- /dev/null
@@ -0,0 +1,1010 @@
+/*
+ * Programming the mspx4xx sound processor family
+ *
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+#include "msp3400.h"
+
+/* this one uses the automatic sound standard detection of newer msp34xx
+   chip versions */
+static struct {
+       int retval;
+       int main, second;
+       char *name;
+} msp_stdlist[] = {
+       { 0x0000, 0, 0, "could not detect sound standard" },
+       { 0x0001, 0, 0, "autodetect start" },
+       { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72  M Dual FM-Stereo" },
+       { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74  B/G Dual FM-Stereo" },
+       { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25  D/K1 Dual FM-Stereo" },
+       { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74  D/K2 Dual FM-Stereo" },
+       { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  D/K FM-Mono (HDEV3)" },
+       { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },
+       { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },
+       { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },
+       { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },
+       { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },
+       { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },
+       { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },
+       { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },
+       { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7  FM-Stereo Radio" },
+       { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  SAT-Mono" },
+       { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20  SAT-Stereo" },
+       { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2  SAT ADR" },
+       {     -1, 0, 0, NULL }, /* EOF */
+};
+
+static struct msp3400c_init_data_dem {
+       int fir1[6];
+       int fir2[6];
+       int cdo1;
+       int cdo2;
+       int ad_cv;
+       int mode_reg;
+       int dsp_src;
+       int dsp_matrix;
+} msp3400c_init_data[] = {
+       {       /* AM (for carrier detect / msp3400) */
+               {75, 19, 36, 35, 39, 40},
+               {75, 19, 36, 35, 39, 40},
+               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+               0x00d0, 0x0500, 0x0020, 0x3000
+       },{     /* AM (for carrier detect / msp3410) */
+               {-1, -1, -8, 2, 59, 126},
+               {-1, -1, -8, 2, 59, 126},
+               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+               0x00d0, 0x0100, 0x0020, 0x3000
+       },{     /* FM Radio */
+               {-8, -8, 4, 6, 78, 107},
+               {-8, -8, 4, 6, 78, 107},
+               MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+               0x00d0, 0x0480, 0x0020, 0x3000
+       },{     /* Terrestial FM-mono + FM-stereo */
+               {3, 18, 27, 48, 66, 72},
+               {3, 18, 27, 48, 66, 72},
+               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+               0x00d0, 0x0480, 0x0030, 0x3000
+       },{     /* Sat FM-mono */
+               { 1, 9, 14, 24, 33, 37},
+               { 3, 18, 27, 48, 66, 72},
+               MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+               0x00c6, 0x0480, 0x0000, 0x3000
+       },{     /* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
+               {-2, -8, -10, 10, 50, 86},
+               {3, 18, 27, 48, 66, 72},
+               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+               0x00d0, 0x0040, 0x0120, 0x3000
+       },{     /* NICAM/FM -- I (6.0/6.552) */
+               {2, 4, -6, -4, 40, 94},
+               {3, 18, 27, 48, 66, 72},
+               MSP_CARRIER(6.0), MSP_CARRIER(6.0),
+               0x00d0, 0x0040, 0x0120, 0x3000
+       },{     /* NICAM/AM -- L (6.5/5.85) */
+               {-2, -8, -10, 10, 50, 86},
+               {-4, -12, -9, 23, 79, 126},
+               MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+               0x00c6, 0x0140, 0x0120, 0x7c03
+       },
+};
+
+struct msp3400c_carrier_detect {
+       int   cdo;
+       char *name;
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = {
+       /* main carrier */
+       { MSP_CARRIER(4.5),        "4.5   NTSC"                   },
+       { MSP_CARRIER(5.5),        "5.5   PAL B/G"                },
+       { MSP_CARRIER(6.0),        "6.0   PAL I"                  },
+       { MSP_CARRIER(6.5),        "6.5   PAL D/K + SAT + SECAM"  }
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = {
+       /* PAL B/G */
+       { MSP_CARRIER(5.7421875),  "5.742 PAL B/G FM-stereo"     },
+       { MSP_CARRIER(5.85),       "5.85  PAL B/G NICAM"         }
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = {
+       /* PAL SAT / SECAM */
+       { MSP_CARRIER(5.85),       "5.85  PAL D/K + SECAM NICAM" },
+       { MSP_CARRIER(6.2578125),  "6.25  PAL D/K1 FM-stereo" },
+       { MSP_CARRIER(6.7421875),  "6.74  PAL D/K2 FM-stereo" },
+       { MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
+       { MSP_CARRIER(7.20),       "7.20  PAL SAT FM-stereo s"   },
+       { MSP_CARRIER(7.38),       "7.38  PAL SAT FM-stereo b"   },
+};
+
+/* ------------------------------------------------------------------------ */
+
+const char *msp_standard_std_name(int std)
+{
+       int i;
+
+       for (i = 0; msp_stdlist[i].name != NULL; i++)
+               if (msp_stdlist[i].retval == std)
+                       return msp_stdlist[i].name;
+       return "unknown";
+}
+
+void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
+{
+       msp_write_dem(client, 0x0093, cdo1 & 0xfff);
+       msp_write_dem(client, 0x009b, cdo1 >> 12);
+       msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
+       msp_write_dem(client, 0x00ab, cdo2 >> 12);
+       msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+}
+
+void msp3400c_setmode(struct i2c_client *client, int type)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+       int i;
+
+       v4l_dbg(1, client, "setmode: %d\n", type);
+       state->mode       = type;
+       state->audmode    = V4L2_TUNER_MODE_MONO;
+       state->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+       msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv);
+
+       for (i = 5; i >= 0; i--)               /* fir 1 */
+               msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]);
+
+       msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
+       msp_write_dem(client, 0x0005, 0x0040);
+       msp_write_dem(client, 0x0005, 0x0000);
+       for (i = 5; i >= 0; i--)
+               msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]);
+
+       msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg);
+
+       msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1,
+                           msp3400c_init_data[type].cdo2);
+
+       msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+
+       if (dolby) {
+               msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
+               msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
+               msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
+       } else {
+               msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src);
+               msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src);
+               msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
+       }
+       msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
+       msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);
+
+       if (state->has_nicam) {
+               /* nicam prescale */
+               msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */
+       }
+}
+
+/* turn on/off nicam + stereo */
+void msp3400c_setstereo(struct i2c_client *client, int mode)
+{
+       static char *strmode[] = { "mono", "stereo", "lang2", "lang1" };
+       struct msp_state *state = i2c_get_clientdata(client);
+       int nicam = 0;          /* channel source: FM/AM or nicam */
+       int src = 0;
+
+       if (state->opmode == OPMODE_AUTOSELECT) {
+               /* this method would break everything, let's make sure
+                * it's never called
+                */
+               v4l_dbg(1, client, "setstereo called with mode=%d instead of set_source (ignored)\n",
+                    mode);
+               return;
+       }
+
+       /* switch demodulator */
+       switch (state->mode) {
+       case MSP_MODE_FM_TERRA:
+               v4l_dbg(1, client, "FM setstereo: %s\n", strmode[mode]);
+               msp3400c_setcarrier(client, state->second, state->main);
+               switch (mode) {
+               case V4L2_TUNER_MODE_STEREO:
+                       msp_write_dsp(client, 0x000e, 0x3001);
+                       break;
+               case V4L2_TUNER_MODE_MONO:
+               case V4L2_TUNER_MODE_LANG1:
+               case V4L2_TUNER_MODE_LANG2:
+                       msp_write_dsp(client, 0x000e, 0x3000);
+                       break;
+               }
+               break;
+       case MSP_MODE_FM_SAT:
+               v4l_dbg(1, client, "SAT setstereo: %s\n", strmode[mode]);
+               switch (mode) {
+               case V4L2_TUNER_MODE_MONO:
+                       msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+                       break;
+               case V4L2_TUNER_MODE_STEREO:
+                       msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+                       break;
+               case V4L2_TUNER_MODE_LANG1:
+                       msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+                       break;
+               case V4L2_TUNER_MODE_LANG2:
+                       msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+                       break;
+               }
+               break;
+       case MSP_MODE_FM_NICAM1:
+       case MSP_MODE_FM_NICAM2:
+       case MSP_MODE_AM_NICAM:
+               v4l_dbg(1, client, "NICAM setstereo: %s\n",strmode[mode]);
+               msp3400c_setcarrier(client,state->second,state->main);
+               if (state->nicam_on)
+                       nicam=0x0100;
+               break;
+       case MSP_MODE_BTSC:
+               v4l_dbg(1, client, "BTSC setstereo: %s\n",strmode[mode]);
+               nicam=0x0300;
+               break;
+       case MSP_MODE_EXTERN:
+               v4l_dbg(1, client, "extern setstereo: %s\n",strmode[mode]);
+               nicam = 0x0200;
+               break;
+       case MSP_MODE_FM_RADIO:
+               v4l_dbg(1, client, "FM-Radio setstereo: %s\n",strmode[mode]);
+               break;
+       default:
+               v4l_dbg(1, client, "mono setstereo\n");
+               return;
+       }
+
+       /* switch audio */
+       switch (mode) {
+       case V4L2_TUNER_MODE_STEREO:
+               src = 0x0020 | nicam;
+               break;
+       case V4L2_TUNER_MODE_MONO:
+               if (state->mode == MSP_MODE_AM_NICAM) {
+                       v4l_dbg(1, client, "switching to AM mono\n");
+                       /* AM mono decoding is handled by tuner, not MSP chip */
+                       /* SCART switching control register */
+                       msp_set_scart(client, SCART_MONO, 0);
+                       src = 0x0200;
+                       break;
+               }
+       case V4L2_TUNER_MODE_LANG1:
+               src = 0x0000 | nicam;
+               break;
+       case V4L2_TUNER_MODE_LANG2:
+               src = 0x0010 | nicam;
+               break;
+       }
+       v4l_dbg(1, client, "setstereo final source/matrix = 0x%x\n", src);
+
+       if (dolby) {
+               msp_write_dsp(client, 0x0008, 0x0520);
+               msp_write_dsp(client, 0x0009, 0x0620);
+               msp_write_dsp(client, 0x000a, src);
+               msp_write_dsp(client, 0x000b, src);
+       } else {
+               msp_write_dsp(client, 0x0008, src);
+               msp_write_dsp(client, 0x0009, src);
+               msp_write_dsp(client, 0x000a, src);
+               msp_write_dsp(client, 0x000b, src);
+               msp_write_dsp(client, 0x000c, src);
+               if (state->has_scart23_in_scart2_out)
+                       msp_write_dsp(client, 0x0041, src);
+       }
+}
+
+static void msp3400c_print_mode(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       if (state->main == state->second) {
+               v4l_dbg(1, client, "mono sound carrier: %d.%03d MHz\n",
+                      state->main / 910000, (state->main / 910) % 1000);
+       } else {
+               v4l_dbg(1, client, "main sound carrier: %d.%03d MHz\n",
+                      state->main / 910000, (state->main / 910) % 1000);
+       }
+       if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
+               v4l_dbg(1, client, "NICAM/FM carrier  : %d.%03d MHz\n",
+                      state->second / 910000, (state->second/910) % 1000);
+       if (state->mode == MSP_MODE_AM_NICAM)
+               v4l_dbg(1, client, "NICAM/AM carrier  : %d.%03d MHz\n",
+                      state->second / 910000, (state->second / 910) % 1000);
+       if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
+               v4l_dbg(1, client, "FM-stereo carrier : %d.%03d MHz\n",
+                      state->second / 910000, (state->second / 910) % 1000);
+       }
+}
+
+/* ----------------------------------------------------------------------- */
+
+int autodetect_stereo(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+       int val;
+       int rxsubchans = state->rxsubchans;
+       int newnicam   = state->nicam_on;
+       int update = 0;
+
+       switch (state->mode) {
+       case MSP_MODE_FM_TERRA:
+               val = msp_read_dsp(client, 0x18);
+               if (val > 32767)
+                       val -= 65536;
+               v4l_dbg(2, client, "stereo detect register: %d\n", val);
+               if (val > 4096) {
+                       rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+               } else if (val < -4096) {
+                       rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+               } else {
+                       rxsubchans = V4L2_TUNER_SUB_MONO;
+               }
+               newnicam = 0;
+               break;
+       case MSP_MODE_FM_NICAM1:
+       case MSP_MODE_FM_NICAM2:
+       case MSP_MODE_AM_NICAM:
+               val = msp_read_dem(client, 0x23);
+               v4l_dbg(2, client, "nicam sync=%d, mode=%d\n",
+                       val & 1, (val & 0x1e) >> 1);
+
+               if (val & 1) {
+                       /* nicam synced */
+                       switch ((val & 0x1e) >> 1)  {
+                       case 0:
+                       case 8:
+                               rxsubchans = V4L2_TUNER_SUB_STEREO;
+                               break;
+                       case 1:
+                       case 9:
+                               rxsubchans = V4L2_TUNER_SUB_MONO
+                                       | V4L2_TUNER_SUB_LANG1;
+                               break;
+                       case 2:
+                       case 10:
+                               rxsubchans = V4L2_TUNER_SUB_MONO
+                                       | V4L2_TUNER_SUB_LANG1
+                                       | V4L2_TUNER_SUB_LANG2;
+                               break;
+                       default:
+                               rxsubchans = V4L2_TUNER_SUB_MONO;
+                               break;
+                       }
+                       newnicam = 1;
+               } else {
+                       newnicam = 0;
+                       rxsubchans = V4L2_TUNER_SUB_MONO;
+               }
+               break;
+       case MSP_MODE_BTSC:
+               val = msp_read_dem(client, 0x200);
+               v4l_dbg(2, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+                       val,
+                       (val & 0x0002) ? "no"     : "yes",
+                       (val & 0x0004) ? "no"     : "yes",
+                       (val & 0x0040) ? "stereo" : "mono",
+                       (val & 0x0080) ? ", nicam 2nd mono" : "",
+                       (val & 0x0100) ? ", bilingual/SAP"  : "");
+               rxsubchans = V4L2_TUNER_SUB_MONO;
+               if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
+               if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
+               break;
+       }
+       if (rxsubchans != state->rxsubchans) {
+               update = 1;
+               v4l_dbg(1, client, "watch: rxsubchans %d => %d\n",
+                       state->rxsubchans,rxsubchans);
+               state->rxsubchans = rxsubchans;
+       }
+       if (newnicam != state->nicam_on) {
+               update = 1;
+               v4l_dbg(1, client, "watch: nicam %d => %d\n",
+                       state->nicam_on,newnicam);
+               state->nicam_on = newnicam;
+       }
+       return update;
+}
+
+/*
+ * A kernel thread for msp3400 control -- we don't want to block the
+ * in the ioctl while doing the sound carrier & stereo detect
+ */
+/* stereo/multilang monitoring */
+static void watch_stereo(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       if (autodetect_stereo(client)) {
+               if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+                       msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
+               else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1)
+                       msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
+               else
+                       msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+       }
+
+       if (once)
+               state->watch_stereo = 0;
+}
+
+int msp3400c_thread(void *data)
+{
+       struct i2c_client *client = data;
+       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp3400c_carrier_detect *cd;
+       int count, max1,max2,val1,val2, val,this;
+
+
+       v4l_dbg(1, client, "msp3400 daemon started\n");
+       for (;;) {
+               v4l_dbg(2, client, "msp3400 thread: sleep\n");
+               msp_sleep(state, -1);
+               v4l_dbg(2, client, "msp3400 thread: wakeup\n");
+
+       restart:
+               v4l_dbg(1, client, "thread: restart scan\n");
+               state->restart = 0;
+               if (kthread_should_stop())
+                       break;
+
+               if (state->radio || MSP_MODE_EXTERN == state->mode) {
+                       /* no carrier scan, just unmute */
+                       v4l_dbg(1, client, "thread: no carrier scan\n");
+                       msp_set_audio(client);
+                       continue;
+               }
+
+               /* mute */
+               msp_set_mute(client);
+               msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
+               val1 = val2 = 0;
+               max1 = max2 = -1;
+               state->watch_stereo = 0;
+
+               /* some time for the tuner to sync */
+               if (msp_sleep(state,200))
+                       goto restart;
+
+               /* carrier detect pass #1 -- main carrier */
+               cd = msp3400c_carrier_detect_main;
+               count = ARRAY_SIZE(msp3400c_carrier_detect_main);
+
+               if (amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
+                       /* autodetect doesn't work well with AM ... */
+                       max1 = 3;
+                       count = 0;
+                       v4l_dbg(1, client, "AM sound override\n");
+               }
+
+               for (this = 0; this < count; this++) {
+                       msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+                       if (msp_sleep(state,100))
+                               goto restart;
+                       val = msp_read_dsp(client, 0x1b);
+                       if (val > 32767)
+                               val -= 65536;
+                       if (val1 < val)
+                               val1 = val, max1 = this;
+                       v4l_dbg(1, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
+               }
+
+               /* carrier detect pass #2 -- second (stereo) carrier */
+               switch (max1) {
+               case 1: /* 5.5 */
+                       cd = msp3400c_carrier_detect_55;
+                       count = ARRAY_SIZE(msp3400c_carrier_detect_55);
+                       break;
+               case 3: /* 6.5 */
+                       cd = msp3400c_carrier_detect_65;
+                       count = ARRAY_SIZE(msp3400c_carrier_detect_65);
+                       break;
+               case 0: /* 4.5 */
+               case 2: /* 6.0 */
+               default:
+                       cd = NULL;
+                       count = 0;
+                       break;
+               }
+
+               if (amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
+                       /* autodetect doesn't work well with AM ... */
+                       cd = NULL;
+                       count = 0;
+                       max2 = 0;
+               }
+               for (this = 0; this < count; this++) {
+                       msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+                       if (msp_sleep(state,100))
+                               goto restart;
+                       val = msp_read_dsp(client, 0x1b);
+                       if (val > 32767)
+                               val -= 65536;
+                       if (val2 < val)
+                               val2 = val, max2 = this;
+                       v4l_dbg(1, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
+               }
+
+               /* program the msp3400 according to the results */
+               state->main   = msp3400c_carrier_detect_main[max1].cdo;
+               switch (max1) {
+               case 1: /* 5.5 */
+                       if (max2 == 0) {
+                               /* B/G FM-stereo */
+                               state->second = msp3400c_carrier_detect_55[max2].cdo;
+                               msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+                               state->nicam_on = 0;
+                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+                               state->watch_stereo = 1;
+                       } else if (max2 == 1 && state->has_nicam) {
+                               /* B/G NICAM */
+                               state->second = msp3400c_carrier_detect_55[max2].cdo;
+                               msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+                               state->nicam_on = 1;
+                               msp3400c_setcarrier(client, state->second, state->main);
+                               state->watch_stereo = 1;
+                       } else {
+                               goto no_second;
+                       }
+                       break;
+               case 2: /* 6.0 */
+                       /* PAL I NICAM */
+                       state->second = MSP_CARRIER(6.552);
+                       msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
+                       state->nicam_on = 1;
+                       msp3400c_setcarrier(client, state->second, state->main);
+                       state->watch_stereo = 1;
+                       break;
+               case 3: /* 6.5 */
+                       if (max2 == 1 || max2 == 2) {
+                               /* D/K FM-stereo */
+                               state->second = msp3400c_carrier_detect_65[max2].cdo;
+                               msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+                               state->nicam_on = 0;
+                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+                               state->watch_stereo = 1;
+                       } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
+                               /* L NICAM or AM-mono */
+                               state->second = msp3400c_carrier_detect_65[max2].cdo;
+                               msp3400c_setmode(client, MSP_MODE_AM_NICAM);
+                               state->nicam_on = 0;
+                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+                               msp3400c_setcarrier(client, state->second, state->main);
+                               /* volume prescale for SCART (AM mono input) */
+                               msp_write_dsp(client, 0x000d, 0x1900);
+                               state->watch_stereo = 1;
+                       } else if (max2 == 0 && state->has_nicam) {
+                               /* D/K NICAM */
+                               state->second = msp3400c_carrier_detect_65[max2].cdo;
+                               msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+                               state->nicam_on = 1;
+                               msp3400c_setcarrier(client, state->second, state->main);
+                               state->watch_stereo = 1;
+                       } else {
+                               goto no_second;
+                       }
+                       break;
+               case 0: /* 4.5 */
+               default:
+               no_second:
+                       state->second = msp3400c_carrier_detect_main[max1].cdo;
+                       msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+                       state->nicam_on = 0;
+                       msp3400c_setcarrier(client, state->second, state->main);
+                       state->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+                       break;
+               }
+
+               /* unmute */
+               msp_set_audio(client);
+
+               if (debug)
+                       msp3400c_print_mode(client);
+
+               /* monitor tv audio mode */
+               while (state->watch_stereo) {
+                       if (msp_sleep(state,5000))
+                               goto restart;
+                       watch_stereo(client);
+               }
+       }
+       v4l_dbg(1, client, "thread: exit\n");
+       return 0;
+}
+
+
+int msp3410d_thread(void *data)
+{
+       struct i2c_client *client = data;
+       struct msp_state *state = i2c_get_clientdata(client);
+       int val, i, std;
+
+       v4l_dbg(1, client, "msp3410 daemon started\n");
+
+       for (;;) {
+               v4l_dbg(2, client, "msp3410 thread: sleep\n");
+               msp_sleep(state,-1);
+               v4l_dbg(2, client, "msp3410 thread: wakeup\n");
+
+       restart:
+               v4l_dbg(1, client, "thread: restart scan\n");
+               state->restart = 0;
+               if (kthread_should_stop())
+                       break;
+
+               if (state->mode == MSP_MODE_EXTERN) {
+                       /* no carrier scan needed, just unmute */
+                       v4l_dbg(1, client, "thread: no carrier scan\n");
+                       msp_set_audio(client);
+                       continue;
+               }
+
+               /* put into sane state (and mute) */
+               msp_reset(client);
+
+               /* some time for the tuner to sync */
+               if (msp_sleep(state,200))
+                       goto restart;
+
+               /* start autodetect */
+               if (state->radio)
+                       std = 0x40;
+               else
+                       std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
+               state->watch_stereo = 0;
+
+               if (debug)
+                       v4l_dbg(1, client, "setting standard: %s (0x%04x)\n",
+                              msp_standard_std_name(std), std);
+
+               if (std != 1) {
+                       /* programmed some specific mode */
+                       val = std;
+               } else {
+                       /* triggered autodetect */
+                       msp_write_dem(client, 0x20, std);
+                       for (;;) {
+                               if (msp_sleep(state, 100))
+                                       goto restart;
+
+                               /* check results */
+                               val = msp_read_dem(client, 0x7e);
+                               if (val < 0x07ff)
+                                       break;
+                               v4l_dbg(1, client, "detection still in progress\n");
+                       }
+               }
+               for (i = 0; msp_stdlist[i].name != NULL; i++)
+                       if (msp_stdlist[i].retval == val)
+                               break;
+               v4l_dbg(1, client, "current standard: %s (0x%04x)\n",
+                       msp_standard_std_name(val), val);
+               state->main   = msp_stdlist[i].main;
+               state->second = msp_stdlist[i].second;
+               state->std = val;
+
+               if (amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
+                               (val != 0x0009)) {
+                       /* autodetection has failed, let backup */
+                       v4l_dbg(1, client, "autodetection failed,"
+                               " switching to backup standard: %s (0x%04x)\n",
+                               msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
+                       val = 0x0009;
+                       msp_write_dem(client, 0x20, val);
+               }
+
+               /* set various prescales */
+               msp_write_dsp(client, 0x0d, 0x1900); /* scart */
+               msp_write_dsp(client, 0x0e, 0x2403); /* FM */
+               msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
+
+               /* set stereo */
+               switch (val) {
+               case 0x0008: /* B/G NICAM */
+               case 0x000a: /* I NICAM */
+                       if (val == 0x0008)
+                               state->mode = MSP_MODE_FM_NICAM1;
+                       else
+                               state->mode = MSP_MODE_FM_NICAM2;
+                       /* just turn on stereo */
+                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       state->nicam_on = 1;
+                       state->watch_stereo = 1;
+                       msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+                       break;
+               case 0x0009:
+                       state->mode = MSP_MODE_AM_NICAM;
+                       state->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       state->nicam_on = 1;
+                       msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
+                       state->watch_stereo = 1;
+                       break;
+               case 0x0020: /* BTSC */
+                       /* just turn on stereo */
+                       state->mode = MSP_MODE_BTSC;
+                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       state->nicam_on = 0;
+                       state->watch_stereo = 1;
+                       msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+                       break;
+               case 0x0040: /* FM radio */
+                       state->mode = MSP_MODE_FM_RADIO;
+                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       state->audmode = V4L2_TUNER_MODE_STEREO;
+                       state->nicam_on = 0;
+                       state->watch_stereo = 0;
+                       /* not needed in theory if we have radio, but
+                          short programming enables carrier mute */
+                       msp3400c_setmode(client, MSP_MODE_FM_RADIO);
+                       msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+                                           MSP_CARRIER(10.7));
+                       /* scart routing */
+                       msp_set_scart(client,SCART_IN2,0);
+                       /* msp34xx does radio decoding */
+                       msp_write_dsp(client, 0x08, 0x0020);
+                       msp_write_dsp(client, 0x09, 0x0020);
+                       msp_write_dsp(client, 0x0b, 0x0020);
+                       break;
+               case 0x0003:
+               case 0x0004:
+               case 0x0005:
+                       state->mode = MSP_MODE_FM_TERRA;
+                       state->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       state->audmode = V4L2_TUNER_MODE_MONO;
+                       state->nicam_on = 0;
+                       state->watch_stereo = 1;
+                       break;
+               }
+
+               /* unmute, restore misc registers */
+               msp_set_audio(client);
+               msp_write_dsp(client, 0x13, state->acb);
+               if (state->has_i2s_conf)
+                       msp_write_dem(client, 0x40, state->i2s_mode);
+
+               /* monitor tv audio mode */
+               while (state->watch_stereo) {
+                       if (msp_sleep(state,5000))
+                               goto restart;
+                       watch_stereo(client);
+               }
+       }
+       v4l_dbg(1, client, "thread: exit\n");
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* msp34xxG + (autoselect no-thread)                                          */
+/* this one uses both automatic standard detection and automatic sound     */
+/* select which are available in the newer G versions                      */
+/* struct msp: only norm, acb and source are really used in this mode      */
+
+/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
+ * the value for source is the same as bit 15:8 of DSP registers 0x08,
+ * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
+ *
+ * this function replaces msp3400c_setstereo
+ */
+static void msp34xxg_set_source(struct i2c_client *client, int source)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       /* fix matrix mode to stereo and let the msp choose what
+        * to output according to 'source', as recommended
+        * for MONO (source==0) downmixing set bit[7:0] to 0x30
+        */
+       int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
+
+       v4l_dbg(1, client, "set source to %d (0x%x)\n", source, value);
+       /* Loudspeaker Output */
+       msp_write_dsp(client, 0x08, value);
+       /* SCART1 DA Output */
+       msp_write_dsp(client, 0x0a, value);
+       /* Quasi-peak detector */
+       msp_write_dsp(client, 0x0c, value);
+       /*
+        * set identification threshold. Personally, I
+        * I set it to a higher value that the default
+        * of 0x190 to ignore noisy stereo signals.
+        * this needs tuning. (recommended range 0x00a0-0x03c0)
+        * 0x7f0 = forced mono mode
+        */
+       /* a2 threshold for stereo/bilingual */
+       msp_write_dem(client, 0x22, stereo_threshold);
+       state->source = source;
+}
+
+/* (re-)initialize the msp34xxg, according to the current norm in state->norm
+ * return 0 if it worked, -1 if it failed
+ */
+static int msp34xxg_reset(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+       int modus, std;
+
+       if (msp_reset(client))
+               return -1;
+
+       /* make sure that input/output is muted (paranoid mode) */
+       /* ACB, mute DSP input, mute SCART 1 */
+       if (msp_write_dsp(client, 0x13, 0x0f20))
+               return -1;
+
+       if (state->has_i2s_conf)
+               msp_write_dem(client, 0x40, state->i2s_mode);
+
+       /* step-by-step initialisation, as described in the manual */
+       modus = msp_modus(client);
+       if (state->radio)
+               std = 0x40;
+       else
+               std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
+       modus &= ~0x03; /* STATUS_CHANGE = 0 */
+       modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION = 1 */
+       if (msp_write_dem(client, 0x30, modus))
+               return -1;
+       if (msp_write_dem(client, 0x20, std))
+               return -1;
+
+       /* write the dsps that may have an influence on
+          standard/audio autodetection right now */
+       msp34xxg_set_source(client, state->source);
+
+       /* AM/FM Prescale [15:8] 75khz deviation */
+       if (msp_write_dsp(client, 0x0e, 0x3000))
+               return -1;
+
+       /* NICAM Prescale 9db gain (as recommended) */
+       if (msp_write_dsp(client, 0x10, 0x5a00))
+               return -1;
+
+       return 0;
+}
+
+int msp34xxg_thread(void *data)
+{
+       struct i2c_client *client = data;
+       struct msp_state *state = i2c_get_clientdata(client);
+       int val, std, i;
+
+       v4l_dbg(1, client, "msp34xxg daemon started\n");
+
+       state->source = 1; /* default */
+       for (;;) {
+               v4l_dbg(2, client, "msp34xxg thread: sleep\n");
+               msp_sleep(state, -1);
+               v4l_dbg(2, client, "msp34xxg thread: wakeup\n");
+
+       restart:
+               v4l_dbg(1, client, "thread: restart scan\n");
+               state->restart = 0;
+               if (kthread_should_stop())
+                       break;
+
+               /* setup the chip*/
+               msp34xxg_reset(client);
+               std = standard;
+               if (std != 0x01)
+                       goto unmute;
+
+               /* watch autodetect */
+               v4l_dbg(1, client, "triggered autodetect, waiting for result\n");
+               for (i = 0; i < 10; i++) {
+                       if (msp_sleep(state, 100))
+                               goto restart;
+
+                       /* check results */
+                       val = msp_read_dem(client, 0x7e);
+                       if (val < 0x07ff) {
+                               std = val;
+                               break;
+                       }
+                       v4l_dbg(2, client, "detection still in progress\n");
+               }
+               if (std == 1) {
+                       v4l_dbg(1, client, "detection still in progress after 10 tries. giving up.\n");
+                       continue;
+               }
+
+       unmute:
+               state->std = std;
+               v4l_dbg(1, client, "current standard: %s (0x%04x)\n",
+                       msp_standard_std_name(std), std);
+
+               /* unmute: dispatch sound to scart output, set scart volume */
+               msp_set_audio(client);
+
+               /* restore ACB */
+               if (msp_write_dsp(client, 0x13, state->acb))
+                       return -1;
+
+               msp_write_dem(client, 0x40, state->i2s_mode);
+       }
+       v4l_dbg(1, client, "thread: exit\n");
+       return 0;
+}
+
+void msp34xxg_detect_stereo(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       int status = msp_read_dem(client, 0x0200);
+       int is_bilingual = status & 0x100;
+       int is_stereo = status & 0x40;
+
+       state->rxsubchans = 0;
+       if (is_stereo)
+               state->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+       else
+               state->rxsubchans |= V4L2_TUNER_SUB_MONO;
+       if (is_bilingual) {
+               state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+               /* I'm supposed to check whether it's SAP or not
+                * and set only LANG2/SAP in this case. Yet, the MSP
+                * does a lot of work to hide this and handle everything
+                * the same way. I don't want to work around it so unless
+                * this is a problem, I'll handle SAP just like lang1/lang2.
+                */
+       }
+       v4l_dbg(1, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+               status, is_stereo, is_bilingual, state->rxsubchans);
+}
+
+void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+       int source;
+
+       switch (audmode) {
+       case V4L2_TUNER_MODE_MONO:
+               source = 0; /* mono only */
+               break;
+       case V4L2_TUNER_MODE_STEREO:
+               source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
+               /* problem: that could also mean 2 (scart input) */
+               break;
+       case V4L2_TUNER_MODE_LANG1:
+               source = 3; /* stereo or A */
+               break;
+       case V4L2_TUNER_MODE_LANG2:
+               source = 4; /* stereo or B */
+               break;
+       default:
+               audmode = 0;
+               source  = 1;
+               break;
+       }
+       state->audmode = audmode;
+       msp34xxg_set_source(client, source);
+}
+
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
deleted file mode 100644 (file)
index 183253e..0000000
+++ /dev/null
@@ -1,2229 +0,0 @@
-/*
- * programming the msp34* sound processor family
- *
- * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
- *
- * what works and what doesn't:
- *
- *  AM-Mono
- *      Support for Hauppauge cards added (decoding handled by tuner) added by
- *      Frederic Crozat <fcrozat@mail.dotcom.fr>
- *
- *  FM-Mono
- *      should work. The stereo modes are backward compatible to FM-mono,
- *      therefore FM-Mono should be allways available.
- *
- *  FM-Stereo (B/G, used in germany)
- *      should work, with autodetect
- *
- *  FM-Stereo (satellite)
- *      should work, no autodetect (i.e. default is mono, but you can
- *      switch to stereo -- untested)
- *
- *  NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
- *      should work, with autodetect. Support for NICAM was added by
- *      Pekka Pietikainen <pp@netppl.fi>
- *
- *
- * TODO:
- *   - better SAT support
- *
- *
- * 980623  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *         using soundcore instead of OSS
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/kthread.h>
-#include <linux/suspend.h>
-#include <asm/semaphore.h>
-#include <asm/pgtable.h>
-
-#include <media/audiochip.h>
-#include "msp3400.h"
-
-#define msp3400_dbg(fmt, arg...) \
-       do { \
-               if (debug) \
-                       printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-                              client->driver->driver.name, \
-                              i2c_adapter_id(client->adapter), client->addr , ## arg); \
-       } while (0)
-
-/* Medium volume debug. */
-#define msp3400_dbg_mediumvol(fmt, arg...) \
-       do { \
-               if (debug >= 2) \
-                       printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-                               client->driver->driver.name, \
-                               i2c_adapter_id(client->adapter), client->addr , ## arg); \
-       } while (0)
-
-/* High volume debug. Use with care. */
-#define msp3400_dbg_highvol(fmt, arg...) \
-       do { \
-               if (debug >= 16) \
-                       printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-                               client->driver->driver.name, \
-                               i2c_adapter_id(client->adapter), client->addr , ## arg); \
-       } while (0)
-
-#define msp3400_err(fmt, arg...) do { \
-       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define msp3400_warn(fmt, arg...) do { \
-       printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \
-               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define msp3400_info(fmt, arg...) do { \
-       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define OPMODE_AUTO    -1
-#define OPMODE_MANUAL   0
-#define OPMODE_SIMPLE   1   /* use short programming (>= msp3410 only) */
-#define OPMODE_SIMPLER  2   /* use shorter programming (>= msp34xxG)   */
-
-/* insmod parameters */
-static int opmode   = OPMODE_AUTO;
-static int debug    = 0;    /* debug output */
-static int once     = 0;    /* no continous stereo monitoring */
-static int amsound  = 0;    /* hard-wire AM sound at 6.5 Hz (france),
-                              the autoscan seems work well only with FM... */
-static int standard = 1;    /* Override auto detect of audio standard, if needed. */
-static int dolby    = 0;
-
-static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
-                                       (msp34xxg only) 0x00a0-0x03c0 */
-#define DFP_COUNT 0x41
-static const int bl_dfp[] = {
-       0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a,
-       0x0b, 0x0d, 0x0e, 0x10
-};
-
-#define IS_MSP34XX_G(msp) ((msp)->opmode==2)
-
-struct msp3400c {
-       int rev1,rev2;
-
-       int opmode;
-       int nicam;
-       int mode;
-       int norm;
-       int stereo;
-       int nicam_on;
-       int acb;
-       int in_scart;
-       int i2s_mode;
-       int main, second;       /* sound carrier */
-       int input;
-       int source;             /* see msp34xxg_set_source */
-
-       /* v4l2 */
-       int audmode;
-       int rxsubchans;
-
-       int muted;
-       int left, right;        /* volume */
-       int bass, treble;
-
-       /* shadow register set */
-       int dfp_regs[DFP_COUNT];
-
-       /* thread */
-       struct task_struct   *kthread;
-       wait_queue_head_t    wq;
-       int                  restart:1;
-       int                  watch_stereo:1;
-};
-
-#define MIN(a,b) (((a)>(b))?(b):(a))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#define HAVE_NICAM(msp)   (((msp->rev2>>8) & 0xff) != 00)
-#define HAVE_SIMPLE(msp)  ((msp->rev1      & 0xff) >= 'D'-'@')
-#define HAVE_SIMPLER(msp) ((msp->rev1      & 0xff) >= 'G'-'@')
-#define HAVE_RADIO(msp)   ((msp->rev1      & 0xff) >= 'G'-'@')
-
-#define VIDEO_MODE_RADIO 16      /* norm magic for radio mode */
-
-/* ---------------------------------------------------------------------- */
-
-/* read-only */
-module_param(opmode,           int, 0444);
-
-/* read-write */
-module_param(once,             int, 0644);
-module_param(debug,            int, 0644);
-module_param(stereo_threshold, int, 0644);
-module_param(standard,         int, 0644);
-module_param(amsound,          int, 0644);
-module_param(dolby,            int, 0644);
-
-MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Simple, 2=Simpler");
-MODULE_PARM_DESC(once, "No continuous stereo monitoring");
-MODULE_PARM_DESC(debug, "Enable debug messages");
-MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
-MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
-MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
-MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
-
-/* ---------------------------------------------------------------------- */
-
-#define I2C_MSP3400C       0x80
-#define I2C_MSP3400C_ALT   0x88
-
-#define I2C_MSP3400C_DEM   0x10
-#define I2C_MSP3400C_DFP   0x12
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
-       I2C_MSP3400C      >> 1,
-       I2C_MSP3400C_ALT  >> 1,
-       I2C_CLIENT_END
-};
-I2C_CLIENT_INSMOD;
-
-MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/* ----------------------------------------------------------------------- */
-/* functions for talking to the MSP3400C Sound processor                   */
-
-static int msp3400c_reset(struct i2c_client *client)
-{
-       /* reset and read revision code */
-       static char reset_off[3] = { 0x00, 0x80, 0x00 };
-       static char reset_on[3]  = { 0x00, 0x00, 0x00 };
-       static char write[3]     = { I2C_MSP3400C_DFP + 1, 0x00, 0x1e };
-       char read[2];
-       struct i2c_msg reset[2] = {
-               { client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
-               { client->addr, I2C_M_IGNORE_NAK, 3, reset_on  },
-       };
-       struct i2c_msg test[2] = {
-               { client->addr, 0,        3, write },
-               { client->addr, I2C_M_RD, 2, read  },
-       };
-
-       msp3400_dbg_highvol("msp3400c_reset\n");
-       if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
-            (1 != i2c_transfer(client->adapter,&reset[1],1)) ||
-            (2 != i2c_transfer(client->adapter,test,2)) ) {
-               msp3400_err("chip reset failed\n");
-               return -1;
-       }
-       return 0;
-}
-
-static int msp3400c_read(struct i2c_client *client, int dev, int addr)
-{
-       int err,retval;
-
-       unsigned char write[3];
-       unsigned char read[2];
-       struct i2c_msg msgs[2] = {
-               { client->addr, 0,        3, write },
-               { client->addr, I2C_M_RD, 2, read  }
-       };
-
-       write[0] = dev+1;
-       write[1] = addr >> 8;
-       write[2] = addr & 0xff;
-
-       for (err = 0; err < 3;) {
-               if (2 == i2c_transfer(client->adapter,msgs,2))
-                       break;
-               err++;
-               msp3400_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err,
-                      dev, addr);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(msecs_to_jiffies(10));
-       }
-       if (3 == err) {
-               msp3400_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n");
-               msp3400c_reset(client);
-               return -1;
-       }
-       retval = read[0] << 8 | read[1];
-       msp3400_dbg_highvol("msp3400c_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
-       return retval;
-}
-
-static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
-{
-       int err;
-       unsigned char buffer[5];
-
-       buffer[0] = dev;
-       buffer[1] = addr >> 8;
-       buffer[2] = addr &  0xff;
-       buffer[3] = val  >> 8;
-       buffer[4] = val  &  0xff;
-
-       msp3400_dbg_highvol("msp3400c_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
-       for (err = 0; err < 3;) {
-               if (5 == i2c_master_send(client, buffer, 5))
-                       break;
-               err++;
-               msp3400_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err,
-                      dev, addr);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(msecs_to_jiffies(10));
-       }
-       if (3 == err) {
-               msp3400_warn("giving up, reseting chip. Sound will go off, sorry folks :-|\n");
-               msp3400c_reset(client);
-               return -1;
-       }
-       return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-
-/* This macro is allowed for *constants* only, gcc must calculate it
-   at compile time.  Remember -- no floats in kernel mode */
-#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24)))
-
-#define MSP_MODE_AM_DETECT   0
-#define MSP_MODE_FM_RADIO    2
-#define MSP_MODE_FM_TERRA    3
-#define MSP_MODE_FM_SAT      4
-#define MSP_MODE_FM_NICAM1   5
-#define MSP_MODE_FM_NICAM2   6
-#define MSP_MODE_AM_NICAM    7
-#define MSP_MODE_BTSC        8
-#define MSP_MODE_EXTERN      9
-
-static struct MSP_INIT_DATA_DEM {
-       int fir1[6];
-       int fir2[6];
-       int cdo1;
-       int cdo2;
-       int ad_cv;
-       int mode_reg;
-       int dfp_src;
-       int dfp_matrix;
-} msp_init_data[] = {
-       {       /* AM (for carrier detect / msp3400) */
-               {75, 19, 36, 35, 39, 40},
-               {75, 19, 36, 35, 39, 40},
-               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-               0x00d0, 0x0500, 0x0020, 0x3000
-       },{     /* AM (for carrier detect / msp3410) */
-               {-1, -1, -8, 2, 59, 126},
-               {-1, -1, -8, 2, 59, 126},
-               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-               0x00d0, 0x0100, 0x0020, 0x3000
-       },{     /* FM Radio */
-               {-8, -8, 4, 6, 78, 107},
-               {-8, -8, 4, 6, 78, 107},
-               MSP_CARRIER(10.7), MSP_CARRIER(10.7),
-               0x00d0, 0x0480, 0x0020, 0x3000
-       },{     /* Terrestial FM-mono + FM-stereo */
-               {3, 18, 27, 48, 66, 72},
-               {3, 18, 27, 48, 66, 72},
-               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-               0x00d0, 0x0480, 0x0030, 0x3000
-       },{     /* Sat FM-mono */
-               { 1, 9, 14, 24, 33, 37},
-               { 3, 18, 27, 48, 66, 72},
-               MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-               0x00c6, 0x0480, 0x0000, 0x3000
-       },{     /* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
-               {-2, -8, -10, 10, 50, 86},
-               {3, 18, 27, 48, 66, 72},
-               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-               0x00d0, 0x0040, 0x0120, 0x3000
-       },{     /* NICAM/FM -- I (6.0/6.552) */
-               {2, 4, -6, -4, 40, 94},
-               {3, 18, 27, 48, 66, 72},
-               MSP_CARRIER(6.0), MSP_CARRIER(6.0),
-               0x00d0, 0x0040, 0x0120, 0x3000
-       },{     /* NICAM/AM -- L (6.5/5.85) */
-               {-2, -8, -10, 10, 50, 86},
-               {-4, -12, -9, 23, 79, 126},
-               MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-               0x00c6, 0x0140, 0x0120, 0x7c03
-       },
-};
-
-struct CARRIER_DETECT {
-       int   cdo;
-       char *name;
-};
-
-static struct CARRIER_DETECT carrier_detect_main[] = {
-       /* main carrier */
-       { MSP_CARRIER(4.5),        "4.5   NTSC"                   },
-       { MSP_CARRIER(5.5),        "5.5   PAL B/G"                },
-       { MSP_CARRIER(6.0),        "6.0   PAL I"                  },
-       { MSP_CARRIER(6.5),        "6.5   PAL D/K + SAT + SECAM"  }
-};
-
-static struct CARRIER_DETECT carrier_detect_55[] = {
-       /* PAL B/G */
-       { MSP_CARRIER(5.7421875),  "5.742 PAL B/G FM-stereo"     },
-       { MSP_CARRIER(5.85),       "5.85  PAL B/G NICAM"         }
-};
-
-static struct CARRIER_DETECT carrier_detect_65[] = {
-       /* PAL SAT / SECAM */
-       { MSP_CARRIER(5.85),       "5.85  PAL D/K + SECAM NICAM" },
-       { MSP_CARRIER(6.2578125),  "6.25  PAL D/K1 FM-stereo" },
-       { MSP_CARRIER(6.7421875),  "6.74  PAL D/K2 FM-stereo" },
-       { MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
-       { MSP_CARRIER(7.20),       "7.20  PAL SAT FM-stereo s"   },
-       { MSP_CARRIER(7.38),       "7.38  PAL SAT FM-stereo b"   },
-};
-
-#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
-
-/* ----------------------------------------------------------------------- *
- * bits  9  8  5 - SCART DSP input Select:
- *       0  0  0 - SCART 1 to DSP input (reset position)
- *       0  1  0 - MONO to DSP input
- *       1  0  0 - SCART 2 to DSP input
- *       1  1  1 - Mute DSP input
- *
- * bits 11 10  6 - SCART 1 Output Select:
- *       0  0  0 - undefined (reset position)
- *       0  1  0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
- *       1  0  0 - MONO input to SCART 1 Output
- *       1  1  0 - SCART 1 DA to SCART 1 Output
- *       0  0  1 - SCART 2 DA to SCART 1 Output
- *       0  1  1 - SCART 1 Input to SCART 1 Output
- *       1  1  1 - Mute SCART 1 Output
- *
- * bits 13 12  7 - SCART 2 Output Select (for devices with 2 Output SCART):
- *       0  0  0 - SCART 1 DA to SCART 2 Output (reset position)
- *       0  1  0 - SCART 1 Input to SCART 2 Output
- *       1  0  0 - MONO input to SCART 2 Output
- *       0  0  1 - SCART 2 DA to SCART 2 Output
- *       0  1  1 - SCART 2 Input to SCART 2 Output
- *       1  1  0 - Mute SCART 2 Output
- *
- * Bits 4 to 0 should be zero.
- * ----------------------------------------------------------------------- */
-
-static int scarts[3][9] = {
-       /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
-       /* SCART DSP Input select */
-       { 0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
-       /* SCART1 Output select */
-       { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
-       /* SCART2 Output select */
-       { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
-};
-
-static char *scart_names[] = {
-       "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
-};
-
-static void msp3400c_set_scart(struct i2c_client *client, int in, int out)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-
-       msp->in_scart=in;
-
-       if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
-               if (-1 == scarts[out][in])
-                       return;
-
-               msp->acb &= ~scarts[out][SCART_MASK];
-               msp->acb |=  scarts[out][in];
-       } else
-               msp->acb = 0xf60; /* Mute Input and SCART 1 Output */
-
-       msp3400_dbg("scart switch: %s => %d (ACB=0x%04x)\n",
-                                               scart_names[in], out, msp->acb);
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb);
-
-       /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
-{
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff);
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12);
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff);
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12);
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
-}
-
-static void msp3400c_setvolume(struct i2c_client *client,
-                              int muted, int left, int right)
- {
-       int vol = 0, val = 0, balance = 0;
-
-       if (!muted) {
-               /* 0x7f instead if 0x73 here has sound quality issues,
-                * probably due to overmodulation + clipping ... */
-               vol = (left > right) ? left : right;
-               val = (vol * 0x73 / 65535) << 8;
-       }
-       if (vol > 0) {
-               balance = ((right - left) * 127) / vol;
-       }
-
-       msp3400_dbg("setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
-               muted ? "on" : "off", left, right, val >> 8, balance);
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007,
-                                       muted ? 0x1 : (val | 0x1));
-       msp3400c_write(client, I2C_MSP3400C_DFP, 0x0001, balance << 8);
-}
-
-static void msp3400c_setbass(struct i2c_client *client, int bass)
-{
-       int val = ((bass-32768) * 0x60 / 65535) << 8;
-
-       msp3400_dbg("setbass: %d 0x%02x\n", bass, val >> 8);
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
-}
-
-static void msp3400c_settreble(struct i2c_client *client, int treble)
-{
-       int val = ((treble-32768) * 0x60 / 65535) << 8;
-
-       msp3400_dbg("settreble: %d 0x%02x\n",treble, val>>8);
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
-}
-
-static void msp3400c_setmode(struct i2c_client *client, int type)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int i;
-
-       msp3400_dbg("setmode: %d\n",type);
-       msp->mode       = type;
-       msp->audmode    = V4L2_TUNER_MODE_MONO;
-       msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb,          /* ad_cv */
-                      msp_init_data[type].ad_cv);
-
-       for (i = 5; i >= 0; i--)                                   /* fir 1 */
-               msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001,
-                              msp_init_data[type].fir1[i]);
-
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040);
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000);
-       for (i = 5; i >= 0; i--)
-               msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005,
-                              msp_init_data[type].fir2[i]);
-
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083,     /* MODE_REG */
-                      msp_init_data[type].mode_reg);
-
-       msp3400c_setcarrier(client, msp_init_data[type].cdo1,
-                           msp_init_data[type].cdo2);
-
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
-
-       if (dolby) {
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,
-                              0x0520); /* I2S1 */
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
-                              0x0620); /* I2S2 */
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
-                              msp_init_data[type].dfp_src);
-       } else {
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,
-                              msp_init_data[type].dfp_src);
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
-                              msp_init_data[type].dfp_src);
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
-                              msp_init_data[type].dfp_src);
-       }
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,
-                      msp_init_data[type].dfp_src);
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e,
-                      msp_init_data[type].dfp_matrix);
-
-       if (HAVE_NICAM(msp)) {
-               /* nicam prescale */
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */
-       }
-}
-
-/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */
-static int best_video_sound(int rxsubchans)
-{
-       if (rxsubchans & V4L2_TUNER_SUB_STEREO)
-               return V4L2_TUNER_MODE_STEREO;
-       if (rxsubchans & V4L2_TUNER_SUB_LANG1)
-               return V4L2_TUNER_MODE_LANG1;
-       if (rxsubchans & V4L2_TUNER_SUB_LANG2)
-               return V4L2_TUNER_MODE_LANG2;
-       return V4L2_TUNER_MODE_MONO;
-}
-
-/* turn on/off nicam + stereo */
-static void msp3400c_setstereo(struct i2c_client *client, int mode)
-{
-       static char *strmode[] = { "0", "mono", "stereo", "3",
-               "lang1", "5", "6", "7", "lang2"
-       };
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int nicam = 0;          /* channel source: FM/AM or nicam */
-       int src = 0;
-
-       if (IS_MSP34XX_G(msp)) {
-               /* this method would break everything, let's make sure
-                * it's never called
-                */
-               msp3400_dbg
-                   ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n",
-                    mode);
-               return;
-       }
-
-       /* switch demodulator */
-       switch (msp->mode) {
-       case MSP_MODE_FM_TERRA:
-               msp3400_dbg("FM setstereo: %s\n", strmode[mode]);
-               msp3400c_setcarrier(client,msp->second,msp->main);
-               switch (mode) {
-               case V4L2_TUNER_MODE_STEREO:
-                       msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);
-                       break;
-               case V4L2_TUNER_MODE_MONO:
-               case V4L2_TUNER_MODE_LANG1:
-               case V4L2_TUNER_MODE_LANG2:
-                       msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000);
-                       break;
-               }
-               break;
-       case MSP_MODE_FM_SAT:
-               msp3400_dbg("SAT setstereo: %s\n", strmode[mode]);
-               switch (mode) {
-               case V4L2_TUNER_MODE_MONO:
-                       msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-                       msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
-                       break;
-               case V4L2_TUNER_MODE_LANG1:
-                       msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
-                       break;
-               case V4L2_TUNER_MODE_LANG2:
-                       msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
-                       break;
-               }
-               break;
-       case MSP_MODE_FM_NICAM1:
-       case MSP_MODE_FM_NICAM2:
-       case MSP_MODE_AM_NICAM:
-               msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]);
-               msp3400c_setcarrier(client,msp->second,msp->main);
-               if (msp->nicam_on)
-                       nicam=0x0100;
-               break;
-       case MSP_MODE_BTSC:
-               msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]);
-               nicam=0x0300;
-               break;
-       case MSP_MODE_EXTERN:
-               msp3400_dbg("extern setstereo: %s\n",strmode[mode]);
-               nicam = 0x0200;
-               break;
-       case MSP_MODE_FM_RADIO:
-               msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]);
-               break;
-       default:
-               msp3400_dbg("mono setstereo\n");
-               return;
-       }
-
-       /* switch audio */
-       switch (best_video_sound(mode)) {
-       case V4L2_TUNER_MODE_STEREO:
-               src = 0x0020 | nicam;
-               break;
-       case V4L2_TUNER_MODE_MONO:
-               if (msp->mode == MSP_MODE_AM_NICAM) {
-                       msp3400_dbg("switching to AM mono\n");
-                       /* AM mono decoding is handled by tuner, not MSP chip */
-                       /* SCART switching control register */
-                       msp3400c_set_scart(client,SCART_MONO,0);
-                       src = 0x0200;
-                       break;
-               }
-       case V4L2_TUNER_MODE_LANG1:
-               src = 0x0000 | nicam;
-               break;
-       case V4L2_TUNER_MODE_LANG2:
-               src = 0x0010 | nicam;
-               break;
-       }
-       msp3400_dbg("setstereo final source/matrix = 0x%x\n", src);
-
-       if (dolby) {
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620);
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
-       } else {
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src);
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src);
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
-               msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
-       }
-}
-
-static void
-msp3400c_print_mode(struct i2c_client *client)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-
-       if (msp->main == msp->second) {
-               msp3400_dbg("mono sound carrier: %d.%03d MHz\n",
-                      msp->main/910000,(msp->main/910)%1000);
-       } else {
-               msp3400_dbg("main sound carrier: %d.%03d MHz\n",
-                      msp->main/910000,(msp->main/910)%1000);
-       }
-       if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2)
-               msp3400_dbg("NICAM/FM carrier   : %d.%03d MHz\n",
-                      msp->second/910000,(msp->second/910)%1000);
-       if (msp->mode == MSP_MODE_AM_NICAM)
-               msp3400_dbg("NICAM/AM carrier   : %d.%03d MHz\n",
-                      msp->second/910000,(msp->second/910)%1000);
-       if (msp->mode == MSP_MODE_FM_TERRA &&
-           msp->main != msp->second) {
-               msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n",
-                      msp->second/910000,(msp->second/910)%1000);
-       }
-}
-
-#define MSP3400_MAX 4
-static struct i2c_client *msps[MSP3400_MAX];
-static void msp3400c_restore_dfp(struct i2c_client *client)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int i;
-
-       for (i = 0; i < DFP_COUNT; i++) {
-               if (-1 == msp->dfp_regs[i])
-                       continue;
-               msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
-       }
-}
-
-/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */
-static int msp3400c_write_dfp_with_default(struct i2c_client *client,
-                                       int addr, int default_value)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int value = default_value;
-       if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr])
-               value = msp->dfp_regs[addr];
-       return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value);
-}
-
-/* ----------------------------------------------------------------------- */
-
-struct REGISTER_DUMP {
-       int   addr;
-       char *name;
-};
-
-struct REGISTER_DUMP d1[] = {
-       {0x007e, "autodetect"},
-       {0x0023, "C_AD_BITS "},
-       {0x0038, "ADD_BITS  "},
-       {0x003e, "CIB_BITS  "},
-       {0x0057, "ERROR_RATE"},
-};
-
-static int autodetect_stereo(struct i2c_client *client)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int val;
-       int rxsubchans = msp->rxsubchans;
-       int newnicam   = msp->nicam_on;
-       int update = 0;
-
-       switch (msp->mode) {
-       case MSP_MODE_FM_TERRA:
-               val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
-               if (val > 32767)
-                       val -= 65536;
-               msp3400_dbg("stereo detect register: %d\n",val);
-               if (val > 4096) {
-                       rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
-               } else if (val < -4096) {
-                       rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-               } else {
-                       rxsubchans = V4L2_TUNER_SUB_MONO;
-               }
-               newnicam = 0;
-               break;
-       case MSP_MODE_FM_NICAM1:
-       case MSP_MODE_FM_NICAM2:
-       case MSP_MODE_AM_NICAM:
-               val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
-               msp3400_dbg("nicam sync=%d, mode=%d\n",
-                       val & 1, (val & 0x1e) >> 1);
-
-               if (val & 1) {
-                       /* nicam synced */
-                       switch ((val & 0x1e) >> 1)  {
-                       case 0:
-                       case 8:
-                               rxsubchans = V4L2_TUNER_SUB_STEREO;
-                               break;
-                       case 1:
-                       case 9:
-                               rxsubchans = V4L2_TUNER_SUB_MONO
-                                       | V4L2_TUNER_SUB_LANG1;
-                               break;
-                       case 2:
-                       case 10:
-                               rxsubchans = V4L2_TUNER_SUB_MONO
-                                       | V4L2_TUNER_SUB_LANG1
-                                       | V4L2_TUNER_SUB_LANG2;
-                               break;
-                       default:
-                               rxsubchans = V4L2_TUNER_SUB_MONO;
-                               break;
-                       }
-                       newnicam=1;
-               } else {
-                       newnicam = 0;
-                       rxsubchans = V4L2_TUNER_SUB_MONO;
-               }
-               break;
-       case MSP_MODE_BTSC:
-               val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
-               msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
-                       val,
-                       (val & 0x0002) ? "no"     : "yes",
-                       (val & 0x0004) ? "no"     : "yes",
-                       (val & 0x0040) ? "stereo" : "mono",
-                       (val & 0x0080) ? ", nicam 2nd mono" : "",
-                       (val & 0x0100) ? ", bilingual/SAP"  : "");
-               rxsubchans = V4L2_TUNER_SUB_MONO;
-               if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
-               if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
-               break;
-       }
-       if (rxsubchans != msp->rxsubchans) {
-               update = 1;
-               msp3400_dbg("watch: rxsubchans %d => %d\n",
-                       msp->rxsubchans,rxsubchans);
-               msp->rxsubchans = rxsubchans;
-       }
-       if (newnicam != msp->nicam_on) {
-               update = 1;
-               msp3400_dbg("watch: nicam %d => %d\n",
-                       msp->nicam_on,newnicam);
-               msp->nicam_on = newnicam;
-       }
-       return update;
-}
-
-/*
- * A kernel thread for msp3400 control -- we don't want to block the
- * in the ioctl while doing the sound carrier & stereo detect
- */
-
-static int msp34xx_sleep(struct msp3400c *msp, int timeout)
-{
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&msp->wq, &wait);
-       if (!kthread_should_stop()) {
-               if (timeout < 0) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule();
-               } else {
-                       schedule_timeout_interruptible
-                                               (msecs_to_jiffies(timeout));
-               }
-       }
-
-       remove_wait_queue(&msp->wq, &wait);
-       try_to_freeze();
-       return msp->restart;
-}
-
-/* stereo/multilang monitoring */
-static void watch_stereo(struct i2c_client *client)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-
-       if (autodetect_stereo(client)) {
-               if (msp->stereo & V4L2_TUNER_MODE_STEREO)
-                       msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
-               else if (msp->stereo & VIDEO_SOUND_LANG1)
-                       msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
-               else
-                       msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-       }
-
-       if (once)
-               msp->watch_stereo = 0;
-}
-
-
-static int msp3400c_thread(void *data)
-{
-       struct i2c_client *client = data;
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       struct CARRIER_DETECT *cd;
-       int count, max1,max2,val1,val2, val,this;
-
-
-       msp3400_info("msp3400 daemon started\n");
-       for (;;) {
-               msp3400_dbg_mediumvol("msp3400 thread: sleep\n");
-               msp34xx_sleep(msp,-1);
-               msp3400_dbg_mediumvol("msp3400 thread: wakeup\n");
-
-       restart:
-               msp3400_dbg("thread: restart scan\n");
-               msp->restart = 0;
-               if (kthread_should_stop())
-                       break;
-
-               if (VIDEO_MODE_RADIO == msp->norm ||
-                   MSP_MODE_EXTERN  == msp->mode) {
-                       /* no carrier scan, just unmute */
-                       msp3400_info("thread: no carrier scan\n");
-                       msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-                       continue;
-               }
-
-               /* mute */
-               msp3400c_setvolume(client, msp->muted, 0, 0);
-               msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
-               val1 = val2 = 0;
-               max1 = max2 = -1;
-               msp->watch_stereo = 0;
-
-               /* some time for the tuner to sync */
-               if (msp34xx_sleep(msp,200))
-                       goto restart;
-
-               /* carrier detect pass #1 -- main carrier */
-               cd = carrier_detect_main;
-               count = CARRIER_COUNT(carrier_detect_main);
-
-               if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
-                       /* autodetect doesn't work well with AM ... */
-                       max1 = 3;
-                       count = 0;
-                       msp3400_dbg("AM sound override\n");
-               }
-
-               for (this = 0; this < count; this++) {
-                       msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
-                       if (msp34xx_sleep(msp,100))
-                               goto restart;
-                       val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
-                       if (val > 32767)
-                               val -= 65536;
-                       if (val1 < val)
-                               val1 = val, max1 = this;
-                       msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name);
-               }
-
-               /* carrier detect pass #2 -- second (stereo) carrier */
-               switch (max1) {
-               case 1: /* 5.5 */
-                       cd = carrier_detect_55;
-                       count = CARRIER_COUNT(carrier_detect_55);
-                       break;
-               case 3: /* 6.5 */
-                       cd = carrier_detect_65;
-                       count = CARRIER_COUNT(carrier_detect_65);
-                       break;
-               case 0: /* 4.5 */
-               case 2: /* 6.0 */
-               default:
-                       cd = NULL;
-                       count = 0;
-                       break;
-               }
-
-               if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
-                       /* autodetect doesn't work well with AM ... */
-                       cd = NULL;
-                       count = 0;
-                       max2 = 0;
-               }
-               for (this = 0; this < count; this++) {
-                       msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
-                       if (msp34xx_sleep(msp,100))
-                               goto restart;
-                       val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
-                       if (val > 32767)
-                               val -= 65536;
-                       if (val2 < val)
-                               val2 = val, max2 = this;
-                       msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name);
-               }
-
-               /* programm the msp3400 according to the results */
-               msp->main   = carrier_detect_main[max1].cdo;
-               switch (max1) {
-               case 1: /* 5.5 */
-                       if (max2 == 0) {
-                               /* B/G FM-stereo */
-                               msp->second = carrier_detect_55[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-                               msp->nicam_on = 0;
-                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-                               msp->watch_stereo = 1;
-                       } else if (max2 == 1 && HAVE_NICAM(msp)) {
-                               /* B/G NICAM */
-                               msp->second = carrier_detect_55[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
-                               msp->nicam_on = 1;
-                               msp3400c_setcarrier(client, msp->second, msp->main);
-                               msp->watch_stereo = 1;
-                       } else {
-                               goto no_second;
-                       }
-                       break;
-               case 2: /* 6.0 */
-                       /* PAL I NICAM */
-                       msp->second = MSP_CARRIER(6.552);
-                       msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
-                       msp->nicam_on = 1;
-                       msp3400c_setcarrier(client, msp->second, msp->main);
-                       msp->watch_stereo = 1;
-                       break;
-               case 3: /* 6.5 */
-                       if (max2 == 1 || max2 == 2) {
-                               /* D/K FM-stereo */
-                               msp->second = carrier_detect_65[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-                               msp->nicam_on = 0;
-                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-                               msp->watch_stereo = 1;
-                       } else if (max2 == 0 &&
-                                  msp->norm == VIDEO_MODE_SECAM) {
-                               /* L NICAM or AM-mono */
-                               msp->second = carrier_detect_65[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_AM_NICAM);
-                               msp->nicam_on = 0;
-                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-                               msp3400c_setcarrier(client, msp->second, msp->main);
-                               /* volume prescale for SCART (AM mono input) */
-                               msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
-                               msp->watch_stereo = 1;
-                       } else if (max2 == 0 && HAVE_NICAM(msp)) {
-                               /* D/K NICAM */
-                               msp->second = carrier_detect_65[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
-                               msp->nicam_on = 1;
-                               msp3400c_setcarrier(client, msp->second, msp->main);
-                               msp->watch_stereo = 1;
-                       } else {
-                               goto no_second;
-                       }
-                       break;
-               case 0: /* 4.5 */
-               default:
-               no_second:
-                       msp->second = carrier_detect_main[max1].cdo;
-                       msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-                       msp->nicam_on = 0;
-                       msp3400c_setcarrier(client, msp->second, msp->main);
-                       msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-                       break;
-               }
-
-               /* unmute */
-               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-               msp3400c_restore_dfp(client);
-
-               if (debug)
-                       msp3400c_print_mode(client);
-
-               /* monitor tv audio mode */
-               while (msp->watch_stereo) {
-                       if (msp34xx_sleep(msp,5000))
-                               goto restart;
-                       watch_stereo(client);
-               }
-       }
-       msp3400_dbg("thread: exit\n");
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-/* this one uses the automatic sound standard detection of newer           */
-/* msp34xx chip versions                                                   */
-
-static struct MODES {
-       int retval;
-       int main, second;
-       char *name;
-} modelist[] = {
-       { 0x0000, 0, 0, "ERROR" },
-       { 0x0001, 0, 0, "autodetect start" },
-       { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72  M Dual FM-Stereo" },
-       { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74  B/G Dual FM-Stereo" },
-       { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25  D/K1 Dual FM-Stereo" },
-       { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74  D/K2 Dual FM-Stereo" },
-       { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  D/K FM-Mono (HDEV3)" },
-       { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },
-       { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },
-       { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },
-       { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },
-       { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },
-       { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },
-       { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },
-       { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },
-       { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7  FM-Stereo Radio" },
-       { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  SAT-Mono" },
-       { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20  SAT-Stereo" },
-       { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2  SAT ADR" },
-       {     -1, 0, 0, NULL }, /* EOF */
-};
-
-static inline const char *msp34xx_standard_mode_name(int mode)
-{
-       int i;
-       for (i = 0; modelist[i].name != NULL; i++)
-               if (modelist[i].retval == mode)
-                       return modelist[i].name;
-       return "unknown";
-}
-
-static int msp34xx_modus(struct i2c_client *client, int norm)
-{
-       switch (norm) {
-       case VIDEO_MODE_PAL:
-               msp3400_dbg("video mode selected to PAL\n");
-
-#if 1
-               /* experimental: not sure this works with all chip versions */
-               return 0x7003;
-#else
-               /* previous value, try this if it breaks ... */
-               return 0x1003;
-#endif
-       case VIDEO_MODE_NTSC:  /* BTSC */
-               msp3400_dbg("video mode selected to NTSC\n");
-               return 0x2003;
-       case VIDEO_MODE_SECAM:
-               msp3400_dbg("video mode selected to SECAM\n");
-               return 0x0003;
-       case VIDEO_MODE_RADIO:
-               msp3400_dbg("video mode selected to Radio\n");
-               return 0x0003;
-       case VIDEO_MODE_AUTO:
-               msp3400_dbg("video mode selected to Auto\n");
-               return 0x2003;
-       default:
-               return 0x0003;
-       }
-}
-
-static int msp34xx_standard(int norm)
-{
-       switch (norm) {
-       case VIDEO_MODE_PAL:
-               return 1;
-       case VIDEO_MODE_NTSC:  /* BTSC */
-               return 0x0020;
-       case VIDEO_MODE_SECAM:
-               return 1;
-       case VIDEO_MODE_RADIO:
-               return 0x0040;
-       default:
-               return 1;
-       }
-}
-
-static int msp3410d_thread(void *data)
-{
-       struct i2c_client *client = data;
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int mode,val,i,std;
-
-       msp3400_info("msp3410 daemon started\n");
-
-       for (;;) {
-               msp3400_dbg_mediumvol("msp3410 thread: sleep\n");
-               msp34xx_sleep(msp,-1);
-               msp3400_dbg_mediumvol("msp3410 thread: wakeup\n");
-
-       restart:
-               msp3400_dbg("thread: restart scan\n");
-               msp->restart = 0;
-               if (kthread_should_stop())
-                       break;
-
-               if (msp->mode == MSP_MODE_EXTERN) {
-                       /* no carrier scan needed, just unmute */
-                       msp3400_dbg("thread: no carrier scan\n");
-               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-                       continue;
-               }
-
-               /* put into sane state (and mute) */
-               msp3400c_reset(client);
-
-               /* some time for the tuner to sync */
-               if (msp34xx_sleep(msp,200))
-                       goto restart;
-
-               /* start autodetect */
-               mode = msp34xx_modus(client, msp->norm);
-               std  = msp34xx_standard(msp->norm);
-               msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
-               msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
-               msp->watch_stereo = 0;
-
-               if (debug)
-                       msp3400_dbg("setting mode: %s (0x%04x)\n",
-                              msp34xx_standard_mode_name(std) ,std);
-
-               if (std != 1) {
-                       /* programmed some specific mode */
-                       val = std;
-               } else {
-                       /* triggered autodetect */
-                       for (;;) {
-                               if (msp34xx_sleep(msp,100))
-                                       goto restart;
-
-                               /* check results */
-                               val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
-                               if (val < 0x07ff)
-                                       break;
-                               msp3400_dbg("detection still in progress\n");
-                       }
-               }
-               for (i = 0; modelist[i].name != NULL; i++)
-                       if (modelist[i].retval == val)
-                               break;
-               msp3400_dbg("current mode: %s (0x%04x)\n",
-                       modelist[i].name ? modelist[i].name : "unknown",
-                       val);
-               msp->main   = modelist[i].main;
-               msp->second = modelist[i].second;
-
-               if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
-                       /* autodetection has failed, let backup */
-                       msp3400_dbg("autodetection failed,"
-                               " switching to backup mode: %s (0x%04x)\n",
-                               modelist[8].name ? modelist[8].name : "unknown",val);
-                       val = 0x0009;
-                       msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
-               }
-
-               /* set various prescales */
-               msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */
-               msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
-               msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */
-
-               /* set stereo */
-               switch (val) {
-               case 0x0008: /* B/G NICAM */
-               case 0x000a: /* I NICAM */
-                       if (val == 0x0008)
-                               msp->mode = MSP_MODE_FM_NICAM1;
-                       else
-                               msp->mode = MSP_MODE_FM_NICAM2;
-                       /* just turn on stereo */
-                       msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       msp->nicam_on = 1;
-                       msp->watch_stereo = 1;
-                       msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
-                       break;
-               case 0x0009:
-                       msp->mode = MSP_MODE_AM_NICAM;
-                       msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       msp->nicam_on = 1;
-                       msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
-                       msp->watch_stereo = 1;
-                       break;
-               case 0x0020: /* BTSC */
-                       /* just turn on stereo */
-                       msp->mode = MSP_MODE_BTSC;
-                       msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       msp->nicam_on = 0;
-                       msp->watch_stereo = 1;
-                       msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
-                       break;
-               case 0x0040: /* FM radio */
-                       msp->mode   = MSP_MODE_FM_RADIO;
-                       msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       msp->audmode = V4L2_TUNER_MODE_STEREO;
-                       msp->nicam_on = 0;
-                       msp->watch_stereo = 0;
-                       /* not needed in theory if HAVE_RADIO(), but
-                          short programming enables carrier mute */
-                       msp3400c_setmode(client,MSP_MODE_FM_RADIO);
-                       msp3400c_setcarrier(client, MSP_CARRIER(10.7),
-                                           MSP_CARRIER(10.7));
-                       /* scart routing */
-                       msp3400c_set_scart(client,SCART_IN2,0);
-                       /* msp34xx does radio decoding */
-                       msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020);
-                       msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020);
-                       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020);
-                       break;
-               case 0x0003:
-               case 0x0004:
-               case 0x0005:
-                       msp->mode   = MSP_MODE_FM_TERRA;
-                       msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       msp->audmode = V4L2_TUNER_MODE_MONO;
-                       msp->nicam_on = 0;
-                       msp->watch_stereo = 1;
-                       break;
-               }
-
-               /* unmute, restore misc registers */
-               msp3400c_setbass(client, msp->bass);
-               msp3400c_settreble(client, msp->treble);
-               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-               msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);
-               msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-               msp3400c_restore_dfp(client);
-
-               /* monitor tv audio mode */
-               while (msp->watch_stereo) {
-                       if (msp34xx_sleep(msp,5000))
-                               goto restart;
-                       watch_stereo(client);
-               }
-       }
-       msp3400_dbg("thread: exit\n");
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-/* msp34xxG + (simpler no-thread)                                          */
-/* this one uses both automatic standard detection and automatic sound     */
-/* select which are available in the newer G versions                      */
-/* struct msp: only norm, acb and source are really used in this mode      */
-
-static void msp34xxg_set_source(struct i2c_client *client, int source);
-
-/* (re-)initialize the msp34xxg, according to the current norm in msp->norm
- * return 0 if it worked, -1 if it failed
- */
-static int msp34xxg_reset(struct i2c_client *client)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int modus,std;
-
-       if (msp3400c_reset(client))
-               return -1;
-
-       /* make sure that input/output is muted (paranoid mode) */
-       if (msp3400c_write(client,
-                          I2C_MSP3400C_DFP,
-                          0x13, /* ACB */
-                          0x0f20 /* mute DSP input, mute SCART 1 */))
-               return -1;
-
-       msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-
-       /* step-by-step initialisation, as described in the manual */
-       modus = msp34xx_modus(client, msp->norm);
-       std   = msp34xx_standard(msp->norm);
-       modus &= ~0x03; /* STATUS_CHANGE=0 */
-       modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION=1 */
-       if (msp3400c_write(client,
-                          I2C_MSP3400C_DEM,
-                          0x30/*MODUS*/,
-                          modus))
-               return -1;
-       if (msp3400c_write(client,
-                          I2C_MSP3400C_DEM,
-                          0x20/*standard*/,
-                          std))
-               return -1;
-
-       /* write the dfps that may have an influence on
-          standard/audio autodetection right now */
-       msp34xxg_set_source(client, msp->source);
-
-       if (msp3400c_write_dfp_with_default(client, 0x0e,       /* AM/FM Prescale */
-                                           0x3000
-                                           /* default: [15:8] 75khz deviation */
-           ))
-               return -1;
-
-       if (msp3400c_write_dfp_with_default(client, 0x10,       /* NICAM Prescale */
-                                           0x5a00
-                                           /* default: 9db gain (as recommended) */
-           ))
-               return -1;
-
-       return 0;
-}
-
-static int msp34xxg_thread(void *data)
-{
-       struct i2c_client *client = data;
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int val, std, i;
-
-       msp3400_info("msp34xxg daemon started\n");
-
-       msp->source = 1; /* default */
-       for (;;) {
-               msp3400_dbg_mediumvol("msp34xxg thread: sleep\n");
-               msp34xx_sleep(msp,-1);
-               msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n");
-
-       restart:
-               msp3400_dbg("thread: restart scan\n");
-               msp->restart = 0;
-               if (kthread_should_stop())
-                       break;
-
-               /* setup the chip*/
-               msp34xxg_reset(client);
-               std = standard;
-               if (std != 0x01)
-                       goto unmute;
-
-               /* watch autodetect */
-               msp3400_dbg("triggered autodetect, waiting for result\n");
-               for (i = 0; i < 10; i++) {
-                       if (msp34xx_sleep(msp,100))
-                               goto restart;
-
-                       /* check results */
-                       val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
-                       if (val < 0x07ff) {
-                               std = val;
-                               break;
-                       }
-                       msp3400_dbg("detection still in progress\n");
-               }
-               if (0x01 == std) {
-                       msp3400_dbg("detection still in progress after 10 tries. giving up.\n");
-                       continue;
-               }
-
-       unmute:
-               msp3400_dbg("current mode: %s (0x%04x)\n",
-                       msp34xx_standard_mode_name(std), std);
-
-               /* unmute: dispatch sound to scart output, set scart volume */
-               msp3400_dbg("unmute\n");
-
-               msp3400c_setbass(client, msp->bass);
-               msp3400c_settreble(client, msp->treble);
-               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-
-               /* restore ACB */
-               if (msp3400c_write(client,
-                                  I2C_MSP3400C_DFP,
-                                  0x13, /* ACB */
-                                  msp->acb))
-                       return -1;
-
-               msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-       }
-       msp3400_dbg("thread: exit\n");
-       return 0;
-}
-
-/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
- * the value for source is the same as bit 15:8 of DFP registers 0x08,
- * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
- *
- * this function replaces msp3400c_setstereo
- */
-static void msp34xxg_set_source(struct i2c_client *client, int source)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-
-       /* fix matrix mode to stereo and let the msp choose what
-        * to output according to 'source', as recommended
-        * for MONO (source==0) downmixing set bit[7:0] to 0x30
-        */
-       int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);
-       msp3400_dbg("set source to %d (0x%x)\n", source, value);
-       msp3400c_write(client,
-                      I2C_MSP3400C_DFP,
-                      0x08, /* Loudspeaker Output */
-                      value);
-       msp3400c_write(client,
-                      I2C_MSP3400C_DFP,
-                      0x0a, /* SCART1 DA Output */
-                      value);
-       msp3400c_write(client,
-                      I2C_MSP3400C_DFP,
-                      0x0c, /* Quasi-peak detector */
-                      value);
-       /*
-        * set identification threshold. Personally, I
-        * I set it to a higher value that the default
-        * of 0x190 to ignore noisy stereo signals.
-        * this needs tuning. (recommended range 0x00a0-0x03c0)
-        * 0x7f0 = forced mono mode
-        */
-       msp3400c_write(client,
-                      I2C_MSP3400C_DEM,
-                      0x22, /* a2 threshold for stereo/bilingual */
-                      stereo_threshold);
-       msp->source=source;
-}
-
-static void msp34xxg_detect_stereo(struct i2c_client *client)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-
-       int status = msp3400c_read(client,
-                                  I2C_MSP3400C_DEM,
-                                  0x0200 /* STATUS */);
-       int is_bilingual = status&0x100;
-       int is_stereo = status&0x40;
-
-       msp->rxsubchans = 0;
-       if (is_stereo)
-               msp->rxsubchans |= V4L2_TUNER_SUB_STEREO;
-       else
-               msp->rxsubchans |= V4L2_TUNER_SUB_MONO;
-       if (is_bilingual) {
-               msp->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2;
-               /* I'm supposed to check whether it's SAP or not
-                * and set only LANG2/SAP in this case. Yet, the MSP
-                * does a lot of work to hide this and handle everything
-                * the same way. I don't want to work around it so unless
-                * this is a problem, I'll handle SAP just like lang1/lang2.
-                */
-       }
-       msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
-               status, is_stereo, is_bilingual, msp->rxsubchans);
-}
-
-static void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
-{
-       struct msp3400c *msp = i2c_get_clientdata(client);
-       int source;
-
-       switch (audmode) {
-       case V4L2_TUNER_MODE_MONO:
-               source=0; /* mono only */
-               break;
-       case V4L2_TUNER_MODE_STEREO:
-               source=1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
-               /* problem: that could also mean 2 (scart input) */
-               break;
-       case V4L2_TUNER_MODE_LANG1:
-               source=3; /* stereo or A */
-               break;
-       case V4L2_TUNER_MODE_LANG2:
-               source=4; /* stereo or B */
-               break;
-       default:
-               audmode = 0;
-               source  = 1;
-               break;
-       }
-       msp->audmode = audmode;
-       msp34xxg_set_source(client, source);
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-static int msp_attach(struct i2c_adapter *adap, int addr, int kind);
-static int msp_detach(struct i2c_client *client);
-static int msp_probe(struct i2c_adapter *adap);
-static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
-
-static int msp_suspend(struct device * dev, pm_message_t state);
-static int msp_resume(struct device * dev);
-
-static void msp_wake_thread(struct i2c_client *client);
-
-static struct i2c_driver driver = {
-       .id             = I2C_DRIVERID_MSP3400,
-       .attach_adapter = msp_probe,
-       .detach_client  = msp_detach,
-       .command        = msp_command,
-       .driver = {
-               .name    = "i2c msp3400 driver",
-               .suspend = msp_suspend,
-               .resume  = msp_resume,
-       },
-};
-
-static struct i2c_client client_template =
-{
-       .name      = "(unset)",
-       .driver    = &driver,
-};
-
-static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       struct msp3400c *msp;
-       struct i2c_client *client = &client_template;
-       int (*thread_func)(void *data) = NULL;
-       int i;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       if (-1 == msp3400c_reset(&client_template)) {
-               msp3400_dbg("no chip found\n");
-               return -1;
-       }
-
-       if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
-               return -ENOMEM;
-       memcpy(client,&client_template,sizeof(struct i2c_client));
-       if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {
-               kfree(client);
-               return -ENOMEM;
-       }
-
-       memset(msp,0,sizeof(struct msp3400c));
-       msp->norm = VIDEO_MODE_NTSC;
-       msp->left = 58880;      /* 0db gain */
-       msp->right = 58880;     /* 0db gain */
-       msp->bass = 32768;
-       msp->treble = 32768;
-       msp->input = -1;
-       msp->muted = 0;
-       msp->i2s_mode = 0;
-       for (i = 0; i < DFP_COUNT; i++)
-               msp->dfp_regs[i] = -1;
-
-       i2c_set_clientdata(client, msp);
-       init_waitqueue_head(&msp->wq);
-
-       if (-1 == msp3400c_reset(client)) {
-               kfree(msp);
-               kfree(client);
-               msp3400_dbg("no chip found\n");
-               return -1;
-       }
-
-       msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e);
-       if (-1 != msp->rev1)
-               msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f);
-       if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
-               kfree(msp);
-               kfree(client);
-               msp3400_dbg("error while reading chip version\n");
-               return -1;
-       }
-       msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);
-
-       msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-
-       snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
-                ((msp->rev1>>4)&0x0f) + '3',
-                (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@',
-                ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
-
-       msp->opmode = opmode;
-       if (OPMODE_AUTO == msp->opmode) {
-               if (HAVE_SIMPLER(msp))
-                       msp->opmode = OPMODE_SIMPLER;
-               else if (HAVE_SIMPLE(msp))
-                       msp->opmode = OPMODE_SIMPLE;
-               else
-                       msp->opmode = OPMODE_MANUAL;
-       }
-
-       /* hello world :-) */
-       msp3400_info("chip=%s", client->name);
-       if (HAVE_NICAM(msp))
-               printk(" +nicam");
-       if (HAVE_SIMPLE(msp))
-               printk(" +simple");
-       if (HAVE_SIMPLER(msp))
-               printk(" +simpler");
-       if (HAVE_RADIO(msp))
-               printk(" +radio");
-
-       /* version-specific initialization */
-       switch (msp->opmode) {
-       case OPMODE_MANUAL:
-               printk(" mode=manual");
-               thread_func = msp3400c_thread;
-               break;
-       case OPMODE_SIMPLE:
-               printk(" mode=simple");
-               thread_func = msp3410d_thread;
-               break;
-       case OPMODE_SIMPLER:
-               printk(" mode=simpler");
-               thread_func = msp34xxg_thread;
-               break;
-       }
-       printk("\n");
-
-       /* startup control thread if needed */
-       if (thread_func) {
-               msp->kthread = kthread_run(thread_func, client, "msp34xx");
-
-               if (NULL == msp->kthread)
-                       msp3400_warn("kernel_thread() failed\n");
-               msp_wake_thread(client);
-       }
-
-       /* done */
-       i2c_attach_client(client);
-
-       /* update our own array */
-       for (i = 0; i < MSP3400_MAX; i++) {
-               if (NULL == msps[i]) {
-                       msps[i] = client;
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int msp_detach(struct i2c_client *client)
-{
-       struct msp3400c *msp  = i2c_get_clientdata(client);
-       int i;
-
-       /* shutdown control thread */
-       if (msp->kthread) {
-               msp->restart = 1;
-               kthread_stop(msp->kthread);
-       }
-       msp3400c_reset(client);
-
-       /* update our own array */
-       for (i = 0; i < MSP3400_MAX; i++) {
-               if (client == msps[i]) {
-                       msps[i] = NULL;
-                       break;
-               }
-       }
-
-       i2c_detach_client(client);
-
-       kfree(msp);
-       kfree(client);
-       return 0;
-}
-
-static int msp_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, msp_attach);
-       return 0;
-}
-
-static void msp_wake_thread(struct i2c_client *client)
-{
-       struct msp3400c *msp  = i2c_get_clientdata(client);
-
-       if (NULL == msp->kthread)
-               return;
-       msp3400c_setvolume(client,msp->muted,0,0);
-       msp->watch_stereo = 0;
-       msp->restart = 1;
-       wake_up_interruptible(&msp->wq);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int mode_v4l2_to_v4l1(int rxsubchans)
-{
-       int mode = 0;
-
-       if (rxsubchans & V4L2_TUNER_SUB_STEREO)
-               mode |= VIDEO_SOUND_STEREO;
-       if (rxsubchans & V4L2_TUNER_SUB_LANG2)
-               mode |= VIDEO_SOUND_LANG2;
-       if (rxsubchans & V4L2_TUNER_SUB_LANG1)
-               mode |= VIDEO_SOUND_LANG1;
-       if (0 == mode)
-               mode |= VIDEO_SOUND_MONO;
-       return mode;
-}
-
-static int mode_v4l1_to_v4l2(int mode)
-{
-       if (mode & VIDEO_SOUND_STEREO)
-               return V4L2_TUNER_MODE_STEREO;
-       if (mode & VIDEO_SOUND_LANG2)
-               return V4L2_TUNER_MODE_LANG2;
-       if (mode & VIDEO_SOUND_LANG1)
-               return V4L2_TUNER_MODE_LANG1;
-       return V4L2_TUNER_MODE_MONO;
-}
-
-static void msp_any_detect_stereo(struct i2c_client *client)
-{
-       struct msp3400c *msp  = i2c_get_clientdata(client);
-
-       switch (msp->opmode) {
-       case OPMODE_MANUAL:
-       case OPMODE_SIMPLE:
-               autodetect_stereo(client);
-               break;
-       case OPMODE_SIMPLER:
-               msp34xxg_detect_stereo(client);
-               break;
-       }
-}
-
-static void msp_any_set_audmode(struct i2c_client *client, int audmode)
-{
-       struct msp3400c *msp  = i2c_get_clientdata(client);
-
-       switch (msp->opmode) {
-       case OPMODE_MANUAL:
-       case OPMODE_SIMPLE:
-               msp->watch_stereo = 0;
-               msp3400c_setstereo(client, audmode);
-               break;
-       case OPMODE_SIMPLER:
-               msp34xxg_set_audmode(client, audmode);
-               break;
-       }
-}
-
-
-static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       struct msp3400c *msp  = i2c_get_clientdata(client);
-       __u16           *sarg = arg;
-       int scart = 0;
-
-       switch (cmd) {
-
-       case AUDC_SET_INPUT:
-               msp3400_dbg("AUDC_SET_INPUT(%d)\n",*sarg);
-
-               if (*sarg == msp->input)
-                       break;
-               msp->input = *sarg;
-               switch (*sarg) {
-               case AUDIO_RADIO:
-                       /* Hauppauge uses IN2 for the radio */
-                       msp->mode   = MSP_MODE_FM_RADIO;
-                       scart       = SCART_IN2;
-                       break;
-               case AUDIO_EXTERN_1:
-                       /* IN1 is often used for external input ... */
-                       msp->mode   = MSP_MODE_EXTERN;
-                       scart       = SCART_IN1;
-                       break;
-               case AUDIO_EXTERN_2:
-                       /* ... sometimes it is IN2 through ;) */
-                       msp->mode   = MSP_MODE_EXTERN;
-                       scart       = SCART_IN2;
-                       break;
-               case AUDIO_TUNER:
-                       msp->mode   = -1;
-                       break;
-               default:
-                       if (*sarg & AUDIO_MUTE)
-                               msp3400c_set_scart(client,SCART_MUTE,0);
-                       break;
-               }
-               if (scart) {
-                       msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       msp->audmode = V4L2_TUNER_MODE_STEREO;
-                       msp3400c_set_scart(client,scart,0);
-                       msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
-                       if (msp->opmode != OPMODE_SIMPLER)
-                               msp3400c_setstereo(client, msp->audmode);
-               }
-               msp_wake_thread(client);
-               break;
-
-       case AUDC_SET_RADIO:
-               msp3400_dbg("AUDC_SET_RADIO\n");
-               msp->norm = VIDEO_MODE_RADIO;
-               msp3400_dbg("switching to radio mode\n");
-               msp->watch_stereo = 0;
-               switch (msp->opmode) {
-               case OPMODE_MANUAL:
-                       /* set msp3400 to FM radio mode */
-                       msp3400c_setmode(client,MSP_MODE_FM_RADIO);
-                       msp3400c_setcarrier(client, MSP_CARRIER(10.7),
-                                           MSP_CARRIER(10.7));
-                       msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-                       break;
-               case OPMODE_SIMPLE:
-               case OPMODE_SIMPLER:
-                       /* the thread will do for us */
-                       msp_wake_thread(client);
-                       break;
-               }
-               break;
-               /* work-in-progress:  hook to control the DFP registers */
-       case MSP_SET_DFPREG:
-       {
-               struct msp_dfpreg *r = arg;
-               int i;
-
-               if (r->reg < 0 || r->reg >= DFP_COUNT)
-                       return -EINVAL;
-               for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++)
-                       if (r->reg == bl_dfp[i])
-                               return -EINVAL;
-               msp->dfp_regs[r->reg] = r->value;
-               msp3400c_write(client, I2C_MSP3400C_DFP, r->reg, r->value);
-               return 0;
-       }
-       case MSP_GET_DFPREG:
-       {
-               struct msp_dfpreg *r = arg;
-
-               if (r->reg < 0 || r->reg >= DFP_COUNT)
-                       return -EINVAL;
-               r->value = msp3400c_read(client, I2C_MSP3400C_DFP, r->reg);
-               return 0;
-       }
-
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               msp3400_dbg("VIDIOCGAUDIO\n");
-               va->flags |= VIDEO_AUDIO_VOLUME |
-                       VIDEO_AUDIO_BASS |
-                       VIDEO_AUDIO_TREBLE |
-                       VIDEO_AUDIO_MUTABLE;
-               if (msp->muted)
-                       va->flags |= VIDEO_AUDIO_MUTE;
-
-               if (msp->muted)
-                       va->flags |= VIDEO_AUDIO_MUTE;
-               va->volume = MAX(msp->left, msp->right);
-               va->balance = (32768 * MIN(msp->left, msp->right)) /
-                   (va->volume ? va->volume : 1);
-               va->balance = (msp->left < msp->right) ?
-                   (65535 - va->balance) : va->balance;
-               if (0 == va->volume)
-                       va->balance = 32768;
-               va->bass = msp->bass;
-               va->treble = msp->treble;
-
-               msp_any_detect_stereo(client);
-               va->mode = mode_v4l2_to_v4l1(msp->rxsubchans);
-               break;
-       }
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               msp3400_dbg("VIDIOCSAUDIO\n");
-               msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
-               msp->left = (MIN(65536 - va->balance, 32768) *
-                            va->volume) / 32768;
-               msp->right = (MIN(va->balance, 32768) * va->volume) / 32768;
-               msp->bass = va->bass;
-               msp->treble = va->treble;
-               msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n",
-                       va->volume);
-               msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n",
-                       va->balance);
-               msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n",
-                       va->flags);
-               msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n",
-                       msp->left);
-               msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n",
-                       msp->right);
-               msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n",
-                       msp->bass);
-               msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n",
-                       msp->treble);
-               msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n",
-                       msp->mode);
-               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-               msp3400c_setbass(client, msp->bass);
-               msp3400c_settreble(client, msp->treble);
-
-               if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO)
-                       msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));
-               break;
-       }
-
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *vc = arg;
-
-               msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm);
-               msp->norm = vc->norm;
-               msp_wake_thread(client);
-               break;
-       }
-
-       case VIDIOCSFREQ:
-       case VIDIOC_S_FREQUENCY:
-       {
-               /* new channel -- kick audio carrier scan */
-               msp3400_dbg("VIDIOCSFREQ\n");
-               msp_wake_thread(client);
-               break;
-       }
-
-       /* msp34xx specific */
-       case MSP_SET_MATRIX:
-       {
-               struct msp_matrix *mspm = arg;
-
-               msp3400_dbg("MSP_SET_MATRIX\n");
-               msp3400c_set_scart(client, mspm->input, mspm->output);
-               break;
-       }
-
-       /* --- v4l2 ioctls --- */
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-
-               /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
-               if (*id & V4L2_STD_PAL) {
-                       msp->norm=VIDEO_MODE_PAL;
-               } else if (*id & V4L2_STD_SECAM) {
-                       msp->norm=VIDEO_MODE_SECAM;
-               } else {
-                       msp->norm=VIDEO_MODE_NTSC;
-               }
-
-               msp_wake_thread(client);
-               return 0;
-       }
-
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
-
-               if (i->index != 0)
-                       return -EINVAL;
-
-               i->type = V4L2_INPUT_TYPE_TUNER;
-               switch (i->index) {
-               case AUDIO_RADIO:
-                       strcpy(i->name,"Radio");
-                       break;
-               case AUDIO_EXTERN_1:
-                       strcpy(i->name,"Extern 1");
-                       break;
-               case AUDIO_EXTERN_2:
-                       strcpy(i->name,"Extern 2");
-                       break;
-               case AUDIO_TUNER:
-                       strcpy(i->name,"Television");
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               return 0;
-       }
-
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
-
-               memset(a,0,sizeof(*a));
-
-               switch (a->index) {
-               case AUDIO_RADIO:
-                       strcpy(a->name,"Radio");
-                       break;
-               case AUDIO_EXTERN_1:
-                       strcpy(a->name,"Extern 1");
-                       break;
-               case AUDIO_EXTERN_2:
-                       strcpy(a->name,"Extern 2");
-                       break;
-               case AUDIO_TUNER:
-                       strcpy(a->name,"Television");
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               msp_any_detect_stereo(client);
-               if (msp->audmode == V4L2_TUNER_MODE_STEREO) {
-                       a->capability=V4L2_AUDCAP_STEREO;
-               }
-
-               break;
-       }
-       case VIDIOC_S_AUDIO:
-       {
-               struct v4l2_audio *sarg = arg;
-
-               switch (sarg->index) {
-               case AUDIO_RADIO:
-                       /* Hauppauge uses IN2 for the radio */
-                       msp->mode   = MSP_MODE_FM_RADIO;
-                       scart       = SCART_IN2;
-                       break;
-               case AUDIO_EXTERN_1:
-                       /* IN1 is often used for external input ... */
-                       msp->mode   = MSP_MODE_EXTERN;
-                       scart       = SCART_IN1;
-                       break;
-               case AUDIO_EXTERN_2:
-                       /* ... sometimes it is IN2 through ;) */
-                       msp->mode   = MSP_MODE_EXTERN;
-                       scart       = SCART_IN2;
-                       break;
-               case AUDIO_TUNER:
-                       msp->mode   = -1;
-                       break;
-               }
-               if (scart) {
-                       msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       msp->audmode = V4L2_TUNER_MODE_STEREO;
-                       msp3400c_set_scart(client,scart,0);
-                       msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
-               }
-               if (sarg->capability==V4L2_AUDCAP_STEREO) {
-                       msp->audmode = V4L2_TUNER_MODE_STEREO;
-               } else {
-                       msp->audmode &= ~V4L2_TUNER_MODE_STEREO;
-               }
-               msp_any_set_audmode(client, msp->audmode);
-               msp_wake_thread(client);
-               break;
-       }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *vt = arg;
-
-               msp_any_detect_stereo(client);
-               vt->audmode    = msp->audmode;
-               vt->rxsubchans = msp->rxsubchans;
-               vt->capability = V4L2_TUNER_CAP_STEREO |
-                       V4L2_TUNER_CAP_LANG1|
-                       V4L2_TUNER_CAP_LANG2;
-               break;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
-
-               /* only set audmode */
-               if (vt->audmode != -1 && vt->audmode != 0)
-                       msp_any_set_audmode(client, vt->audmode);
-               break;
-       }
-
-       case VIDIOC_G_AUDOUT:
-       {
-               struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
-               int idx=a->index;
-
-               memset(a,0,sizeof(*a));
-
-               switch (idx) {
-               case 0:
-                       strcpy(a->name,"Scart1 Out");
-                       break;
-               case 1:
-                       strcpy(a->name,"Scart2 Out");
-                       break;
-               case 2:
-                       strcpy(a->name,"I2S Out");
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-
-       }
-       case VIDIOC_S_AUDOUT:
-       {
-               struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
-
-               if (a->index<0||a->index>2)
-                       return -EINVAL;
-
-               if (a->index==2) {
-                       if (a->mode == V4L2_AUDMODE_32BITS)
-                               msp->i2s_mode=1;
-                       else
-                               msp->i2s_mode=0;
-               }
-               msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",
-                                               a->index,msp->i2s_mode);
-               msp3400c_set_scart(client,msp->in_scart,a->index+1);
-
-               break;
-       }
-
-       default:
-               /* nothing */
-               break;
-       }
-       return 0;
-}
-
-static int msp_suspend(struct device * dev, pm_message_t state)
-{
-       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-
-       msp3400_dbg("msp34xx: suspend\n");
-       msp3400c_reset(client);
-       return 0;
-}
-
-static int msp_resume(struct device * dev)
-{
-       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-
-       msp3400_dbg("msp34xx: resume\n");
-       msp_wake_thread(client);
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int __init msp3400_init_module(void)
-{
-       return i2c_add_driver(&driver);
-}
-
-static void __exit msp3400_cleanup_module(void)
-{
-       i2c_del_driver(&driver);
-}
-
-module_init(msp3400_init_module);
-module_exit(msp3400_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 2d9ff40f0b09c0f6c8a3de98f60a82fe64c5c91e..8a05cf500a8cf8d882d830fb6cdc0c1556308a1e 100644 (file)
@@ -6,22 +6,28 @@
 
 /* ---------------------------------------------------------------------- */
 
-struct msp_dfpreg {
-    int reg;
-    int value;
-};
-
 struct msp_matrix {
   int input;
   int output;
 };
 
-#define MSP_SET_DFPREG     _IOW('m',15,struct msp_dfpreg)
-#define MSP_GET_DFPREG     _IOW('m',16,struct msp_dfpreg)
-
 /* ioctl for MSP_SET_MATRIX will have to be registered */
 #define MSP_SET_MATRIX     _IOW('m',17,struct msp_matrix)
 
+/* This macro is allowed for *constants* only, gcc must calculate it
+   at compile time.  Remember -- no floats in kernel mode */
+#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))
+
+#define MSP_MODE_AM_DETECT   0
+#define MSP_MODE_FM_RADIO    2
+#define MSP_MODE_FM_TERRA    3
+#define MSP_MODE_FM_SAT      4
+#define MSP_MODE_FM_NICAM1   5
+#define MSP_MODE_FM_NICAM2   6
+#define MSP_MODE_AM_NICAM    7
+#define MSP_MODE_BTSC        8
+#define MSP_MODE_EXTERN      9
+
 #define SCART_MASK    0
 #define SCART_IN1     1
 #define SCART_IN2     2
@@ -36,4 +42,84 @@ struct msp_matrix {
 #define SCART1_OUT    1
 #define SCART2_OUT    2
 
+#define OPMODE_AUTO       -1
+#define OPMODE_MANUAL      0
+#define OPMODE_AUTODETECT  1   /* use autodetect (>= msp3410 only) */
+#define OPMODE_AUTOSELECT  2   /* use autodetect & autoselect (>= msp34xxG)   */
+
+/* module parameters */
+extern int debug;
+extern int once;
+extern int amsound;
+extern int standard;
+extern int dolby;
+extern int stereo_threshold;
+
+struct msp_state {
+       int rev1, rev2;
+       u8 has_nicam;
+       u8 has_radio;
+       u8 has_headphones;
+       u8 has_ntsc_jp_d_k3;
+       u8 has_scart4;
+       u8 has_scart23_in_scart2_out;
+       u8 has_scart2_out_volume;
+       u8 has_i2s_conf;
+       u8 has_subwoofer;
+       u8 has_sound_processing;
+       u8 has_virtual_dolby_surround;
+       u8 has_dolby_pro_logic;
+
+       int radio;
+       int opmode;
+       int std;
+       int mode;
+       v4l2_std_id v4l2_std;
+       int nicam_on;
+       int acb;
+       int in_scart;
+       int i2s_mode;
+       int main, second;       /* sound carrier */
+       int input;
+       int source;             /* see msp34xxg_set_source */
+
+       /* v4l2 */
+       int audmode;
+       int rxsubchans;
+
+       int volume, muted;
+       int balance, loudness;
+       int bass, treble;
+
+       /* thread */
+       struct task_struct   *kthread;
+       wait_queue_head_t    wq;
+       int                  restart:1;
+       int                  watch_stereo:1;
+};
+
+/* msp3400-driver.c */
+int msp_write_dem(struct i2c_client *client, int addr, int val);
+int msp_write_dsp(struct i2c_client *client, int addr, int val);
+int msp_read_dem(struct i2c_client *client, int addr);
+int msp_read_dsp(struct i2c_client *client, int addr);
+int msp_reset(struct i2c_client *client);
+void msp_set_scart(struct i2c_client *client, int in, int out);
+void msp_set_mute(struct i2c_client *client);
+void msp_set_audio(struct i2c_client *client);
+int msp_modus(struct i2c_client *client);
+int msp_sleep(struct msp_state *state, int timeout);
+
+/* msp3400-kthreads.c */
+const char *msp_standard_std_name(int std);
+void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2);
+void msp3400c_setmode(struct i2c_client *client, int type);
+void msp3400c_setstereo(struct i2c_client *client, int mode);
+int autodetect_stereo(struct i2c_client *client);
+int msp3400c_thread(void *data);
+int msp3410d_thread(void *data);
+int msp34xxg_thread(void *data);
+void msp34xxg_detect_stereo(struct i2c_client *client);
+void msp34xxg_set_audmode(struct i2c_client *client, int audmode);
+
 #endif /* MSP3400_H */
index 2180018f06de95af017850d319441650d1f16acb..2c19c9588c0287cb1c407b8fb665299b737e83d3 100644 (file)
@@ -20,6 +20,9 @@ module_param(tv_antenna,        int, 0644);
 static unsigned int radio_antenna = 0;
 module_param(radio_antenna,     int, 0644);
 
+/* from tuner-core.c */
+extern int debug;
+
 /* ---------------------------------------------------------------------- */
 
 #define MT2032 0x04
@@ -401,7 +404,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
        div2a=(lo2/8)-1;
        div2b=lo2-(div2a+1)*8;
 
-       if (tuner_debug > 1) {
+       if (debug > 1) {
                tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
                tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
                          num1,num2,div1a,div1b,div2a,div2b);
@@ -417,7 +420,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
        buf[5]=div2a;
        if(num2!=0) buf[5]=buf[5]|0x40;
 
-       if (tuner_debug > 1) {
+       if (debug > 1) {
                int i;
                tuner_dbg("bufs is: ");
                for(i=0;i<6;i++)
@@ -494,11 +497,18 @@ int microtune_init(struct i2c_client *c)
        t->tv_freq    = NULL;
        t->radio_freq = NULL;
        t->standby    = NULL;
+       if (t->std & V4L2_STD_525_60) {
+               tuner_dbg("pinnacle ntsc\n");
+               t->radio_if2 = 41300 * 1000;
+       } else {
+               tuner_dbg("pinnacle pal\n");
+               t->radio_if2 = 33300 * 1000;
+       }
        name = "unknown";
 
        i2c_master_send(c,buf,1);
        i2c_master_recv(c,buf,21);
-       if (tuner_debug) {
+       if (debug) {
                int i;
                tuner_dbg("MT20xx hexdump:");
                for(i=0;i<21;i++) {
index d04793fb80fcae21cee6ceb903eb753ec7bf1006..91681aa6c6574261102deb36a60fe47fad63e005 100644 (file)
@@ -26,6 +26,7 @@
 #include <media/saa7146_vv.h>
 #include <media/tuner.h>
 #include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
 
 #include "mxb.h"
 #include "tea6415c.h"
index 2504207b2e3da83167668a1f947e965b79308704..9e6448639480c75f22553f4e4a9b924a7b194101 100644 (file)
@@ -883,6 +883,7 @@ static struct file_operations pms_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = pms_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .read           = pms_read,
        .llseek         = no_llseek,
 };
index a51c7bd96618ef767123dfec1b3a923b29fb5520..73b4f0e2abf086d7974e76b6148f2822a8b33ecc 100644 (file)
@@ -702,6 +702,7 @@ static struct file_operations saa_fops = {
        .open           = saa5249_open,
        .release        = saa5249_release,
        .ioctl          = saa5249_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index d60a783e04730b53c67c1a0b6ca5f4a8e2a8dfd3..e70b17ef36e9d0938d7b805f51527c0d8edd6f82 100644 (file)
@@ -427,18 +427,8 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
 
 static int saa6588_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, saa6588_attach);
-#else
-       switch (adap->id) {
-       case I2C_HW_B_BT848:
-       case I2C_HW_B_RIVA:
-       case I2C_HW_SAA7134:
-               return i2c_probe(adap, &addr_data, saa6588_attach);
-               break;
-       }
-#endif
        return 0;
 }
 
@@ -496,7 +486,7 @@ static int saa6588_command(struct i2c_client *client, unsigned int cmd,
 
 static struct i2c_driver driver = {
        .driver = {
-               .name = "i2c saa6588 driver",
+               .name = "saa6588",
        },
        .id = -1,               /* FIXME */
        .attach_adapter = saa6588_probe,
index 29e28c742cd4b3e407c7845cefbf237e8212edde..4a4bc69fb0e97a7e95218a3fb563d51a68e841c6 100644 (file)
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <asm/div64.h>
 
 MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
 static int debug = 0;
-module_param(debug, int, 0644);
+module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define saa7115_dbg(fmt,arg...) \
-       do { \
-               if (debug) \
-                       printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-                              client->driver->driver.name, \
-                              i2c_adapter_id(client->adapter), client->addr , ## arg); \
-       } while (0)
-
-#define saa7115_err(fmt, arg...) do { \
-       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define saa7115_info(fmt, arg...) do { \
-       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
 static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
 
 
@@ -73,12 +60,13 @@ struct saa7115_state {
        v4l2_std_id std;
        int input;
        int enable;
+       int radio;
        int bright;
        int contrast;
        int hue;
        int sat;
        enum v4l2_chip_ident ident;
-       enum v4l2_audio_clock_freq audclk_freq;
+       u32 audclk_freq;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -469,80 +457,6 @@ static const unsigned char saa7115_init_misc[] = {
        0x00, 0x00
 };
 
-/* ============== SAA7715 AUDIO settings ============= */
-
-/* 48.0 kHz */
-static const unsigned char saa7115_cfg_48_audio[] = {
-       0x34, 0xce,
-       0x35, 0xfb,
-       0x36, 0x30,
-       0x00, 0x00
-};
-
-/* 44.1 kHz */
-static const unsigned char saa7115_cfg_441_audio[] = {
-       0x34, 0xf2,
-       0x35, 0x00,
-       0x36, 0x2d,
-       0x00, 0x00
-};
-
-/* 32.0 kHz */
-static const unsigned char saa7115_cfg_32_audio[] = {
-       0x34, 0xdf,
-       0x35, 0xa7,
-       0x36, 0x20,
-       0x00, 0x00
-};
-
-/* 48.0 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_48_audio[] = {
-       0x30, 0xcd,
-       0x31, 0x20,
-       0x32, 0x03,
-       0x00, 0x00
-};
-
-/* 48.0 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_48_audio[] = {
-       0x30, 0x00,
-       0x31, 0xc0,
-       0x32, 0x03,
-       0x00, 0x00
-};
-
-/* 44.1 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_441_audio[] = {
-       0x30, 0xbc,
-       0x31, 0xdf,
-       0x32, 0x02,
-       0x00, 0x00
-};
-
-/* 44.1 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_441_audio[] = {
-       0x30, 0x00,
-       0x31, 0x72,
-       0x32, 0x03,
-       0x00, 0x00
-};
-
-/* 32.0 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_32_audio[] = {
-       0x30, 0xde,
-       0x31, 0x15,
-       0x32, 0x02,
-       0x00, 0x00
-};
-
-/* 32.0 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_32_audio[] = {
-       0x30, 0x00,
-       0x31, 0x80,
-       0x32, 0x02,
-       0x00, 0x00
-};
-
 static int saa7115_odd_parity(u8 c)
 {
        c ^= (c >> 4);
@@ -627,40 +541,38 @@ static int saa7115_decode_wss(u8 * p)
 }
 
 
-static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq)
+static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
 {
        struct saa7115_state *state = i2c_get_clientdata(client);
+       u32 acpf;
+       u32 acni;
+       u32 hz;
+       u64 f;
 
-       saa7115_dbg("set audio clock freq: %d\n", freq);
-       switch (freq) {
-               case V4L2_AUDCLK_32_KHZ:
-                       saa7115_writeregs(client, saa7115_cfg_32_audio);
-                       if (state->std & V4L2_STD_525_60) {
-                               saa7115_writeregs(client, saa7115_cfg_60hz_32_audio);
-                       } else {
-                               saa7115_writeregs(client, saa7115_cfg_50hz_32_audio);
-                       }
-                       break;
-               case V4L2_AUDCLK_441_KHZ:
-                       saa7115_writeregs(client, saa7115_cfg_441_audio);
-                       if (state->std & V4L2_STD_525_60) {
-                               saa7115_writeregs(client, saa7115_cfg_60hz_441_audio);
-                       } else {
-                               saa7115_writeregs(client, saa7115_cfg_50hz_441_audio);
-                       }
-                       break;
-               case V4L2_AUDCLK_48_KHZ:
-                       saa7115_writeregs(client, saa7115_cfg_48_audio);
-                       if (state->std & V4L2_STD_525_60) {
-                               saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
-                       } else {
-                               saa7115_writeregs(client, saa7115_cfg_50hz_48_audio);
-                       }
-                       break;
-               default:
-                       saa7115_dbg("invalid audio setting %d\n", freq);
-                       return -EINVAL;
-       }
+       v4l_dbg(1, client, "set audio clock freq: %d\n", freq);
+
+       /* sanity check */
+       if (freq < 32000 || freq > 48000)
+               return -EINVAL;
+
+       /* hz is the refresh rate times 100 */
+       hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
+       /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
+       acpf = (25600 * freq) / hz;
+       /* acni = (256 * freq * 2^23) / crystal_frequency =
+                 (freq * 2^(8+23)) / crystal_frequency =
+                 (freq << 31) / 32.11 MHz */
+       f = freq;
+       f = f << 31;
+       do_div(f, 32110000);
+       acni = f;
+
+       saa7115_write(client, 0x30, acpf & 0xff);
+       saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
+       saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
+       saa7115_write(client, 0x34, acni & 0xff);
+       saa7115_write(client, 0x35, (acni >> 8) & 0xff);
+       saa7115_write(client, 0x36, (acni >> 16) & 0x3f);
        state->audclk_freq = freq;
        return 0;
 }
@@ -672,7 +584,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                if (ctrl->value < 0 || ctrl->value > 255) {
-                       saa7115_err("invalid brightness setting %d\n", ctrl->value);
+                       v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
@@ -682,7 +594,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
 
        case V4L2_CID_CONTRAST:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       saa7115_err("invalid contrast setting %d\n", ctrl->value);
+                       v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
@@ -692,7 +604,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
 
        case V4L2_CID_SATURATION:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       saa7115_err("invalid saturation setting %d\n", ctrl->value);
+                       v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
@@ -702,13 +614,16 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
 
        case V4L2_CID_HUE:
                if (ctrl->value < -127 || ctrl->value > 127) {
-                       saa7115_err("invalid hue setting %d\n", ctrl->value);
+                       v4l_err(client, "invalid hue setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->hue = ctrl->value;
                saa7115_write(client, 0x0d, state->hue);
                break;
+
+       default:
+               return -EINVAL;
        }
 
        return 0;
@@ -743,12 +658,22 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
        struct saa7115_state *state = i2c_get_clientdata(client);
        int taskb = saa7115_read(client, 0x80) & 0x10;
 
+       /* Prevent unnecessary standard changes. During a standard
+          change the I-Port is temporarily disabled. Any devices
+          reading from that port can get confused.
+          Note that VIDIOC_S_STD is also used to switch from
+          radio to TV mode, so if a VIDIOC_S_STD is broadcast to
+          all I2C devices then you do not want to have an unwanted
+          side-effect here. */
+       if (std == state->std)
+               return;
+
        // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
        if (std & V4L2_STD_525_60) {
-               saa7115_dbg("decoder set standard 60 Hz\n");
+               v4l_dbg(1, client, "decoder set standard 60 Hz\n");
                saa7115_writeregs(client, saa7115_cfg_60hz_video);
        } else {
-               saa7115_dbg("decoder set standard 50 Hz\n");
+               v4l_dbg(1, client, "decoder set standard 50 Hz\n");
                saa7115_writeregs(client, saa7115_cfg_50hz_video);
        }
 
@@ -773,24 +698,17 @@ static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
 static void saa7115_log_status(struct i2c_client *client)
 {
        struct saa7115_state *state = i2c_get_clientdata(client);
-       char *audfreq = "undefined";
        int reg1e, reg1f;
        int signalOk;
        int vcr;
 
-       switch (state->audclk_freq) {
-               case V4L2_AUDCLK_32_KHZ:  audfreq = "32 kHz"; break;
-               case V4L2_AUDCLK_441_KHZ: audfreq = "44.1 kHz"; break;
-               case V4L2_AUDCLK_48_KHZ:  audfreq = "48 kHz"; break;
-       }
-
-       saa7115_info("Audio frequency: %s\n", audfreq);
+       v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
        if (client->name[6] == '4') {
                /* status for the saa7114 */
                reg1f = saa7115_read(client, 0x1f);
                signalOk = (reg1f & 0xc1) == 0x81;
-               saa7115_info("Video signal:    %s\n", signalOk ? "ok" : "bad");
-               saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+               v4l_info(client, "Video signal:    %s\n", signalOk ? "ok" : "bad");
+               v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
                return;
        }
 
@@ -801,21 +719,26 @@ static void saa7115_log_status(struct i2c_client *client)
        signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
        vcr = !(reg1f & 0x10);
 
-       saa7115_info("Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
-       saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+       if (state->input >= 6) {
+               v4l_info(client, "Input:           S-Video %d\n", state->input - 6);
+       } else {
+               v4l_info(client, "Input:           Composite %d\n", state->input);
+       }
+       v4l_info(client, "Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+       v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
 
        switch (reg1e & 0x03) {
                case 1:
-                       saa7115_info("Detected format: NTSC\n");
+                       v4l_info(client, "Detected format: NTSC\n");
                        break;
                case 2:
-                       saa7115_info("Detected format: PAL\n");
+                       v4l_info(client, "Detected format: PAL\n");
                        break;
                case 3:
-                       saa7115_info("Detected format: SECAM\n");
+                       v4l_info(client, "Detected format: SECAM\n");
                        break;
                default:
-                       saa7115_info("Detected format: BW/No color\n");
+                       v4l_info(client, "Detected format: BW/No color\n");
                        break;
        }
 }
@@ -940,7 +863,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
 
        pix = &(fmt->fmt.pix);
 
-       saa7115_dbg("decoder set size\n");
+       v4l_dbg(1, client, "decoder set size\n");
 
        /* FIXME need better bounds checking here */
        if ((pix->width < 1) || (pix->width > 1440))
@@ -966,7 +889,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
                HPSC = HPSC ? HPSC : 1;
                HFSC = (int)((1024 * 720) / (HPSC * pix->width));
 
-               saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+               v4l_dbg(1, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
                /* FIXME hardcodes to "Task B"
                 * write H prescaler integer */
                saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
@@ -980,10 +903,10 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
                saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
        } else {
                if (is_50hz) {
-                       saa7115_dbg("Setting full 50hz width\n");
+                       v4l_dbg(1, client, "Setting full 50hz width\n");
                        saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
                } else {
-                       saa7115_dbg("Setting full 60hz width\n");
+                       v4l_dbg(1, client, "Setting full 60hz width\n");
                        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
                }
        }
@@ -992,7 +915,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
 
        if (pix->height != Vsrc) {
                VSCY = (int)((1024 * Vsrc) / pix->height);
-               saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+               v4l_dbg(1, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
 
                /* Correct Contrast and Luminance */
                saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
@@ -1006,10 +929,10 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
                saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
        } else {
                if (is_50hz) {
-                       saa7115_dbg("Setting full 50Hz height\n");
+                       v4l_dbg(1, client, "Setting full 50Hz height\n");
                        saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
                } else {
-                       saa7115_dbg("Setting full 60hz height\n");
+                       v4l_dbg(1, client, "Setting full 60hz height\n");
                        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
                }
        }
@@ -1089,6 +1012,48 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
 
 /* ============ SAA7115 AUDIO settings (end) ============= */
 
+static struct v4l2_queryctrl saa7115_qctrl[] = {
+       {
+               .id            = V4L2_CID_BRIGHTNESS,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Brightness",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 128,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_CONTRAST,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Contrast",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 64,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_SATURATION,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Saturation",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 64,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_HUE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Hue",
+               .minimum       = -128,
+               .maximum       = 127,
+               .step          = 1,
+               .default_value = 0,
+               .flags         = 0,
+       },
+};
+
+/* ----------------------------------------------------------------------- */
+
 static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct saa7115_state *state = i2c_get_clientdata(client);
@@ -1103,16 +1068,18 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
                return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
 
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+               return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
 
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *vt = arg;
                int status;
 
+               if (state->radio)
+                       break;
                status = saa7115_read(client, 0x1f);
 
-               saa7115_dbg("status: 0x%02x\n", status);
+               v4l_dbg(1, client, "status: 0x%02x\n", status);
                vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
                break;
        }
@@ -1127,20 +1094,38 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
        case VIDIOC_S_CTRL:
                return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
 
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *qc = arg;
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
+                       if (qc->id && qc->id == saa7115_qctrl[i].id) {
+                               memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
+                               return 0;
+                       }
+               return -EINVAL;
+       }
+
        case VIDIOC_G_STD:
                *(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
                break;
 
        case VIDIOC_S_STD:
+               state->radio = 0;
                saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
                break;
 
+       case AUDC_SET_RADIO:
+               state->radio = 1;
+               break;
+
        case VIDIOC_G_INPUT:
                *(int *)arg = state->input;
                break;
 
        case VIDIOC_S_INPUT:
-               saa7115_dbg("decoder set input %d\n", *iarg);
+               v4l_dbg(1, client, "decoder set input %d\n", *iarg);
                /* inputs from 0-9 are available */
                if (*iarg < 0 || *iarg > 9) {
                        return -EINVAL;
@@ -1148,7 +1133,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
 
                if (state->input == *iarg)
                        break;
-               saa7115_dbg("now setting %s input\n",
+               v4l_dbg(1, client, "now setting %s input\n",
                        *iarg >= 6 ? "S-Video" : "Composite");
                state->input = *iarg;
 
@@ -1165,7 +1150,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
 
        case VIDIOC_STREAMON:
        case VIDIOC_STREAMOFF:
-               saa7115_dbg("%s output\n",
+               v4l_dbg(1, client, "%s output\n",
                        (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
 
                if (state->enable != (cmd == VIDIOC_STREAMON)) {
@@ -1179,7 +1164,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
                break;
 
        case VIDIOC_INT_RESET:
-               saa7115_dbg("decoder RESET\n");
+               v4l_dbg(1, client, "decoder RESET\n");
                saa7115_writeregs(client, saa7115_cfg_reset_scaler);
                break;
 
@@ -1273,19 +1258,19 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
        client->driver = &i2c_driver_saa7115;
        snprintf(client->name, sizeof(client->name) - 1, "saa7115");
 
-       saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1);
+       v4l_dbg(1, client, "detecting saa7115 client on address 0x%x\n", address << 1);
 
        saa7115_write(client, 0, 5);
        chip_id = saa7115_read(client, 0) & 0x0f;
        if (chip_id != 4 && chip_id != 5) {
-               saa7115_dbg("saa7115 not found\n");
+               v4l_dbg(1, client, "saa7115 not found\n");
                kfree(client);
                return 0;
        }
        if (chip_id == 4) {
                snprintf(client->name, sizeof(client->name) - 1, "saa7114");
        }
-       saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
+       v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
 
        state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL);
        i2c_set_clientdata(client, state);
@@ -1297,14 +1282,15 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
        state->std = V4L2_STD_NTSC;
        state->input = -1;
        state->enable = 1;
+       state->radio = 0;
        state->bright = 128;
        state->contrast = 64;
        state->hue = 0;
        state->sat = 64;
        state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
-       state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+       state->audclk_freq = 48000;
 
-       saa7115_dbg("writing init values\n");
+       v4l_dbg(1, client, "writing init values\n");
 
        /* init to 60hz/48khz */
        saa7115_writeregs(client, saa7115_init_auto_input);
@@ -1312,13 +1298,12 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
        saa7115_writeregs(client, saa7115_cfg_60hz_video);
-       saa7115_writeregs(client, saa7115_cfg_48_audio);
-       saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+       saa7115_set_audio_clock_freq(client, state->audclk_freq);
        saa7115_writeregs(client, saa7115_cfg_reset_scaler);
 
        i2c_attach_client(client);
 
-       saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n",
+       v4l_dbg(1, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
                saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
 
        return 0;
@@ -1326,11 +1311,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
 
 static int saa7115_probe(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-       if (adapter->id == I2C_HW_B_BT848)
-#endif
                return i2c_probe(adapter, &addr_data, &saa7115_attach);
        return 0;
 }
index 8008537391b5425ed3ce71c92cf3267cc6a2b580..f39a7be08588010fe5c29393793f2e576c5cbf1c 100644 (file)
@@ -567,9 +567,7 @@ static struct i2c_driver i2c_driver_saa711x = {
        .driver = {
                .name = "saa711x",
        },
-
        .id = I2C_DRIVERID_SAA711X,
-
        .attach_adapter = saa711x_attach_adapter,
        .detach_client = saa711x_detach_client,
        .command = saa711x_command,
index bca6ed0e27525e5b5d06068add0f2183a36a89eb..2009c1bc47207c1b1f4e8d8eb75d5e6027399e22 100644 (file)
@@ -66,30 +66,6 @@ module_param(test_image, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (0-2)");
 MODULE_PARM_DESC(test_image, "test_image (0-1)");
 
-#define saa7127_dbg(fmt, arg...) \
-       do { \
-               if (debug >= 1) \
-                       printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-                              client->driver->driver.name, \
-                              i2c_adapter_id(client->adapter), client->addr , ## arg); \
-       } while (0)
-
-/* High volume debug. Use with care. */
-#define saa7127_dbg_highvol(fmt, arg...) \
-       do { \
-               if (debug == 2) \
-                       printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-                              client->driver->driver.name, \
-                              i2c_adapter_id(client->adapter), client->addr , ## arg); \
-       } while (0)
-
-#define saa7127_err(fmt, arg...) do { \
-       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define saa7127_info(fmt, arg...) do { \
-       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
 static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
 
@@ -336,7 +312,7 @@ static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
                if (i2c_smbus_write_byte_data(client, reg, val) == 0)
                        return 0;
        }
-       saa7127_err("I2C Write Problem\n");
+       v4l_err(client, "I2C Write Problem\n");
        return -1;
 }
 
@@ -362,7 +338,7 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
        if (enable && (data->field != 0 || data->line != 16))
                return -EINVAL;
        if (state->vps_enable != enable) {
-               saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off");
+               v4l_dbg(1, client, "Turn VPS Signal %s\n", enable ? "on" : "off");
                saa7127_write(client, 0x54, enable << 7);
                state->vps_enable = enable;
        }
@@ -374,7 +350,7 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
        state->vps_data[2] = data->data[11];
        state->vps_data[3] = data->data[12];
        state->vps_data[4] = data->data[13];
-       saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n",
+       v4l_dbg(1, client, "Set VPS data %02x %02x %02x %02x %02x\n",
                state->vps_data[0], state->vps_data[1],
                state->vps_data[2], state->vps_data[3],
                state->vps_data[4]);
@@ -397,7 +373,7 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
        if (enable && (data->field != 0 || data->line != 21))
                return -EINVAL;
        if (state->cc_enable != enable) {
-               saa7127_dbg("Turn CC %s\n", enable ? "on" : "off");
+               v4l_dbg(1, client, "Turn CC %s\n", enable ? "on" : "off");
                saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
                                (state->xds_enable << 7) | (enable << 6) | 0x11);
                state->cc_enable = enable;
@@ -405,7 +381,7 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
        if (!enable)
                return 0;
 
-       saa7127_dbg_highvol("CC data: %04x\n", cc);
+       v4l_dbg(2, client, "CC data: %04x\n", cc);
        saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
        saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
        state->cc_data = cc;
@@ -423,7 +399,7 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat
        if (enable && (data->field != 1 || data->line != 21))
                return -EINVAL;
        if (state->xds_enable != enable) {
-               saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off");
+               v4l_dbg(1, client, "Turn XDS %s\n", enable ? "on" : "off");
                saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
                                (enable << 7) | (state->cc_enable << 6) | 0x11);
                state->xds_enable = enable;
@@ -431,7 +407,7 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat
        if (!enable)
                return 0;
 
-       saa7127_dbg_highvol("XDS data: %04x\n", xds);
+       v4l_dbg(2, client, "XDS data: %04x\n", xds);
        saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
        saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
        state->xds_data = xds;
@@ -448,7 +424,7 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
        if (enable && (data->field != 0 || data->line != 23))
                return -EINVAL;
        if (state->wss_enable != enable) {
-               saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off");
+               v4l_dbg(1, client, "Turn WSS %s\n", enable ? "on" : "off");
                saa7127_write(client, 0x27, enable << 7);
                state->wss_enable = enable;
        }
@@ -457,7 +433,7 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 
        saa7127_write(client, 0x26, data->data[0]);
        saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
-       saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+       v4l_dbg(1, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
        state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
        return 0;
 }
@@ -469,11 +445,11 @@ static int saa7127_set_video_enable(struct i2c_client *client, int enable)
        struct saa7127_state *state = i2c_get_clientdata(client);
 
        if (enable) {
-               saa7127_dbg("Enable Video Output\n");
+               v4l_dbg(1, client, "Enable Video Output\n");
                saa7127_write(client, 0x2d, state->reg_2d);
                saa7127_write(client, 0x61, state->reg_61);
        } else {
-               saa7127_dbg("Disable Video Output\n");
+               v4l_dbg(1, client, "Disable Video Output\n");
                saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
                saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
        }
@@ -489,11 +465,11 @@ static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
        const struct i2c_reg_value *inittab;
 
        if (std & V4L2_STD_525_60) {
-               saa7127_dbg("Selecting 60 Hz video Standard\n");
+               v4l_dbg(1, client, "Selecting 60 Hz video Standard\n");
                inittab = saa7127_init_config_60hz;
                state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
        } else {
-               saa7127_dbg("Selecting 50 Hz video Standard\n");
+               v4l_dbg(1, client, "Selecting 50 Hz video Standard\n");
                inittab = saa7127_init_config_50hz;
                state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
        }
@@ -544,7 +520,7 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
        default:
                return -EINVAL;
        }
-       saa7127_dbg("Selecting %s output type\n", output_strs[output]);
+       v4l_dbg(1, client, "Selecting %s output type\n", output_strs[output]);
 
        /* Configure Encoder */
        saa7127_write(client, 0x2d, state->reg_2d);
@@ -561,12 +537,12 @@ static int saa7127_set_input_type(struct i2c_client *client, int input)
 
        switch (input) {
        case SAA7127_INPUT_TYPE_NORMAL: /* avia */
-               saa7127_dbg("Selecting Normal Encoder Input\n");
+               v4l_dbg(1, client, "Selecting Normal Encoder Input\n");
                state->reg_3a_cb = 0;
                break;
 
        case SAA7127_INPUT_TYPE_TEST_IMAGE:     /* color bar */
-               saa7127_dbg("Selecting Color Bar generator\n");
+               v4l_dbg(1, client, "Selecting Color Bar generator\n");
                state->reg_3a_cb = 0x80;
                break;
 
@@ -633,14 +609,14 @@ static int saa7127_command(struct i2c_client *client,
                break;
 
        case VIDIOC_LOG_STATUS:
-               saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
-               saa7127_info("Input:    %s\n", state->input_type ?  "color bars" : "normal");
-               saa7127_info("Output:   %s\n", state->video_enable ?
+               v4l_info(client, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+               v4l_info(client, "Input:    %s\n", state->input_type ?  "color bars" : "normal");
+               v4l_info(client, "Output:   %s\n", state->video_enable ?
                        output_strs[state->output_type] : "disabled");
-               saa7127_info("WSS:      %s\n", state->wss_enable ?
+               v4l_info(client, "WSS:      %s\n", state->wss_enable ?
                        wss_strs[state->wss_mode] : "disabled");
-               saa7127_info("VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
-               saa7127_info("CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
+               v4l_info(client, "VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
+               v4l_info(client, "CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
                break;
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -723,7 +699,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
        client->driver = &i2c_driver_saa7127;
        snprintf(client->name, sizeof(client->name) - 1, "saa7127");
 
-       saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1);
+       v4l_dbg(1, client, "detecting saa7127 client on address 0x%x\n", address << 1);
 
        /* First test register 0: Bits 5-7 are a version ID (should be 0),
           and bit 2 should also be 0.
@@ -732,7 +708,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
           0x1d after a reset and not expected to ever change. */
        if ((saa7127_read(client, 0) & 0xe4) != 0 ||
                        (saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
-               saa7127_dbg("saa7127 not found\n");
+               v4l_dbg(1, client, "saa7127 not found\n");
                kfree(client);
                return 0;
        }
@@ -748,7 +724,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
 
        /* Configure Encoder */
 
-       saa7127_dbg("Configuring encoder\n");
+       v4l_dbg(1, client, "Configuring encoder\n");
        saa7127_write_inittab(client, saa7127_init_config_common);
        saa7127_set_std(client, V4L2_STD_NTSC);
        saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
@@ -769,12 +745,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
        read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
        saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
        if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
-               saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
+               v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
                saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
                saa7127_write_inittab(client, saa7129_init_config_extra);
                state->ident = V4L2_IDENT_SAA7129;
        } else {
-               saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
+               v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
                state->ident = V4L2_IDENT_SAA7127;
        }
 
@@ -787,11 +763,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
 
 static int saa7127_probe(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-       if (adapter->id == I2C_HW_B_BT848)
-#endif
                return i2c_probe(adapter, &addr_data, saa7127_attach);
        return 0;
 }
index 4615a982ac64c8470544611f8854ddd50b39c405..ad73c4a60f2b2078f788d2d45aed9502bd065441 100644 (file)
@@ -9,7 +9,8 @@
 #include <linux/poll.h>
 #include <linux/i2c.h>
 #include <linux/types.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
 
@@ -509,7 +510,6 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        struct saa6752hs_state *h;
 
-       printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
 
        if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
                return -ENOMEM;
@@ -525,6 +525,8 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
        i2c_set_clientdata(&h->client, h);
        i2c_attach_client(&h->client);
 
+       v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
+
        return 0;
 }
 
@@ -598,7 +600,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static struct i2c_driver driver = {
        .driver = {
-               .name   = "i2c saa6752hs MPEG encoder",
+               .name   = "saa6752hs",
        },
        .id             = I2C_DRIVERID_SAA6752HS,
        .attach_adapter = saa6752hs_probe,
index ade05f75fdb05d2c23165c42091913ca56f67859..a7a6ab9298a91062f67c2c1a089cd2ee87c35e57 100644 (file)
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
 #include <linux/module.h>
+#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
index 672fb205959f8b21be1f6dc45c4635b8e6907d9e..77e5be98e4c67887d3b33c4fcf2d33e0d28a0d68 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -2555,6 +2556,69 @@ struct saa7134_board saa7134_boards[] = {
                        .amux   = LINE1,
                },
        },
+       [SAA7134_BOARD_CINERGY250PCI] = {
+               /* remote-control does not work. The signal about a
+                  key press comes in via gpio, but the key code
+                  doesn't. Neither does it have an i2c remote control
+                  interface. */
+               .name           = "Terratec Cinergy 250 PCI TV",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x80200000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_svideo,  /* NOT tested */
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+               .radio = {
+                       .name   = name_radio,
+                       .amux   = LINE1,
+                       .gpio   = 0x0200000,
+               },
+       },
+       [SAA7134_BOARD_FLYDVB_TRIO] = {
+               /* LifeView LR319 FlyDVB Trio */
+               /* Peter Missel <peter.missel@onlinehome.de> */
+               .name           = "LifeView FlyDVB Trio",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x00200000,
+               .inputs         = {{
+                       .name = name_tv,        /* Analog broadcast/cable TV */
+                       .vmux = 1,
+                       .amux = TV,
+                       .gpio = 0x200000,       /* GPIO21=High for TV input */
+                       .tv   = 1,
+               },{
+                       .name = name_svideo,    /* S-Video signal on S-Video input */
+                       .vmux = 8,
+                       .amux = LINE2,
+               },{
+                       .name = name_comp1,     /* Composite signal on S-Video input */
+                       .vmux = 0,
+                       .amux = LINE2,
+               },{
+                       .name = name_comp2,     /* Composite input */
+                       .vmux = 3,
+                       .amux = LINE2,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = TV,
+                       .gpio = 0x000000,       /* GPIO21=Low for FM radio antenna */
+               },
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2891,6 +2955,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1421,
                .subdevice    = 0x0350,         /* PCI version */
                .driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1421,
+               .subdevice    = 0x0351,         /* PCI version, new revision */
+               .driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -3001,6 +3071,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1462,
                .subdevice    = 0x6231,
                .driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x153b,
+               .subdevice    = 0x1160,
+               .driver_data  = SAA7134_BOARD_CINERGY250PCI,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,  /* SAA 7131E */
+               .subvendor    = 0x5168,
+               .subdevice    = 0x0319,
+               .driver_data  = SAA7134_BOARD_FLYDVB_TRIO,
        },{
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -3090,6 +3172,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
 /*      case SAA7134_BOARD_SABRENT_SBTTVFM:  */ /* not finished yet */
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+       case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
        case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
index 23d8747338edee3e11dfb0d8d37ea04645f21cb9..accbc32725cf9d9fdd190c0ff5590e83d8d97291 100644 (file)
@@ -95,77 +95,6 @@ int (*dmasound_exit)(struct saa7134_dev *dev);
 #define dprintk(fmt, arg...)   if (core_debug) \
        printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
 
-/* ------------------------------------------------------------------ */
-/* debug help functions                                               */
-
-static const char *v4l1_ioctls[] = {
-       "0", "GCAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
-       "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
-       "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
-       "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
-       "SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
-       "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
-       "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
-       "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
-       "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
-       "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
-       "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
-       "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
-       "44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
-       "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
-       "S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-static const char *osspcm_ioctls[] = {
-       "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
-       "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
-       "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
-       "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
-       "SETDUPLEX", "GETODELAY"
-};
-#define OSSPCM_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void saa7134_print_ioctl(char *name, unsigned int cmd)
-{
-       char *dir;
-
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:              dir = "--"; break;
-       case _IOC_READ:              dir = "r-"; break;
-       case _IOC_WRITE:             dir = "-w"; break;
-       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-       default:                     dir = "??"; break;
-       }
-       switch (_IOC_TYPE(cmd)) {
-       case 'v':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
-                      name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-                      v4l1_ioctls[_IOC_NR(cmd)] : "???");
-               break;
-       case 'V':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
-                      name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
-                      v4l2_ioctls[_IOC_NR(cmd)] : "???");
-               break;
-       case 'P':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
-                      name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
-                      osspcm_ioctls[_IOC_NR(cmd)] : "???");
-               break;
-       case 'M':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
-                      name, cmd, dir, _IOC_NR(cmd));
-               break;
-       default:
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
-                      name, cmd, dir, _IOC_NR(cmd));
-       }
-}
-
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
 {
        unsigned long mode,status;
@@ -211,7 +140,7 @@ static int pending_call(struct notifier_block *self, unsigned long state,
        return NOTIFY_DONE;
 }
 
-static int pending_registered;
+static int pending_registered=0;
 static struct notifier_block pending_notifier = {
        .notifier_call = pending_call,
 };
@@ -610,11 +539,38 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
                    card_has_mpeg(dev))
                        saa7134_irq_ts_done(dev,status);
 
-               if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
-                              SAA7134_IRQ_REPORT_GPIO18)) &&
-                   dev->remote)
-                       saa7134_input_irq(dev);
+               if (report & SAA7134_IRQ_REPORT_GPIO16) {
+                       switch (dev->has_remote) {
+                               case SAA7134_REMOTE_GPIO:
+                                       if  (dev->remote->mask_keydown & 0x10000) {
+                                               saa7134_input_irq(dev);
+                                       }
+                                       break;
+
+                               case SAA7134_REMOTE_I2C:
+                                       break;                  /* FIXME: invoke I2C get_key() */
 
+                               default:                        /* GPIO16 not used by IR remote */
+                                       break;
+                       }
+               }
+
+               if (report & SAA7134_IRQ_REPORT_GPIO18) {
+                       switch (dev->has_remote) {
+                               case SAA7134_REMOTE_GPIO:
+                                       if ((dev->remote->mask_keydown & 0x40000) ||
+                                           (dev->remote->mask_keyup & 0x40000)) {
+                                               saa7134_input_irq(dev);
+                                       }
+                                       break;
+
+                               case SAA7134_REMOTE_I2C:
+                                       break;                  /* FIXME: invoke I2C get_key() */
+
+                               default:                        /* GPIO18 not used by IR remote */
+                                       break;
+                       }
+               }
        }
 
        if (10 == loop) {
@@ -624,13 +580,16 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
                        printk(KERN_WARNING "%s/irq: looping -- "
                               "clearing PE (parity error!) enable bit\n",dev->name);
                        saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE);
-               } else if (report & (SAA7134_IRQ_REPORT_GPIO16 |
-                                    SAA7134_IRQ_REPORT_GPIO18)) {
-                       /* disable gpio IRQs */
+               } else if (report & SAA7134_IRQ_REPORT_GPIO16) {
+                       /* disable gpio16 IRQ */
                        printk(KERN_WARNING "%s/irq: looping -- "
-                              "clearing GPIO enable bits\n",dev->name);
-                       saa_clearl(SAA7134_IRQ2, (SAA7134_IRQ2_INTE_GPIO16 |
-                                                 SAA7134_IRQ2_INTE_GPIO18));
+                              "clearing GPIO16 enable bit\n",dev->name);
+                       saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16);
+               } else if (report & SAA7134_IRQ_REPORT_GPIO18) {
+                       /* disable gpio18 IRQs */
+                       printk(KERN_WARNING "%s/irq: looping -- "
+                              "clearing GPIO18 enable bit\n",dev->name);
+                       saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
                } else {
                        /* disable all irqs */
                        printk(KERN_WARNING "%s/irq: looping -- "
@@ -711,10 +670,14 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
                SAA7134_IRQ2_INTE_PE      |
                SAA7134_IRQ2_INTE_AR;
 
-       if (dev->has_remote == SAA7134_REMOTE_GPIO)
-               irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18  |
-                             SAA7134_IRQ2_INTE_GPIO18A |
-                             SAA7134_IRQ2_INTE_GPIO16  );
+       if (dev->has_remote == SAA7134_REMOTE_GPIO) {
+               if (dev->remote->mask_keydown & 0x10000)
+                       irq2_mask |= SAA7134_IRQ2_INTE_GPIO16;
+               else if (dev->remote->mask_keydown & 0x40000)
+                       irq2_mask |= SAA7134_IRQ2_INTE_GPIO18;
+               else if (dev->remote->mask_keyup & 0x40000)
+                       irq2_mask |= SAA7134_IRQ2_INTE_GPIO18A;
+       }
 
        saa_writel(SAA7134_IRQ1, 0);
        saa_writel(SAA7134_IRQ2, irq2_mask);
@@ -1156,7 +1119,7 @@ static int saa7134_init(void)
        printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n",
               SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-       return pci_module_init(&saa7134_pci_driver);
+       return pci_register_driver(&saa7134_pci_driver);
 }
 
 static void saa7134_fini(void)
@@ -1173,7 +1136,6 @@ module_exit(saa7134_fini);
 
 /* ----------------------------------------------------------- */
 
-EXPORT_SYMBOL(saa7134_print_ioctl);
 EXPORT_SYMBOL(saa7134_i2c_call_clients);
 EXPORT_SYMBOL(saa7134_devlist);
 EXPORT_SYMBOL(saa7134_boards);
index e016480c3468139c9f85b1650c29e6b300a1053e..399f9952596c30a64c46abd1162bcd7108a7e6ee 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
 
 #ifdef HAVE_MT352
 # include "mt352.h"
index 575f3e835f91e102aaba4a9719191f4c6cbd1ca8..bd4c389d4c37a6d190f61130ce8d686c630b8b73 100644 (file)
@@ -29,6 +29,7 @@
 #include "saa7134.h"
 
 #include <media/saa6752hs.h>
+#include <media/v4l2-common.h>
 
 /* ------------------------------------------------------------------ */
 
@@ -163,7 +164,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
        struct saa7134_dev *dev = file->private_data;
 
        if (debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
+               v4l_print_ioctl(dev->name,cmd);
        switch (cmd) {
        case VIDIOC_QUERYCAP:
        {
index 1792d03d621d44596b0b75b7a5c149a6f0250b4c..6162550c413604c97069ae751ad5dbd415f0db14 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
 
 /* ----------------------------------------------------------- */
 
@@ -390,9 +391,7 @@ static struct i2c_algorithm saa7134_algo = {
 
 static struct i2c_adapter saa7134_adap_template = {
        .owner         = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
        .class         = I2C_CLASS_TV_ANALOG,
-#endif
        .name          = "saa7134",
        .id            = I2C_HW_SAA7134,
        .algo          = &saa7134_algo,
index ab75ca5ac356b16862b0957f9a85d56dd5f650b4..82d28cbf289f1a1fe1bb5e22168ee32d8de2e001 100644 (file)
@@ -56,23 +56,23 @@ static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
        [   12 ] = KEY_KP8,
        [   13 ] = KEY_KP9,
 
-       [   14 ] = KEY_TUNER,        // Air/Cable
+       [   14 ] = KEY_MODE,         // Air/Cable
        [   17 ] = KEY_VIDEO,        // Video
        [   21 ] = KEY_AUDIO,        // Audio
-       [    0 ] = KEY_POWER,        // Pover
+       [    0 ] = KEY_POWER,        // Power
+       [   24 ] = KEY_TUNER,        // AV Source
        [    2 ] = KEY_ZOOM,         // Fullscreen
+       [   26 ] = KEY_LANGUAGE,     // Stereo
        [   27 ] = KEY_MUTE,         // Mute
-       [   20 ] = KEY_VOLUMEUP,
-       [   23 ] = KEY_VOLUMEDOWN,
+       [   20 ] = KEY_VOLUMEUP,     // Volume +
+       [   23 ] = KEY_VOLUMEDOWN,   // Volume -
        [   18 ] = KEY_CHANNELUP,    // Channel +
        [   19 ] = KEY_CHANNELDOWN,  // Channel -
-       [    6 ] = KEY_AGAIN,        // Recal
-       [   16 ] = KEY_KPENTER,      // Enter
-
-       [   26 ] = KEY_F22,          // Stereo
-       [   24 ] = KEY_EDIT,         // AV Source
+       [    6 ] = KEY_AGAIN,        // Recall
+       [   16 ] = KEY_ENTER,      // Enter
 };
 
+
 static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
        [    0 ] = KEY_KP0,
        [    1 ] = KEY_KP1,
@@ -543,12 +543,22 @@ static int build_key(struct saa7134_dev *dev)
        dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
                gpio, ir->mask_keycode, data);
 
-       if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
-           (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
-               ir_input_keydown(ir->dev, &ir->ir, data, data);
-       } else {
-               ir_input_nokey(ir->dev, &ir->ir);
+       if (ir->polling) {
+               if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+                   (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+                       ir_input_keydown(ir->dev, &ir->ir, data, data);
+               } else {
+                       ir_input_nokey(ir->dev, &ir->ir);
+               }
+       }
+       else {  /* IRQ driven mode - handle key press and release in one go */
+               if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+                   (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+                       ir_input_keydown(ir->dev, &ir->ir, data, data);
+                       ir_input_nokey(ir->dev, &ir->ir);
+               }
        }
+
        return 0;
 }
 
@@ -686,6 +696,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+       case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
        case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
                ir_codes     = videomate_tv_pvr_codes;
                mask_keycode = 0x00003F;
index 8badd2a9cb2ff08d1e5fe07661999c245e6708eb..7448e386a804cf0f6b50f202859d2fb9bcadb65b 100644 (file)
@@ -373,6 +373,42 @@ static ssize_t dsp_write(struct file *file, const char __user *buffer,
        return -EINVAL;
 }
 
+static const char *osspcm_ioctls[] = {
+       "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
+       "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
+       "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
+       "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
+       "SETDUPLEX", "GETODELAY"
+};
+#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls)
+
+static void saa7134_oss_print_ioctl(char *name, unsigned int cmd)
+{
+       char *dir;
+
+       switch (_IOC_DIR(cmd)) {
+       case _IOC_NONE:              dir = "--"; break;
+       case _IOC_READ:              dir = "r-"; break;
+       case _IOC_WRITE:             dir = "-w"; break;
+       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+       default:                     dir = "??"; break;
+       }
+       switch (_IOC_TYPE(cmd)) {
+       case 'P':
+               printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
+                      name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
+                      osspcm_ioctls[_IOC_NR(cmd)] : "???");
+               break;
+       case 'M':
+               printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
+                      name, cmd, dir, _IOC_NR(cmd));
+               break;
+       default:
+               printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+                      name, cmd, dir, _IOC_NR(cmd));
+       }
+}
+
 static int dsp_ioctl(struct inode *inode, struct file *file,
                     unsigned int cmd, unsigned long arg)
 {
@@ -382,7 +418,7 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
        int val = 0;
 
        if (debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
+               saa7134_oss_print_ioctl(dev->name,cmd);
        switch (cmd) {
        case OSS_GETVERSION:
                return put_user(SOUND_VERSION, p);
@@ -678,7 +714,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
        int __user *p = argp;
 
        if (debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
+               saa7134_oss_print_ioctl(dev->name,cmd);
        switch (cmd) {
        case OSS_GETVERSION:
                return put_user(SOUND_VERSION, p);
index 45c852df13ed56c24c2f0332314144a1ef05d3ff..adfa8fe49a11547c468e5a418f88e841d106deb4 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
 
 /* Include V4L1 specific functions. Should be removed soon */
 #include <linux/videodev.h>
@@ -1689,7 +1690,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
        int err;
 
        if (video_debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
+               v4l_print_ioctl(dev->name,cmd);
 
        switch (cmd) {
        case VIDIOC_S_CTRL:
@@ -2142,7 +2143,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
        struct saa7134_dev *dev = fh->dev;
 
        if (video_debug > 1)
-               saa7134_print_ioctl(dev->name,cmd);
+               v4l_print_ioctl(dev->name,cmd);
        switch (cmd) {
        case VIDIOC_QUERYCAP:
        {
@@ -2262,6 +2263,7 @@ static struct file_operations video_fops =
        .poll     = video_poll,
        .mmap     = video_mmap,
        .ioctl    = video_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek   = no_llseek,
 };
 
@@ -2271,6 +2273,7 @@ static struct file_operations radio_fops =
        .open     = video_open,
        .release  = video_release,
        .ioctl    = radio_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek   = no_llseek,
 };
 
index add49db1ad41130d9d39408cdcd8975ff0f9c869..e70eae8d29bbed0bf4cb5ff7b6afb57dacb15079 100644 (file)
@@ -37,6 +37,9 @@
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/video-buf.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
 #include <media/video-buf-dvb.h>
 
 #ifndef TRUE
 #endif
 #define UNSET (-1U)
 
-#include <sound/driver.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-
 /* ----------------------------------------------------------- */
 /* enums                                                       */
 
@@ -209,6 +208,8 @@ struct saa7134_format {
 #define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
 #define SAA7134_BOARD_PHILIPS_TIGER  81
 #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS  82
+#define SAA7134_BOARD_CINERGY250PCI 83
+#define SAA7134_BOARD_FLYDVB_TRIO 84
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -546,7 +547,6 @@ struct saa7134_dev {
 
 extern struct list_head  saa7134_devlist;
 
-void saa7134_print_ioctl(char *name, unsigned int cmd);
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
 
 #define SAA7134_PGTABLE_SIZE 4096
index d4497dbae05c7b641abaa617e9f17563847ecd0e..6ee54a45411f19ae95b1cf9f3cebe6b8b8b0f82d 100644 (file)
@@ -1974,6 +1974,7 @@ static struct file_operations saa_fops =
        .open           = saa_open,
        .release        = saa_release,
        .ioctl          = saa_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .read           = saa_read,
        .llseek         = no_llseek,
        .write          = saa_write,
index 549c9929f107a84c76861df192c5db736aa3b541..99261f15e66ebebdb15a3ea9921ff1029188d291 100644 (file)
@@ -50,6 +50,7 @@
 
 #include "bttv.h"
 #include <media/audiochip.h>
+#include <media/v4l2-common.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
 # define VIDEO_AUDIO_BALANCE 32
@@ -90,9 +91,6 @@ struct tda7432 {
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
-#define dprintk  if (debug) printk
-#define d2printk if (debug > 1) printk
-
 /* The TDA7432 is made by STS-Thompson
  * http://www.st.com
  * http://us.st.com/stonline/books/pdf/docs/4056.pdf
@@ -229,12 +227,12 @@ static struct i2c_client client_template;
 static int tda7432_write(struct i2c_client *client, int subaddr, int val)
 {
        unsigned char buffer[2];
-       d2printk("tda7432: In tda7432_write\n");
-       dprintk("tda7432: Writing %d 0x%x\n", subaddr, val);
+       v4l_dbg(2,client,"In tda7432_write\n");
+       v4l_dbg(1,client,"Writing %d 0x%x\n", subaddr, val);
        buffer[0] = subaddr;
        buffer[1] = val;
        if (2 != i2c_master_send(client,buffer,2)) {
-               printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n",
+               v4l_err(client,"I/O error, trying (write %d 0x%x)\n",
                       subaddr, val);
                return -1;
        }
@@ -247,9 +245,9 @@ static int tda7432_set(struct i2c_client *client)
 {
        struct tda7432 *t = i2c_get_clientdata(client);
        unsigned char buf[16];
-       d2printk("tda7432: In tda7432_set\n");
+       v4l_dbg(2,client,"In tda7432_set\n");
 
-       dprintk(KERN_INFO
+       v4l_dbg(1,client,
                "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
                t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud);
        buf[0]  = TDA7432_IN;
@@ -263,7 +261,7 @@ static int tda7432_set(struct i2c_client *client)
        buf[8]  = t->rr;
        buf[9]  = t->loud;
        if (10 != i2c_master_send(client,buf,10)) {
-               printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n");
+               v4l_err(client,"I/O error, trying tda7432_set\n");
                return -1;
        }
 
@@ -273,7 +271,7 @@ static int tda7432_set(struct i2c_client *client)
 static void do_tda7432_init(struct i2c_client *client)
 {
        struct tda7432 *t = i2c_get_clientdata(client);
-       d2printk("tda7432: In tda7432_init\n");
+       v4l_dbg(2,client,"In tda7432_init\n");
 
        t->input  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
                    TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
@@ -301,7 +299,6 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        struct tda7432 *t;
        struct i2c_client *client;
-       d2printk("tda7432: In tda7432_attach\n");
 
        t = kmalloc(sizeof *t,GFP_KERNEL);
        if (!t)
@@ -315,21 +312,16 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
        i2c_set_clientdata(client, t);
 
        do_tda7432_init(client);
-       printk(KERN_INFO "tda7432: init\n");
-
        i2c_attach_client(client);
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n", addr << 1, adap->name);
        return 0;
 }
 
 static int tda7432_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, tda7432_attach);
-#else
-       if (adap->id == I2C_HW_B_BT848)
-               return i2c_probe(adap, &addr_data, tda7432_attach);
-#endif
        return 0;
 }
 
@@ -348,7 +340,9 @@ static int tda7432_command(struct i2c_client *client,
                           unsigned int cmd, void *arg)
 {
        struct tda7432 *t = i2c_get_clientdata(client);
-       d2printk("tda7432: In tda7432_command\n");
+       v4l_dbg(2,client,"In tda7432_command\n");
+       if (debug>1)
+               v4l_i2c_print_ioctl(client,cmd);
 
        switch (cmd) {
        /* --- v4l ioctls --- */
@@ -359,7 +353,6 @@ static int tda7432_command(struct i2c_client *client,
        case VIDIOCGAUDIO:
        {
                struct video_audio *va = arg;
-               dprintk("tda7432: VIDIOCGAUDIO\n");
 
                va->flags |= VIDEO_AUDIO_VOLUME |
                        VIDEO_AUDIO_BASS |
@@ -414,7 +407,6 @@ static int tda7432_command(struct i2c_client *client,
        case VIDIOCSAUDIO:
        {
                struct video_audio *va = arg;
-               dprintk("tda7432: VIDEOCSAUDIO\n");
 
                if(va->flags & VIDEO_AUDIO_VOLUME){
                        if(!maxvol){ /* max +20db */
@@ -490,11 +482,6 @@ static int tda7432_command(struct i2c_client *client,
 
        } /* end of VIDEOCSAUDIO case */
 
-       default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
-
-               /* nothing */
-               d2printk("tda7432: Default\n");
-
        } /* end of (cmd) switch */
 
        return 0;
@@ -502,7 +489,7 @@ static int tda7432_command(struct i2c_client *client,
 
 static struct i2c_driver driver = {
        .driver = {
-               .name    = "i2c tda7432 driver",
+               .name    = "tda7432",
        },
        .id              = I2C_DRIVERID_TDA7432,
        .attach_adapter  = tda7432_probe,
@@ -519,7 +506,7 @@ static struct i2c_client client_template =
 static int __init tda7432_init(void)
 {
        if ( (loudness < 0) || (loudness > 15) ) {
-               printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n");
+               printk(KERN_ERR "loudness parameter must be between 0 and 15\n");
                return -EINVAL;
        }
 
index 61d94ddaff41f836f925a96a997266623aabb8c8..2498b76df429c3d36cd48588703a4e0513b896e7 100644 (file)
@@ -398,14 +398,8 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        return 0;
 }
 
-
 /*---------------------------------------------------------------------*/
 
-#define V4L2_STD_MN    (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
-#define V4L2_STD_B     (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
-#define V4L2_STD_GH    (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
-#define V4L2_STD_DK    (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
-
 static void set_audio(struct tuner *t)
 {
        char* mode;
index 9c3ecf7a0fedef2b25f0fd19ac0d9a8b2a30ffcc..299393bf900a38c7fd67754a8845a8be102f070e 100644 (file)
@@ -257,13 +257,8 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
 
 static int tda9875_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, tda9875_attach);
-#else
-       if (adap->id == I2C_HW_B_BT848)
-               return i2c_probe(adap, &addr_data, tda9875_attach);
-#endif
        return 0;
 }
 
@@ -373,7 +368,7 @@ static int tda9875_command(struct i2c_client *client,
 
 static struct i2c_driver driver = {
        .driver = {
-               .name   = "i2c tda9875 driver",
+               .name   = "tda9875",
        },
        .id             = I2C_DRIVERID_TDA9875,
        .attach_adapter = tda9875_probe,
index 7165a1b9625a475a00283fc36c0daa1551fb9336..9cf47dc65579c28acc2b9fcf4224593884484745 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
 #include <media/tuner.h>
 
 
@@ -57,7 +57,6 @@ struct tda9887 {
        v4l2_std_id        std;
        enum tuner_mode    mode;
        unsigned int       config;
-       unsigned int       pinnacle_id;
        unsigned int       using_v4l2;
        unsigned int       radio_mode;
        unsigned char      data[4];
@@ -115,6 +114,9 @@ static struct i2c_client client_template;
 #define cAudioGain0             0x00    // bit c7
 #define cAudioGain6             0x80    // bit c7
 
+#define cTopMask                0x1f    // bit c0:4
+#define cTopPalSecamDefault    0x14    // bit c0:4
+#define cTopNtscRadioDefault   0x10    // bit c0:4
 
 //// third reg (e)
 #define cAudioIF_4_5             0x00    // bit e0:1
@@ -146,13 +148,15 @@ static struct i2c_client client_template;
 
 static struct tvnorm tvnorms[] = {
        {
-               .std   = V4L2_STD_PAL_BG,
-               .name  = "PAL-BG",
+               .std   = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
+               .name  = "PAL-BGHN",
                .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cDeemphasisON  |
-                          cDeemphasis50  ),
-               .e     = ( cAudioIF_5_5   |
+                          cDeemphasis50  |
+                          cTopPalSecamDefault),
+               .e     = ( cGating_36     |
+                          cAudioIF_5_5   |
                           cVideoIF_38_90 ),
        },{
                .std   = V4L2_STD_PAL_I,
@@ -160,8 +164,10 @@ static struct tvnorm tvnorms[] = {
                .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cDeemphasisON  |
-                          cDeemphasis50  ),
-               .e     = ( cAudioIF_6_0   |
+                          cDeemphasis50  |
+                          cTopPalSecamDefault),
+               .e     = ( cGating_36     |
+                          cAudioIF_6_0   |
                           cVideoIF_38_90 ),
        },{
                .std   = V4L2_STD_PAL_DK,
@@ -169,52 +175,80 @@ static struct tvnorm tvnorms[] = {
                .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cDeemphasisON  |
-                          cDeemphasis50  ),
-               .e     = ( cAudioIF_6_5   |
-                          cVideoIF_38_00 ),
+                          cDeemphasis50  |
+                          cTopPalSecamDefault),
+               .e     = ( cGating_36     |
+                          cAudioIF_6_5   |
+                          cVideoIF_38_90 ),
        },{
-               .std   = V4L2_STD_PAL_M | V4L2_STD_PAL_N,
-               .name  = "PAL-M/N",
+               .std   = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
+               .name  = "PAL-M/Nc",
                .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cDeemphasisON  |
-                          cDeemphasis75  ),
-               .e     = ( cAudioIF_4_5   |
+                          cDeemphasis75  |
+                          cTopNtscRadioDefault),
+               .e     = ( cGating_36     |
+                          cAudioIF_4_5   |
                           cVideoIF_45_75 ),
+       },{
+               .std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
+               .name  = "SECAM-BGH",
+               .b     = ( cPositiveAmTV  |
+                          cQSS           ),
+               .c     = ( cTopPalSecamDefault),
+               .e     = ( cGating_36     |
+                          cAudioIF_5_5   |
+                          cVideoIF_38_90 ),
        },{
                .std   = V4L2_STD_SECAM_L,
                .name  = "SECAM-L",
                .b     = ( cPositiveAmTV  |
                           cQSS           ),
+               .c     = ( cTopPalSecamDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_38_90 ),
+       },{
+               .std   = V4L2_STD_SECAM_LC,
+               .name  = "SECAM-L'",
+               .b     = ( cOutputPort2Inactive |
+                          cPositiveAmTV  |
+                          cQSS           ),
+               .c     = ( cTopPalSecamDefault),
+               .e     = ( cGating_36     |
+                          cAudioIF_6_5   |
+                          cVideoIF_33_90 ),
        },{
                .std   = V4L2_STD_SECAM_DK,
                .name  = "SECAM-DK",
                .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cDeemphasisON  |
-                          cDeemphasis50  ),
-               .e     = ( cAudioIF_6_5   |
-                          cVideoIF_38_00 ),
+                          cDeemphasis50  |
+                          cTopPalSecamDefault),
+               .e     = ( cGating_36     |
+                          cAudioIF_6_5   |
+                          cVideoIF_38_90 ),
        },{
                .std   = V4L2_STD_NTSC_M,
                .name  = "NTSC-M",
                .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cDeemphasisON  |
-                          cDeemphasis75  ),
+                          cDeemphasis75  |
+                          cTopNtscRadioDefault),
                .e     = ( cGating_36     |
                           cAudioIF_4_5   |
                           cVideoIF_45_75 ),
        },{
                .std   = V4L2_STD_NTSC_M_JP,
-               .name  = "NTSC-JP",
+               .name  = "NTSC-M-JP",
                .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cDeemphasisON  |
-                          cDeemphasis50  ),
+                          cDeemphasis50  |
+                          cTopNtscRadioDefault),
                .e     = ( cGating_36     |
                           cAudioIF_4_5   |
                           cVideoIF_58_75 ),
@@ -226,8 +260,10 @@ static struct tvnorm radio_stereo = {
        .b    = ( cFmRadio       |
                  cQSS           ),
        .c    = ( cDeemphasisOFF |
-                 cAudioGain6 ),
-       .e    = ( cAudioIF_5_5   |
+                 cAudioGain6    |
+                 cTopNtscRadioDefault),
+       .e    = ( cTunerGainLow  |
+                 cAudioIF_5_5   |
                  cRadioIF_38_90 ),
 };
 
@@ -236,8 +272,10 @@ static struct tvnorm radio_mono = {
        .b    = ( cFmRadio       |
                  cQSS           ),
        .c    = ( cDeemphasisON  |
-                 cDeemphasis50),
-       .e    = ( cAudioIF_5_5   |
+                 cDeemphasis75  |
+                 cTopNtscRadioDefault),
+       .e    = ( cTunerGainLow  |
+                 cAudioIF_5_5   |
                  cRadioIF_38_90 ),
 };
 
@@ -400,7 +438,8 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
 static unsigned int port1  = UNSET;
 static unsigned int port2  = UNSET;
 static unsigned int qss    = UNSET;
-static unsigned int adjust = 0x10;
+static unsigned int adjust = UNSET;
+
 module_param(port1, int, 0644);
 module_param(port2, int, 0644);
 module_param(qss, int, 0644);
@@ -428,8 +467,10 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf)
                        buf[1] &= ~cQSS;
        }
 
-       if (adjust >= 0x00 && adjust < 0x20)
+       if (adjust >= 0x00 && adjust < 0x20) {
+               buf[2] &= ~cTopMask;
                buf[2] |= adjust;
+       }
        return 0;
 }
 
@@ -465,6 +506,10 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
                        break;
                }
        }
+       if (t->config & TDA9887_TOP_SET) {
+               buf[2] &= ~cTopMask;
+               buf[2] |= (t->config >> 8) & cTopMask;
+       }
        if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
                buf[1] &= ~cQSS;
        return 0;
@@ -472,38 +517,13 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_set_pinnacle(struct tda9887 *t, char *buf)
-{
-       unsigned int bCarrierMode = UNSET;
-
-       if (t->std & V4L2_STD_625_50) {
-               if ((1 == t->pinnacle_id) || (7 == t->pinnacle_id)) {
-                       bCarrierMode = cIntercarrier;
-               } else {
-                       bCarrierMode = cQSS;
-               }
-       }
-       if (t->std & V4L2_STD_525_60) {
-               if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
-                       bCarrierMode = cIntercarrier;
-               } else {
-                       bCarrierMode = cQSS;
-               }
-       }
-
-       if (bCarrierMode != UNSET) {
-               buf[1] &= ~0x04;
-               buf[1] |= bCarrierMode;
-       }
-       return 0;
-}
-
-/* ---------------------------------------------------------------------- */
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
 
-static char pal[] = "-";
 module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "-";
 module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 
 static int tda9887_fixup_std(struct tda9887 *t)
 {
@@ -514,8 +534,17 @@ static int tda9887_fixup_std(struct tda9887 *t)
                case 'B':
                case 'g':
                case 'G':
-                       tda9887_dbg("insmod fixup: PAL => PAL-BG\n");
-                       t->std = V4L2_STD_PAL_BG;
+               case 'h':
+               case 'H':
+               case 'n':
+               case 'N':
+                       if (pal[1] == 'c' || pal[1] == 'C') {
+                               tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
+                               t->std = V4L2_STD_PAL_Nc;
+                       } else {
+                               tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
+                               t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
+                       }
                        break;
                case 'i':
                case 'I':
@@ -529,6 +558,11 @@ static int tda9887_fixup_std(struct tda9887 *t)
                        tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
                        t->std = V4L2_STD_PAL_DK;
                        break;
+               case 'm':
+               case 'M':
+                       tda9887_dbg("insmod fixup: PAL => PAL-M\n");
+                       t->std = V4L2_STD_PAL_M;
+                       break;
                case '-':
                        /* default parameter, do nothing */
                        break;
@@ -539,6 +573,15 @@ static int tda9887_fixup_std(struct tda9887 *t)
        }
        if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
                switch (secam[0]) {
+               case 'b':
+               case 'B':
+               case 'g':
+               case 'G':
+               case 'h':
+               case 'H':
+                       tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
+                       t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+                       break;
                case 'd':
                case 'D':
                case 'k':
@@ -548,8 +591,13 @@ static int tda9887_fixup_std(struct tda9887 *t)
                        break;
                case 'l':
                case 'L':
-                       tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
-                       t->std = V4L2_STD_SECAM_L;
+                       if (secam[1] == 'c' || secam[1] == 'C') {
+                               tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
+                               t->std = V4L2_STD_SECAM_LC;
+                       } else {
+                               tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
+                               t->std = V4L2_STD_SECAM_L;
+                       }
                        break;
                case '-':
                        /* default parameter, do nothing */
@@ -559,6 +607,26 @@ static int tda9887_fixup_std(struct tda9887 *t)
                        break;
                }
        }
+       if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+               switch (ntsc[0]) {
+               case 'm':
+               case 'M':
+                       tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
+                       t->std = V4L2_STD_NTSC_M;
+                       break;
+               case 'j':
+               case 'J':
+                       tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
+                       t->std = V4L2_STD_NTSC_M_JP;
+                       break;
+               case '-':
+                       /* default parameter, do nothing */
+                       break;
+               default:
+                       tda9887_info("ntsc= argument not recognised\n");
+                       break;
+               }
+       }
        return 0;
 }
 
@@ -581,12 +649,22 @@ static int tda9887_configure(struct tda9887 *t)
        memset(t->data,0,sizeof(t->data));
        tda9887_set_tvnorm(t,t->data);
 
+       /* A note on the port settings:
+          These settings tend to depend on the specifics of the board.
+          By default they are set to inactive (bit value 1) by this driver,
+          overwriting any changes made by the tvnorm. This means that it
+          is the responsibility of the module using the tda9887 to set
+          these values in case of changes in the tvnorm.
+          In many cases port 2 should be made active (0) when selecting
+          SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
+
+          For the other standards the tda9887 application note says that
+          the ports should be set to active (0), but, again, that may
+          differ depending on the precise hardware configuration.
+        */
        t->data[1] |= cOutputPort1Inactive;
        t->data[1] |= cOutputPort2Inactive;
 
-       if (UNSET != t->pinnacle_id) {
-               tda9887_set_pinnacle(t,t->data);
-       }
        tda9887_set_config(t,t->data);
        tda9887_set_insmod(t,t->data);
 
@@ -594,7 +672,6 @@ static int tda9887_configure(struct tda9887 *t)
                t->data[1] |= cForcedMuteAudioON;
        }
 
-
        tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
                t->data[1],t->data[2],t->data[3]);
        if (debug > 1)
@@ -625,7 +702,6 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
 
        t->client      = client_template;
        t->std         = 0;
-       t->pinnacle_id = UNSET;
        t->radio_mode = V4L2_TUNER_MODE_STEREO;
 
        tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
@@ -638,18 +714,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
 
 static int tda9887_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, tda9887_attach);
-#else
-       switch (adap->id) {
-       case I2C_HW_B_BT848:
-       case I2C_HW_B_RIVA:
-       case I2C_HW_SAA7134:
-               return i2c_probe(adap, &addr_data, tda9887_attach);
-               break;
-       }
-#endif
        return 0;
 }
 
@@ -689,14 +755,6 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
                tda9887_configure(t);
                break;
        }
-       case AUDC_CONFIG_PINNACLE:
-       {
-               int *i = arg;
-
-               t->pinnacle_id = *i;
-               tda9887_configure(t);
-               break;
-       }
        case TDA9887_SET_CONFIG:
        {
                int *i = arg;
@@ -787,7 +845,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
        }
        case VIDIOC_LOG_STATUS:
        {
-               tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]);
+               tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
                break;
        }
        default:
@@ -824,7 +882,7 @@ static struct i2c_driver driver = {
        .detach_client  = tda9887_detach,
        .command        = tda9887_command,
        .driver = {
-               .name    = "i2c tda9887 driver",
+               .name    = "tda9887",
                .suspend = tda9887_suspend,
                .resume  = tda9887_resume,
        },
index a9375ef05de121b5986060fc6c464f97d0d53e3f..261b7a3c041735ce88337db628495c2c0c485526 100644 (file)
@@ -17,6 +17,9 @@
 
 #define PREFIX "TEA5767 "
 
+/* from tuner-core.c */
+extern int debug;
+
 /*****************************************************************************/
 
 /******************************
@@ -246,7 +249,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
        if (5 != (rc = i2c_master_send(c, buffer, 5)))
                tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
 
-       if (tuner_debug) {
+       if (debug) {
                if (5 != (rc = i2c_master_recv(c, buffer, 5)))
                        tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
                else
@@ -264,7 +267,7 @@ static int tea5767_signal(struct i2c_client *c)
        if (5 != (rc = i2c_master_recv(c, buffer, 5)))
                tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
 
-       return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << (13 - 4));
+       return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
 }
 
 static int tea5767_stereo(struct i2c_client *c)
index c13c7b95ef35860f581c008d3f15e0f07fcfba74..57bc585a6955c135dfad3c37fefd0f4eaf58c79c 100644 (file)
 #include <linux/init.h>
 
 #include <media/tuner.h>
+#include <media/v4l2-common.h>
 #include <media/audiochip.h>
 
-#include "msp3400.h"
-
 #define UNSET (-1U)
 
 /* standard i2c insmod options */
@@ -38,21 +37,30 @@ I2C_CLIENT_INSMOD;
 
 /* insmod options used at init time => read/only */
 static unsigned int addr = 0;
-module_param(addr, int, 0444);
-
 static unsigned int no_autodetect = 0;
-module_param(no_autodetect, int, 0444);
-
 static unsigned int show_i2c = 0;
-module_param(show_i2c, int, 0444);
 
 /* insmod options used at runtime => read/write */
-unsigned int tuner_debug = 0;
-module_param(tuner_debug, int, 0644);
+static unsigned int tuner_debug = 0;
+int debug = 0;
 
 static unsigned int tv_range[2] = { 44, 958 };
 static unsigned int radio_range[2] = { 65, 108 };
 
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+module_param(addr, int, 0444);
+module_param(no_autodetect, int, 0444);
+module_param(show_i2c, int, 0444);
+/* Note: tuner_debug is deprecated and will be removed in 2.6.17 */
+module_param(tuner_debug, int, 0444);
+module_param(debug, int, 0644);
+
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 module_param_array(tv_range, int, NULL, 0644);
 module_param_array(radio_range, int, NULL, 0644);
 
@@ -249,11 +257,6 @@ static inline int check_mode(struct tuner *t, char *cmd)
        return 0;
 }
 
-static char pal[] = "-";
-module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "--";
-module_param_string(secam, secam, sizeof(secam), 0644);
-
 /* get more precise norm info from insmod option */
 static int tuner_fixup_std(struct tuner *t)
 {
@@ -285,8 +288,13 @@ static int tuner_fixup_std(struct tuner *t)
                        break;
                case 'N':
                case 'n':
-                       tuner_dbg ("insmod fixup: PAL => PAL-N\n");
-                       t->std = V4L2_STD_PAL_N;
+                       if (pal[1] == 'c' || pal[1] == 'C') {
+                               tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
+                               t->std = V4L2_STD_PAL_Nc;
+                       } else {
+                               tuner_dbg ("insmod fixup: PAL => PAL-N\n");
+                               t->std = V4L2_STD_PAL_N;
+                       }
                        break;
                case '-':
                        /* default parameter, do nothing */
@@ -298,6 +306,15 @@ static int tuner_fixup_std(struct tuner *t)
        }
        if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
                switch (secam[0]) {
+               case 'b':
+               case 'B':
+               case 'g':
+               case 'G':
+               case 'h':
+               case 'H':
+                       tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
+                       t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+                       break;
                case 'd':
                case 'D':
                case 'k':
@@ -324,9 +341,60 @@ static int tuner_fixup_std(struct tuner *t)
                }
        }
 
+       if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+               switch (ntsc[0]) {
+               case 'm':
+               case 'M':
+                       tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
+                       t->std = V4L2_STD_NTSC_M;
+                       break;
+               case 'j':
+               case 'J':
+                       tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
+                       t->std = V4L2_STD_NTSC_M_JP;
+                       break;
+               case '-':
+                       /* default parameter, do nothing */
+                       break;
+               default:
+                       tuner_info("ntsc= argument not recognised\n");
+                       break;
+               }
+       }
        return 0;
 }
 
+static void tuner_status(struct i2c_client *client)
+{
+       struct tuner *t = i2c_get_clientdata(client);
+       unsigned long freq, freq_fraction;
+       const char *p;
+
+       switch (t->mode) {
+               case V4L2_TUNER_RADIO:      p = "radio"; break;
+               case V4L2_TUNER_ANALOG_TV:  p = "analog TV"; break;
+               case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
+               default: p = "undefined"; break;
+       }
+       if (t->mode == V4L2_TUNER_RADIO) {
+               freq = t->freq / 16000;
+               freq_fraction = (t->freq % 16000) * 100 / 16000;
+       } else {
+               freq = t->freq / 16;
+               freq_fraction = (t->freq % 16) * 100 / 16;
+       }
+       tuner_info("Tuner mode:      %s\n", p);
+       tuner_info("Frequency:       %lu.%02lu MHz\n", freq, freq_fraction);
+       tuner_info("Standard:        0x%08llx\n", t->std);
+       if (t->mode == V4L2_TUNER_RADIO) {
+               if (t->has_signal) {
+                       tuner_info("Signal strength: %d\n", t->has_signal(client));
+               }
+               if (t->is_stereo) {
+                       tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
+               }
+       }
+}
 /* ---------------------------------------------------------------------- */
 
 /* static var Used only in tuner_attach and tuner_probe */
@@ -352,6 +420,11 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        t->radio_if2 = 10700 * 1000;    /* 10.7MHz - FM radio */
        t->audmode = V4L2_TUNER_MODE_STEREO;
        t->mode_mask = T_UNINITIALIZED;
+       if (tuner_debug) {
+               debug = tuner_debug;
+               printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
+               printk(KERN_ERR "tuner: use the debug option instead.\n");
+       }
 
        if (show_i2c) {
                unsigned char buffer[16];
@@ -478,7 +551,9 @@ static inline int check_v4l2(struct tuner *t)
 static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct tuner *t = i2c_get_clientdata(client);
-       unsigned int *iarg = (int *)arg;
+
+       if (debug>1)
+               v4l_i2c_print_ioctl(&(t->i2c),cmd);
 
        switch (cmd) {
        /* --- configuration --- */
@@ -501,18 +576,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                t->standby (client);
                        break;
                }
-       case AUDC_CONFIG_PINNACLE:
-               switch (*iarg) {
-               case 2:
-                       tuner_dbg("pinnacle pal\n");
-                       t->radio_if2 = 33300 * 1000;
-                       break;
-               case 3:
-                       tuner_dbg("pinnacle ntsc\n");
-                       t->radio_if2 = 41300 * 1000;
-                       break;
-               }
-               break;
        case VIDIOCSAUDIO:
                if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
                        return 0;
@@ -522,9 +585,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                /* Should be implemented, since bttv calls it */
                tuner_dbg("VIDIOCSAUDIO not implemented.\n");
 
-               break;
-       case MSP_SET_MATRIX:
-       case TDA9887_SET_CONFIG:
                break;
        /* --- v4l ioctls --- */
        /* take care: bttv does userspace copying, we'll get a
@@ -708,10 +768,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        }
                        break;
                }
-       default:
-               tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n",
-                                        cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd),
-                                       _IOC_NR(cmd), _IOC_SIZE(cmd));
+       case VIDIOC_LOG_STATUS:
+               tuner_status(client);
                break;
        }
 
@@ -747,10 +805,10 @@ static struct i2c_driver driver = {
        .detach_client = tuner_detach,
        .command = tuner_command,
        .driver = {
-                  .name = "tuner",
-                  .suspend = tuner_suspend,
-                  .resume = tuner_resume,
-                  },
+               .name    = "tuner",
+               .suspend = tuner_suspend,
+               .resume  = tuner_resume,
+       },
 };
 static struct i2c_client client_template = {
        .name = "(tuner unset)",
index e0c9fdb9914a673846ba6ffb3aae3cee5d55d7c3..e5fb7436583692041008d01af5aee86d55f58cf6 100644 (file)
@@ -8,6 +8,10 @@
 #include <linux/videodev.h>
 #include <media/tuner.h>
 
+static int offset = 0;
+module_param(offset, int, 0666);
+MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
+
 /* ---------------------------------------------------------------------- */
 
 /* tv standard selection for Temic 4046 FM5
 #define TUNER_PLL_LOCKED   0x40
 #define TUNER_STEREO_MK3   0x04
 
+#define TUNER_MAX_RANGES   3
+
 /* ---------------------------------------------------------------------- */
 
 struct tunertype
 {
        char *name;
-       unsigned char Vendor;
-       unsigned char Type;
-
-       unsigned short thresh1;  /*  band switch VHF_LO <=> VHF_HI  */
-       unsigned short thresh2;  /*  band switch VHF_HI <=> UHF     */
-       unsigned char VHF_L;
-       unsigned char VHF_H;
-       unsigned char UHF;
+
+       int count;
+       struct {
+               unsigned short thresh;
+               unsigned char cb;
+       } ranges[TUNER_MAX_RANGES];
        unsigned char config;
-       unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL,
-                                  732  =16*45.75 NTSCi,
-                                  940  =16*58.75 NTSC-Japan
-                                  704  =16*44    ATSC */
 };
 
 /*
@@ -102,158 +102,696 @@ struct tunertype
  */
 static struct tunertype tuners[] = {
        /* 0-9 */
-       { "Temic PAL (4002 FH5)", TEMIC, PAL,
-         16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
-       { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
-         16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-       { "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC,
-         16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
-       { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM,
-         16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
-       { "NoTuner", NoTuner, NOTUNER,
-         0,0,0x00,0x00,0x00,0x00,0x00},
-       { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL,
-         16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623},
-       { "Temic NTSC (4032 FY5)", TEMIC, NTSC,
-         16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
-       { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
-         16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
-       { "Temic NTSC (4036 FY5)", TEMIC, NTSC,
-         16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
-       { "Alps HSBH1", TEMIC, NTSC,
-         16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
+       [TUNER_TEMIC_PAL] = { /* TEMIC PAL */
+               .name   = "Temic PAL (4002 FH5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 140.25 /*MHz*/, 0x02, },
+                       { 16 * 463.25 /*MHz*/, 0x04, },
+                       { 16 * 999.99        , 0x01, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
+               .name   = "Philips PAL_I (FI1246 and compatibles)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 140.25 /*MHz*/, 0xa0, },
+                       { 16 * 463.25 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
+               .name   = "Philips NTSC (FI1236,FM1236 and compatibles)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 157.25 /*MHz*/, 0xa0, },
+                       { 16 * 451.25 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
+               .name   = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 168.25 /*MHz*/, 0xa7, },
+                       { 16 * 447.25 /*MHz*/, 0x97, },
+                       { 16 * 999.99        , 0x37, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_ABSENT] = { /* Tuner Absent */
+               .name   = "NoTuner",
+               .count  = 1,
+               .ranges = {
+                       { 0, 0x00, },
+               },
+               .config = 0x00,
+       },
+       [TUNER_PHILIPS_PAL] = { /* Philips PAL */
+               .name   = "Philips PAL_BG (FI1216 and compatibles)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 168.25 /*MHz*/, 0xa0, },
+                       { 16 * 447.25 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
+               .name   = "Temic NTSC (4032 FY5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 157.25 /*MHz*/, 0x02, },
+                       { 16 * 463.25 /*MHz*/, 0x04, },
+                       { 16 * 999.99        , 0x01, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
+               .name   = "Temic PAL_I (4062 FY5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0x02, },
+                       { 16 * 450.00 /*MHz*/, 0x04, },
+                       { 16 * 999.99        , 0x01, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
+               .name   = "Temic NTSC (4036 FY5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 157.25 /*MHz*/, 0xa0, },
+                       { 16 * 463.25 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
+               .name   = "Alps HSBH1",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 137.25 /*MHz*/, 0x01, },
+                       { 16 * 385.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
 
        /* 10-19 */
-       { "Alps TSBE1", TEMIC, PAL,
-         16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
-       { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
-         16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
-       { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
-         16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
-       { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
-         16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
-       { "Temic PAL_BG (4006FH5)", TEMIC, PAL,
-         16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-       { "Alps TSCH6", Alps, NTSC,
-         16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
-       { "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
-         16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
-       { "Philips NTSC_M (MK2)", Philips, NTSC,
-         16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
-       { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
-         16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-       { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
-         16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+       [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
+               .name   = "Alps TSBE1",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 137.25 /*MHz*/, 0x01, },
+                       { 16 * 385.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
+               .name   = "Alps TSBB5",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 133.25 /*MHz*/, 0x01, },
+                       { 16 * 351.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
+               .name   = "Alps TSBE5",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 133.25 /*MHz*/, 0x01, },
+                       { 16 * 351.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
+               .name   = "Alps TSBC5",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 133.25 /*MHz*/, 0x01, },
+                       { 16 * 351.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
+               .name   = "Temic PAL_BG (4006FH5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0xa0, },
+                       { 16 * 450.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
+               .name   = "Alps TSCH6",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 137.25 /*MHz*/, 0x14, },
+                       { 16 * 385.25 /*MHz*/, 0x12, },
+                       { 16 * 999.99        , 0x11, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
+               .name   = "Temic PAL_DK (4016 FY5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 168.25 /*MHz*/, 0xa0, },
+                       { 16 * 456.25 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
+               .name   = "Philips NTSC_M (MK2)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0xa0, },
+                       { 16 * 454.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
+               .name   = "Temic PAL_I (4066 FY5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 169.00 /*MHz*/, 0xa0, },
+                       { 16 * 454.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
+               .name   = "Temic PAL* auto (4006 FN5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 169.00 /*MHz*/, 0xa0, },
+                       { 16 * 454.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
 
        /* 20-29 */
-       { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
-         16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-       { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
-         16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
-       { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
-         16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-       { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
-         16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-       { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
-         16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-       { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I,
-         16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-       { "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I,
-         16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-       { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC,
-         16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732},
-       { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL,
-         16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-       { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
-         16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+       [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
+               .name   = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 141.00 /*MHz*/, 0xa0, },
+                       { 16 * 464.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
+               .name   = "Temic NTSC (4039 FR5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 158.00 /*MHz*/, 0xa0, },
+                       { 16 * 453.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
+               .name   = "Temic PAL/SECAM multi (4046 FM5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 169.00 /*MHz*/, 0xa0, },
+                       { 16 * 454.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
+               .name   = "Philips PAL_DK (FI1256 and compatibles)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0xa0, },
+                       { 16 * 450.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
+               .name   = "Philips PAL/SECAM multi (FQ1216ME)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0xa0, },
+                       { 16 * 450.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
+               .name   = "LG PAL_I+FM (TAPC-I001D)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0xa0, },
+                       { 16 * 450.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
+               .name   = "LG PAL_I (TAPC-I701D)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0xa0, },
+                       { 16 * 450.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
+               .name   = "LG NTSC+FM (TPI8NSR01F)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 210.00 /*MHz*/, 0xa0, },
+                       { 16 * 497.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
+               .name   = "LG PAL_BG+FM (TPI8PSB01D)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0xa0, },
+                       { 16 * 450.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_LG_PAL] = { /* LGINNOTEK PAL */
+               .name   = "LG PAL_BG (TPI8PSB11D)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0xa0, },
+                       { 16 * 450.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
 
        /* 30-39 */
-       { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
-         16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-       { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
-         16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 },
-       { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */
-         16*169,16*464,0xA0,0x90,0x30,0x8e,623},
-       { "MT20xx universal", Microtune, PAL|NTSC,
+       [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
+               .name   = "Temic PAL* auto + FM (4009 FN5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 141.00 /*MHz*/, 0xa0, },
+                       { 16 * 464.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
+               .name   = "SHARP NTSC_JP (2U5JF5540)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 137.25 /*MHz*/, 0x01, },
+                       { 16 * 317.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
+               .name   = "Samsung PAL TCPM9091PD27",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 169 /*MHz*/, 0xa0, },
+                       { 16 * 464 /*MHz*/, 0x90, },
+                       { 16 * 999.99     , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_MT2032] = { /* Microtune PAL|NTSC */
+               .name   = "MT20xx universal",
          /* see mt20xx.c for details */ },
-       { "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
-         16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-       { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
-         16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
-       { "Temic NTSC (4136 FY5)", TEMIC, NTSC,
-         16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
-       { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
-         16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
-       { "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
-         16*158.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
-       { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
-         16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+       [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
+               .name   = "Temic PAL_BG (4106 FH5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 141.00 /*MHz*/, 0xa0, },
+                       { 16 * 464.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
+               .name   = "Temic PAL_DK/SECAM_L (4012 FY5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 140.25 /*MHz*/, 0x02, },
+                       { 16 * 463.25 /*MHz*/, 0x04, },
+                       { 16 * 999.99        , 0x01, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
+               .name   = "Temic NTSC (4136 FY5)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 158.00 /*MHz*/, 0xa0, },
+                       { 16 * 453.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
+               .name   = "LG PAL (newer TAPC series)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0x01, },
+                       { 16 * 450.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
+               .name   = "Philips PAL/SECAM multi (FM1216ME MK3)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 158.00 /*MHz*/, 0x01, },
+                       { 16 * 442.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
+               .name   = "LG NTSC (newer TAPC series)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0x01, },
+                       { 16 * 450.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
 
        /* 40-49 */
-       { "HITACHI V7-J180AT", HITACHI, NTSC,
-         16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 },
-       { "Philips PAL_MK (FI1216 MK)", Philips, PAL,
-         16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
-       { "Philips 1236D ATSC/NTSC daul in", Philips, ATSC,
-         16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
-       { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
-         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
-       { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
-         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
-       { "Microtune 4049 FM5", Microtune, PAL,
-         16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
-       { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
-         16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
-       { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
-         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
-       { "Tenna TNF 8831 BGFF)", Philips, PAL,
-         16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-       { "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
-         16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
+       [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
+               .name   = "HITACHI V7-J180AT",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0x01, },
+                       { 16 * 450.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
+               .name   = "Philips PAL_MK (FI1216 MK)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 140.25 /*MHz*/, 0x01, },
+                       { 16 * 463.25 /*MHz*/, 0xc2, },
+                       { 16 * 999.99        , 0xcf, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
+               .name   = "Philips 1236D ATSC/NTSC dual in",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 157.25 /*MHz*/, 0xa0, },
+                       { 16 * 454.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
+               .name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01, },
+                       { 16 * 442.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
+               .name   = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01, },
+                       { 16 * 442.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
+               .name   = "Microtune 4049 FM5",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 141.00 /*MHz*/, 0xa0, },
+                       { 16 * 464.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
+               .name   = "Panasonic VP27s/ENGE4324D",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01, },
+                       { 16 * 454.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0xce,
+       },
+       [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
+               .name   = "LG NTSC (TAPE series)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01, },
+                       { 16 * 442.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TNF_8831BGFF] = { /* Philips PAL */
+               .name   = "Tenna TNF 8831 BGFF)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 161.25 /*MHz*/, 0xa0, },
+                       { 16 * 463.25 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
+               .name   = "Microtune 4042 FI5 ATSC/NTSC dual in",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 162.00 /*MHz*/, 0xa2, },
+                       { 16 * 457.00 /*MHz*/, 0x94, },
+                       { 16 * 999.99        , 0x31, },
+               },
+               .config = 0x8e,
+       },
 
        /* 50-59 */
-       { "TCL 2002N", TCL, NTSC,
-         16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
-       { "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
-         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
-       { "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC,
-         16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
-       { "Philips FQ1286", Philips, NTSC,
-         16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */
-       { "tda8290+75", Philips, PAL|NTSC,
+       [TUNER_TCL_2002N] = { /* TCL NTSC */
+               .name   = "TCL 2002N",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 172.00 /*MHz*/, 0x01, },
+                       { 16 * 448.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
+               .name   = "Philips PAL/SECAM_D (FM 1256 I-H3)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01, },
+                       { 16 * 442.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
+               .name   = "Thomson DTT 7610 (ATSC/NTSC)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 157.25 /*MHz*/, 0x39, },
+                       { 16 * 454.00 /*MHz*/, 0x3a, },
+                       { 16 * 999.99        , 0x3c, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
+               .name   = "Philips FQ1286",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x41, },
+                       { 16 * 454.00 /*MHz*/, 0x42, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
+               .name   = "tda8290+75",
          /* see tda8290.c for details */ },
-       { "TCL 2002MB", TCL, PAL,
-         16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
-       { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
-         16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
-       { "Philips FQ1236A MK4", Philips, NTSC,
-         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
-       { "Ymec TVision TVF-8531MF/8831MF/8731MF", Philips, NTSC,
-         16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
-       { "Ymec TVision TVF-5533MF", Philips, NTSC,
-         16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
+       [TUNER_TCL_2002MB] = { /* TCL PAL */
+               .name   = "TCL 2002MB",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 170.00 /*MHz*/, 0x01, },
+                       { 16 * 450.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0xce,
+       },
+       [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
+               .name   = "Philips PAL/SECAM multi (FQ1216AME MK4)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01, },
+                       { 16 * 442.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0xce,
+       },
+       [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
+               .name   = "Philips FQ1236A MK4",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01, },
+                       { 16 * 442.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
+               .name   = "Ymec TVision TVF-8531MF/8831MF/8731MF",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0xa0, },
+                       { 16 * 454.00 /*MHz*/, 0x90, },
+                       { 16 * 999.99        , 0x30, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
+               .name   = "Ymec TVision TVF-5533MF",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01, },
+                       { 16 * 454.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
 
        /* 60-69 */
-       { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
-         16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
-       { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
-         16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
-       { "Philips TEA5767HN FM Radio", Philips, RADIO,
+       [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */
+               /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+               .name   = "Thomson DTT 761X (ATSC/NTSC)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 145.25 /*MHz*/, 0x39, },
+                       { 16 * 415.25 /*MHz*/, 0x3a, },
+                       { 16 * 999.99        , 0x3c, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TENA_9533_DI] = { /* Philips PAL */
+               .name   = "Tena TNF9533-D/IF/TNF9533-B/DF",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.25 /*MHz*/, 0x01, },
+                       { 16 * 464.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_TEA5767] = { /* Philips RADIO */
+               .name   = "Philips TEA5767HN FM Radio",
          /* see tea5767.c for details */},
-       { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
-         16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
-       { "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC,
-         16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732},
-       { "Ymec TVF66T5-B/DFF", Philips, PAL,
-         16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
-       { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
-         16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 },
-       { "Philips TD1316 Hybrid Tuner", Philips, PAL,
-         16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
-       { "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
-         16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
-       { "Tena TNF 5335 MF", Philips, NTSC,
-         16*157.25,16*454.00,0x01,0x02,0x04,0x8e,732 },
+       [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
+               .name   = "Philips FMD1216ME MK3 Hybrid Tuner",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x51, },
+                       { 16 * 442.00 /*MHz*/, 0x52, },
+                       { 16 * 999.99        , 0x54, },
+               },
+               .config = 0x86,
+       },
+       [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
+               .name   = "LG TDVS-H062F/TUA6034",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0x01 },
+                       { 16 * 455.00 /*MHz*/, 0x02 },
+                       { 16 * 999.99        , 0x04 },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
+               .name   = "Ymec TVF66T5-B/DFF",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.25 /*MHz*/, 0x01, },
+                       { 16 * 464.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */
+               .name   = "LG NTSC (TALN mini series)",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 137.25 /*MHz*/, 0x01, },
+                       { 16 * 373.25 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x08, },
+               },
+               .config = 0x8e,
+       },
+       [TUNER_PHILIPS_TD1316] = { /* Philips PAL */
+               .name   = "Philips TD1316 Hybrid Tuner",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 160.00 /*MHz*/, 0xa1, },
+                       { 16 * 442.00 /*MHz*/, 0xa2, },
+                       { 16 * 999.99        , 0xa4, },
+               },
+               .config = 0xc8,
+       },
+       [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
+               .name   = "Philips TUV1236D ATSC/NTSC dual in",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 157.25 /*MHz*/, 0x01, },
+                       { 16 * 454.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0xce,
+       },
+       [TUNER_TNF_5335MF] = { /* Philips NTSC */
+               .name   = "Tena TNF 5335 MF",
+               .count  = 3,
+               .ranges = {
+                       { 16 * 157.25 /*MHz*/, 0x01, },
+                       { 16 * 454.00 /*MHz*/, 0x02, },
+                       { 16 * 999.99        , 0x04, },
+               },
+               .config = 0x8e,
+       },
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
@@ -305,20 +843,19 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
        u16 div;
        struct tunertype *tun;
        unsigned char buffer[4];
-       int rc;
+       int rc, IFPCoff, i;
 
        tun = &tuners[t->type];
-       if (freq < tun->thresh1) {
-               config = tun->VHF_L;
-               tuner_dbg("tv: VHF lowrange\n");
-       } else if (freq < tun->thresh2) {
-               config = tun->VHF_H;
-               tuner_dbg("tv: VHF high range\n");
-       } else {
-               config = tun->UHF;
-               tuner_dbg("tv: UHF range\n");
+       for (i = 0; i < tun->count; i++) {
+               if (freq > tun->ranges[i].thresh)
+                       continue;
+               break;
        }
-
+       config = tun->ranges[i].cb;
+       /*  i == 0 -> VHF_LO  */
+       /*  i == 1 -> VHF_HI  */
+       /*  i == 2 -> UHF     */
+       tuner_dbg("tv: range %d\n",i);
 
        /* tv norm specific stuff for multi-norm tuners */
        switch (t->type) {
@@ -420,7 +957,37 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
         * frequency in case (wanted frequency < current frequency).
         */
 
-       div=freq + tun->IFPCoff;
+       /* IFPCoff = Video Intermediate Frequency - Vif:
+               940  =16*58.75  NTSC/J (Japan)
+               732  =16*45.75  M/N STD
+               704  =16*44     ATSC (at DVB code)
+               632  =16*39.50  I U.K.
+               622.4=16*38.90  B/G D/K I, L STD
+               592  =16*37.00  D China
+               590  =16.36.875 B Australia
+               543.2=16*33.95  L' STD
+               171.2=16*10.70  FM Radio (at set_radio_freq)
+       */
+
+       if (t->std == V4L2_STD_NTSC_M_JP) {
+               IFPCoff = 940;
+       } else if ((t->std & V4L2_STD_MN) &&
+                 !(t->std & ~V4L2_STD_MN)) {
+               IFPCoff = 732;
+       } else if (t->std == V4L2_STD_SECAM_LC) {
+               IFPCoff = 543;
+       } else {
+               IFPCoff = 623;
+       }
+
+       div=freq + IFPCoff + offset;
+
+       tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
+                                       freq / 16, freq % 16 * 100 / 16,
+                                       IFPCoff / 16, IFPCoff % 16 * 100 / 16,
+                                       offset / 16, offset % 16 * 100 / 16,
+                                       div);
+
        if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) {
                buffer[0] = tun->config;
                buffer[1] = config;
index 0292c5abf14aab3fe1355a31c0bc8abab3e8a01a..b582943a0d3e57406f9d3ed1434c20f26586b873 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smp_lock.h>
 
 #include <media/audiochip.h>
+#include <media/v4l2-common.h>
 
 #include "tvaudio.h"
 
@@ -46,17 +47,6 @@ MODULE_LICENSE("GPL");
 
 #define UNSET    (-1U)
 
-#define tvaudio_info(fmt, arg...) do {\
-       printk(KERN_INFO "tvaudio %d-%04x: " fmt, \
-                       chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-#define tvaudio_warn(fmt, arg...) do {\
-       printk(KERN_WARNING "tvaudio %d-%04x: " fmt, \
-                       chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-#define tvaudio_dbg(fmt, arg...) do {\
-       if (debug) \
-               printk(KERN_INFO "tvaudio %d-%04x: " fmt, \
-                       chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-
 /* ---------------------------------------------------------------------- */
 /* our structs                                                            */
 
@@ -131,7 +121,7 @@ struct CHIPSTATE {
        /* current settings */
        __u16 left,right,treble,bass,mode;
        int prevmode;
-       int norm;
+       int radio;
 
        /* thread */
        pid_t                tpid;
@@ -142,8 +132,6 @@ struct CHIPSTATE {
        int                  watch_stereo;
 };
 
-#define VIDEO_MODE_RADIO 16      /* norm magic for radio mode */
-
 /* ---------------------------------------------------------------------- */
 /* i2c addresses                                                          */
 
@@ -171,23 +159,23 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
        unsigned char buffer[2];
 
        if (-1 == subaddr) {
-               tvaudio_dbg("%s: chip_write: 0x%x\n",
+               v4l_dbg(1, &chip->c, "%s: chip_write: 0x%x\n",
                        chip->c.name, val);
                chip->shadow.bytes[1] = val;
                buffer[0] = val;
                if (1 != i2c_master_send(&chip->c,buffer,1)) {
-                       tvaudio_warn("%s: I/O error (write 0x%x)\n",
+                       v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n",
                                chip->c.name, val);
                        return -1;
                }
        } else {
-               tvaudio_dbg("%s: chip_write: reg%d=0x%x\n",
+               v4l_dbg(1, &chip->c, "%s: chip_write: reg%d=0x%x\n",
                        chip->c.name, subaddr, val);
                chip->shadow.bytes[subaddr+1] = val;
                buffer[0] = subaddr;
                buffer[1] = val;
                if (2 != i2c_master_send(&chip->c,buffer,2)) {
-                       tvaudio_warn("%s: I/O error (write reg%d=0x%x)\n",
+                       v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n",
                        chip->c.name, subaddr, val);
                        return -1;
                }
@@ -212,11 +200,11 @@ static int chip_read(struct CHIPSTATE *chip)
        unsigned char buffer;
 
        if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
-               tvaudio_warn("%s: I/O error (read)\n",
+               v4l_warn(&chip->c, "%s: I/O error (read)\n",
                chip->c.name);
                return -1;
        }
-       tvaudio_dbg("%s: chip_read: 0x%x\n",chip->c.name, buffer);
+       v4l_dbg(1, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer);
        return buffer;
 }
 
@@ -231,10 +219,10 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
        write[0] = subaddr;
 
        if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
-               tvaudio_warn("%s: I/O error (read2)\n", chip->c.name);
+               v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name);
                return -1;
        }
-       tvaudio_dbg("%s: chip_read2: reg%d=0x%x\n",
+       v4l_dbg(1, &chip->c, "%s: chip_read2: reg%d=0x%x\n",
                chip->c.name, subaddr,read[0]);
        return read[0];
 }
@@ -247,7 +235,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
                return 0;
 
        /* update our shadow register set; print bytes if (debug > 0) */
-       tvaudio_dbg("%s: chip_cmd(%s): reg=%d, data:",
+       v4l_dbg(1, &chip->c, "%s: chip_cmd(%s): reg=%d, data:",
                chip->c.name, name,cmd->bytes[0]);
        for (i = 1; i < cmd->count; i++) {
                if (debug)
@@ -259,7 +247,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
 
        /* send data to the chip */
        if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
-               tvaudio_warn("%s: I/O error (%s)\n", chip->c.name, name);
+               v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name);
                return -1;
        }
        return 0;
@@ -286,7 +274,7 @@ static int chip_thread(void *data)
 
        daemonize("%s", chip->c.name);
        allow_signal(SIGTERM);
-       tvaudio_dbg("%s: thread started\n", chip->c.name);
+       v4l_dbg(1, &chip->c, "%s: thread started\n", chip->c.name);
 
        for (;;) {
                add_wait_queue(&chip->wq, &wait);
@@ -298,10 +286,10 @@ static int chip_thread(void *data)
                try_to_freeze();
                if (chip->done || signal_pending(current))
                        break;
-               tvaudio_dbg("%s: thread wakeup\n", chip->c.name);
+               v4l_dbg(1, &chip->c, "%s: thread wakeup\n", chip->c.name);
 
                /* don't do anything for radio or if mode != auto */
-               if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0)
+               if (chip->radio || chip->mode != 0)
                        continue;
 
                /* have a look what's going on */
@@ -311,7 +299,7 @@ static int chip_thread(void *data)
                mod_timer(&chip->wt, jiffies+2*HZ);
        }
 
-       tvaudio_dbg("%s: thread exiting\n", chip->c.name);
+       v4l_dbg(1, &chip->c, "%s: thread exiting\n", chip->c.name);
        complete_and_exit(&chip->texit, 0);
        return 0;
 }
@@ -324,7 +312,7 @@ static void generic_checkmode(struct CHIPSTATE *chip)
        if (mode == chip->prevmode)
        return;
 
-       tvaudio_dbg("%s: thread checkmode\n", chip->c.name);
+       v4l_dbg(1, &chip->c, "%s: thread checkmode\n", chip->c.name);
        chip->prevmode = mode;
 
        if (mode & VIDEO_SOUND_STEREO)
@@ -371,7 +359,7 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
        if (val & TDA9840_ST_STEREO)
                mode |= VIDEO_SOUND_STEREO;
 
-       tvaudio_dbg ("tda9840_getmode(): raw chip read: %d, return: %d\n",
+       v4l_dbg(1, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
                val, mode);
        return mode;
 }
@@ -667,7 +655,7 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
                mode |= VIDEO_SOUND_STEREO;
        if (val & TDA9873_DUAL)
                mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       tvaudio_dbg ("tda9873_getmode(): raw chip read: %d, return: %d\n",
+       v4l_dbg(1, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
                val, mode);
        return mode;
 }
@@ -678,12 +666,12 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
        /*      int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
        if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
-               tvaudio_dbg("tda9873_setmode(): external input\n");
+               v4l_dbg(1, &chip->c, "tda9873_setmode(): external input\n");
                return;
        }
 
-       tvaudio_dbg("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
-       tvaudio_dbg("tda9873_setmode(): sw_data  = %d\n", sw_data);
+       v4l_dbg(1, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+       v4l_dbg(1, &chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
 
        switch (mode) {
        case VIDEO_SOUND_MONO:
@@ -704,7 +692,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
        }
 
        chip_write(chip, TDA9873_SW, sw_data);
-       tvaudio_dbg("tda9873_setmode(): req. mode %d; chip_write: %d\n",
+       v4l_dbg(1, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
                mode, sw_data);
 }
 
@@ -843,7 +831,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
                chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
                chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
        }
-       tvaudio_dbg("tda9874a_setup(): %s [0x%02X].\n",
+       v4l_dbg(1, &chip->c, "tda9874a_setup(): %s [0x%02X].\n",
                tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
        return 1;
 }
@@ -886,7 +874,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
                        mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
        }
 
-       tvaudio_dbg("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+       v4l_dbg(1, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
                 dsr, nsr, necr, mode);
        return mode;
 }
@@ -932,7 +920,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                chip_write(chip, TDA9874A_AOSR, aosr);
                chip_write(chip, TDA9874A_MDACOSR, mdacosr);
 
-               tvaudio_dbg("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+               v4l_dbg(1, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
                        mode, aosr, mdacosr);
 
        } else { /* dic == 0x07 */
@@ -967,7 +955,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                chip_write(chip, TDA9874A_FMMR, fmmr);
                chip_write(chip, TDA9874A_AOSR, aosr);
 
-               tvaudio_dbg("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+               v4l_dbg(1, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
                        mode, fmmr, aosr);
        }
 }
@@ -981,10 +969,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
        if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
                return 0;
 
-       tvaudio_dbg("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+       v4l_dbg(1, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
 
        if((dic == 0x11)||(dic == 0x07)) {
-               tvaudio_info("found tda9874%s.\n", (dic == 0x11) ? "a":"h");
+               v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
                tda9874a_dic = dic;     /* remember device id. */
                return 1;
        }
@@ -1196,7 +1184,7 @@ static int ta8874z_getmode(struct CHIPSTATE *chip)
        }else if (!(val & TA8874Z_B0)){
                mode |= VIDEO_SOUND_STEREO;
        }
-       /* tvaudio_dbg ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
+       /* v4l_dbg(1, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
        return mode;
 }
 
@@ -1209,7 +1197,7 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
 {
        int update = 1;
        audiocmd *t = NULL;
-       tvaudio_dbg("ta8874z_setmode(): mode: 0x%02x\n", mode);
+       v4l_dbg(1, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
 
        switch(mode){
        case VIDEO_SOUND_MONO:
@@ -1490,7 +1478,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
        i2c_set_clientdata(&chip->c, chip);
 
        /* find description for the chip */
-       tvaudio_dbg("chip found @ 0x%x\n", addr<<1);
+       v4l_dbg(1, &chip->c, "chip found @ 0x%x\n", addr<<1);
        for (desc = chiplist; desc->name != NULL; desc++) {
                if (0 == *(desc->insmodopt))
                        continue;
@@ -1502,12 +1490,12 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
                break;
        }
        if (desc->name == NULL) {
-               tvaudio_dbg("no matching chip description found\n");
+               v4l_dbg(1, &chip->c, "no matching chip description found\n");
                return -EIO;
        }
-       tvaudio_info("%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
+       v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
        if (desc->flags) {
-               tvaudio_dbg("matches:%s%s%s.\n",
+               v4l_dbg(1, &chip->c, "matches:%s%s%s.\n",
                        (desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
                        (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
                        (desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
@@ -1550,7 +1538,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
                init_completion(&chip->texit);
                chip->tpid = kernel_thread(chip_thread,(void *)chip,0);
                if (chip->tpid < 0)
-                       tvaudio_warn("%s: kernel_thread() failed\n",
+                       v4l_warn(&chip->c, "%s: kernel_thread() failed\n",
                               chip->c.name);
                wake_up_interruptible(&chip->wq);
        }
@@ -1563,17 +1551,8 @@ static int chip_probe(struct i2c_adapter *adap)
           because dedicated drivers are used */
        if ((adap->id == I2C_HW_SAA7146))
                return 0;
-#ifdef I2C_CLASS_TV_ANALOG
        if (adap->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adap, &addr_data, chip_attach);
-#else
-       switch (adap->id) {
-       case I2C_HW_B_BT848:
-       case I2C_HW_B_RIVA:
-       case I2C_HW_SAA7134:
-               return i2c_probe(adap, &addr_data, chip_attach);
-       }
-#endif
        return 0;
 }
 
@@ -1604,7 +1583,7 @@ static int chip_command(struct i2c_client *client,
        struct CHIPSTATE *chip = i2c_get_clientdata(client);
        struct CHIPDESC  *desc = chiplist + chip->type;
 
-       tvaudio_dbg("%s: chip_command 0x%x\n", chip->c.name, cmd);
+       v4l_dbg(1, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd);
 
        switch (cmd) {
        case AUDC_SET_INPUT:
@@ -1617,7 +1596,7 @@ static int chip_command(struct i2c_client *client,
                break;
 
        case AUDC_SET_RADIO:
-               chip->norm = VIDEO_MODE_RADIO;
+               chip->radio = 1;
                chip->watch_stereo = 0;
                /* del_timer(&chip->wt); */
                break;
@@ -1643,7 +1622,7 @@ static int chip_command(struct i2c_client *client,
                        va->bass   = chip->bass;
                        va->treble = chip->treble;
                }
-               if (chip->norm != VIDEO_MODE_RADIO) {
+               if (!chip->radio) {
                        if (desc->getmode)
                                va->mode = desc->getmode(chip);
                        else
@@ -1678,15 +1657,80 @@ static int chip_command(struct i2c_client *client,
                }
                break;
        }
-       case VIDIOCSCHAN:
+
+       case VIDIOC_S_TUNER:
        {
-               struct video_channel *vc = arg;
+               struct v4l2_tuner *vt = arg;
+               int mode = 0;
 
-               chip->norm = vc->norm;
+               switch (vt->audmode) {
+               case V4L2_TUNER_MODE_MONO:
+                       mode = VIDEO_SOUND_MONO;
+                       break;
+               case V4L2_TUNER_MODE_STEREO:
+                       mode = VIDEO_SOUND_STEREO;
+                       break;
+               case V4L2_TUNER_MODE_LANG1:
+                       mode = VIDEO_SOUND_LANG1;
+                       break;
+               case V4L2_TUNER_MODE_LANG2:
+                       mode = VIDEO_SOUND_LANG2;
+                       break;
+               default:
+                       break;
+               }
+
+               if (desc->setmode && mode) {
+                       chip->watch_stereo = 0;
+                       /* del_timer(&chip->wt); */
+                       chip->mode = mode;
+                       desc->setmode(chip, mode);
+               }
                break;
        }
-       case VIDIOCSFREQ:
+
+       case VIDIOC_G_TUNER:
        {
+               struct v4l2_tuner *vt = arg;
+               int mode = VIDEO_SOUND_MONO;
+
+               if (chip->radio)
+                       break;
+               vt->audmode = 0;
+               vt->rxsubchans = 0;
+               vt->capability = V4L2_TUNER_CAP_STEREO |
+                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+
+               if (desc->getmode)
+                       mode = desc->getmode(chip);
+
+               if (mode & VIDEO_SOUND_MONO)
+                       vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
+               if (mode & VIDEO_SOUND_STEREO)
+                       vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+               if (mode & VIDEO_SOUND_LANG1)
+                       vt->rxsubchans |= V4L2_TUNER_SUB_LANG1 |
+                                         V4L2_TUNER_SUB_LANG2;
+
+               mode = chip->mode;
+               if (mode & VIDEO_SOUND_MONO)
+                       vt->audmode = V4L2_TUNER_MODE_MONO;
+               if (mode & VIDEO_SOUND_STEREO)
+                       vt->audmode = V4L2_TUNER_MODE_STEREO;
+               if (mode & VIDEO_SOUND_LANG1)
+                       vt->audmode = V4L2_TUNER_MODE_LANG1;
+               if (mode & VIDEO_SOUND_LANG2)
+                       vt->audmode = V4L2_TUNER_MODE_LANG2;
+               break;
+       }
+
+       case VIDIOCSCHAN:
+       case VIDIOC_S_STD:
+               chip->radio = 0;
+               break;
+
+       case VIDIOCSFREQ:
+       case VIDIOC_S_FREQUENCY:
                chip->mode = 0; /* automatic */
                if (desc->checkmode) {
                        desc->setmode(chip,VIDEO_SOUND_MONO);
@@ -1695,15 +1739,14 @@ static int chip_command(struct i2c_client *client,
                        mod_timer(&chip->wt, jiffies+2*HZ);
                        /* the thread will call checkmode() later */
                }
-       }
+               break;
        }
        return 0;
 }
 
-
 static struct i2c_driver driver = {
        .driver = {
-               .name    = "generic i2c audio driver",
+               .name    = "tvaudio",
        },
        .id              = I2C_DRIVERID_TVAUDIO,
        .attach_adapter  = chip_probe,
index 8ac4cb82a45949841d0383e0c3c2178139ab0d38..fd0acc5da66771e5c5af5aa73bff79537ea3ea30 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <media/tuner.h>
 #include <media/tveeprom.h>
+#include <media/v4l2-common.h>
 #include <media/audiochip.h>
 
 MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
@@ -52,21 +53,19 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 #define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
 
-#define tveeprom_info(fmt, arg...) do {\
-       printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
-                       c->adapter->nr, c->addr , ##arg); } while (0)
-#define tveeprom_warn(fmt, arg...) do {\
-       printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \
-                       c->adapter->nr, c->addr , ##arg); } while (0)
-#define tveeprom_dbg(fmt, arg...) do {\
+#define tveeprom_info(fmt, arg...) \
+       v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+#define tveeprom_warn(fmt, arg...) \
+       v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+#define tveeprom_dbg(fmt, arg...) do { \
        if (debug) \
-               printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
-                       c->adapter->nr, c->addr , ##arg); } while (0)
-
-
-/* ----------------------------------------------------------------------- */
-/* some hauppauge specific stuff                                           */
+               v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \
+       } while (0)
 
+/*
+ * The Hauppauge eeprom uses an 8bit field to determine which
+ * tuner formats the tuner supports.
+ */
 static struct HAUPPAUGE_TUNER_FMT
 {
        int     id;
@@ -74,14 +73,14 @@ static struct HAUPPAUGE_TUNER_FMT
 }
 hauppauge_tuner_fmt[] =
 {
-       { 0x00000000, " unknown1" },
-       { 0x00000000, " unknown2" },
-       { 0x00000007, " PAL(B/G)" },
-       { 0x00001000, " NTSC(M)" },
-       { 0x00000010, " PAL(I)" },
-       { 0x00400000, " SECAM(L/L')" },
-       { 0x00000e00, " PAL(D/K)" },
-       { 0x03000000, " ATSC/DVB Digital" },
+       { V4L2_STD_UNKNOWN," UNKNOWN" },
+       { V4L2_STD_UNKNOWN," FM" },
+       { V4L2_STD_PAL_BG, " PAL(B/G)" },
+       { V4L2_STD_NTSC_M, " NTSC(M)" },
+       { V4L2_STD_PAL_I,  " PAL(I)" },
+       { V4L2_STD_SECAM_L," SECAM(L/L')" },
+       { V4L2_STD_PAL_DK, " PAL(D/D1/K)" },
+       { V4L2_STD_ATSC,   " ATSC/DVB Digital" },
 };
 
 /* This is the full list of possible tuners. Many thanks to Hauppauge for
@@ -387,7 +386,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
        if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) &&
                        (eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95))
                start=0xa0; /* Generic em28xx offset */
-       else if (((eeprom_data[0] & 0xf0) == 0x10) &&
+       else if (((eeprom_data[0] & 0xe1) == 0x01) &&
                                        (eeprom_data[1] == 0x00) &&
                                        (eeprom_data[2] == 0x00) &&
                                        (eeprom_data[8] == 0x84))
index e837f9f7fed6924aae480db9e3b4458828cdaa1c..9e86caeb96a7b530da89b05e18a0cb44d53d7865 100644 (file)
@@ -227,13 +227,9 @@ static int tvmixer_release(struct inode *inode, struct file *file)
 }
 
 static struct i2c_driver driver = {
-#ifdef I2C_PEC
        .driver = {
-               .name    = "tv card mixer driver",
+               .name    = "tvmixer",
        },
-#else
-       .name            = "tv card mixer driver",
-#endif
        .id              = I2C_DRIVERID_TVMIXER,
        .detach_adapter  = tvmixer_adapters,
        .attach_adapter  = tvmixer_adapters,
@@ -267,22 +263,8 @@ static int tvmixer_clients(struct i2c_client *client)
        struct video_audio va;
        int i,minor;
 
-#ifdef I2C_CLASS_TV_ANALOG
        if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
                return -1;
-#else
-       /* TV card ??? */
-       switch (client->adapter->id) {
-       case I2C_HW_SMBUS_VOODOO3:
-       case I2C_HW_B_BT848:
-       case I2C_HW_B_RIVA:
-               /* ok, have a look ... */
-               break;
-       default:
-               /* ignore that one */
-               return -1;
-       }
-#endif
 
        /* unregister ?? */
        for (i = 0; i < DEV_MAX; i++) {
index a60442ea4f94274d26995c29f492ea90b2c644e8..c35b8042eee58dd84bd7080a28801762bb36c4c9 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/videodev.h>
 #include <linux/delay.h>
 #include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
 
 #include "tvp5150_reg.h"
 
@@ -28,33 +29,38 @@ static int debug = 0;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
+#define tvp5150_info(fmt, arg...) do { \
+       printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \
+              i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
+#define tvp5150_dbg(num, fmt, arg...) \
        do { \
                if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
+                       printk(KERN_DEBUG "%s debug %d-%04x: " fmt,\
+                               c->driver->driver.name, \
+                               i2c_adapter_id(c->adapter), \
+                               c->addr , ## arg); } while (0)
 
 /* supported controls */
 static struct v4l2_queryctrl tvp5150_qctrl[] = {
        {
-        .id = V4L2_CID_BRIGHTNESS,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "Brightness",
-        .minimum = 0,
-        .maximum = 255,
-        .step = 1,
-        .default_value = 0,
-        .flags = 0,
-        }, {
-            .id = V4L2_CID_CONTRAST,
-            .type = V4L2_CTRL_TYPE_INTEGER,
-            .name = "Contrast",
-            .minimum = 0,
-            .maximum = 255,
-            .step = 0x1,
-            .default_value = 0x10,
-            .flags = 0,
-            }, {
+               .id = V4L2_CID_BRIGHTNESS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step = 1,
+               .default_value = 0,
+               .flags = 0,
+       }, {
+               .id = V4L2_CID_CONTRAST,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Contrast",
+               .minimum = 0,
+               .maximum = 255,
+               .step = 0x1,
+               .default_value = 0x10,
+               .flags = 0,
+       }, {
                 .id = V4L2_CID_SATURATION,
                 .type = V4L2_CTRL_TYPE_INTEGER,
                 .name = "Saturation",
@@ -63,16 +69,16 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = {
                 .step = 0x1,
                 .default_value = 0x10,
                 .flags = 0,
-                }, {
-                    .id = V4L2_CID_HUE,
-                    .type = V4L2_CTRL_TYPE_INTEGER,
-                    .name = "Hue",
-                    .minimum = -128,
-                    .maximum = 127,
-                    .step = 0x1,
-                    .default_value = 0x10,
-                    .flags = 0,
-                    }
+       }, {
+               .id = V4L2_CID_HUE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Hue",
+               .minimum = -128,
+               .maximum = 127,
+               .step = 0x1,
+               .default_value = 0x10,
+               .flags = 0,
+       }
 };
 
 struct tvp5150 {
@@ -94,12 +100,14 @@ static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
 
        buffer[0] = addr;
        if (1 != (rc = i2c_master_send(c, buffer, 1)))
-               dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+               tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
 
        msleep(10);
 
        if (1 != (rc = i2c_master_recv(c, buffer, 1)))
-               dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+               tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+       tvp5150_dbg(2, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
 
        return (buffer[0]);
 }
@@ -109,13 +117,12 @@ static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
 {
        unsigned char buffer[2];
        int rc;
-/*     struct tvp5150 *core = i2c_get_clientdata(c); */
 
        buffer[0] = addr;
        buffer[1] = value;
-       dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+       tvp5150_dbg(2, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
        if (2 != (rc = i2c_master_send(c, buffer, 2)))
-               dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+               tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
 }
 
 static void dump_reg(struct i2c_client *c)
@@ -437,48 +444,346 @@ enum tvp5150_input {
 static inline void tvp5150_selmux(struct i2c_client *c,
                                  enum tvp5150_input input)
 {
+       int opmode=0;
+
        struct tvp5150 *decoder = i2c_get_clientdata(c);
 
        if (!decoder->enable)
                input |= TVP5150_BLACK_SCREEN;
 
+       switch (input) {
+       case TVP5150_ANALOG_CH0:
+       case TVP5150_ANALOG_CH1:
+               opmode=0x30;            /* TV Mode */
+               break;
+       default:
+               opmode=0;               /* Auto Mode */
+               break;
+       }
+
+       tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
        tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
 };
 
-static inline void tvp5150_reset(struct i2c_client *c)
+struct i2c_reg_value {
+       unsigned char reg;
+       unsigned char value;
+};
+
+/* Default values as sugested at TVP5150AM1 datasheet */
+static const struct i2c_reg_value tvp5150_init_default[] = {
+       { /* 0x00 */
+               TVP5150_VD_IN_SRC_SEL_1,0x00
+       },
+       { /* 0x01 */
+               TVP5150_ANAL_CHL_CTL,0x15
+       },
+       { /* 0x02 */
+               TVP5150_OP_MODE_CTL,0x00
+       },
+       { /* 0x03 */
+               TVP5150_MISC_CTL,0x01
+       },
+       { /* 0x06 */
+               TVP5150_COLOR_KIL_THSH_CTL,0x10
+       },
+       { /* 0x07 */
+               TVP5150_LUMA_PROC_CTL_1,0x60
+       },
+       { /* 0x08 */
+               TVP5150_LUMA_PROC_CTL_2,0x00
+       },
+       { /* 0x09 */
+               TVP5150_BRIGHT_CTL,0x80
+       },
+       { /* 0x0a */
+               TVP5150_SATURATION_CTL,0x80
+       },
+       { /* 0x0b */
+               TVP5150_HUE_CTL,0x00
+       },
+       { /* 0x0c */
+               TVP5150_CONTRAST_CTL,0x80
+       },
+       { /* 0x0d */
+               TVP5150_DATA_RATE_SEL,0x47
+       },
+       { /* 0x0e */
+               TVP5150_LUMA_PROC_CTL_3,0x00
+       },
+       { /* 0x0f */
+               TVP5150_CONF_SHARED_PIN,0x08
+       },
+       { /* 0x11 */
+               TVP5150_ACT_VD_CROP_ST_MSB,0x00
+       },
+       { /* 0x12 */
+               TVP5150_ACT_VD_CROP_ST_LSB,0x00
+       },
+       { /* 0x13 */
+               TVP5150_ACT_VD_CROP_STP_MSB,0x00
+       },
+       { /* 0x14 */
+               TVP5150_ACT_VD_CROP_STP_LSB,0x00
+       },
+       { /* 0x15 */
+               TVP5150_GENLOCK,0x01
+       },
+       { /* 0x16 */
+               TVP5150_HORIZ_SYNC_START,0x80
+       },
+       { /* 0x18 */
+               TVP5150_VERT_BLANKING_START,0x00
+       },
+       { /* 0x19 */
+               TVP5150_VERT_BLANKING_STOP,0x00
+       },
+       { /* 0x1a */
+               TVP5150_CHROMA_PROC_CTL_1,0x0c
+       },
+       { /* 0x1b */
+               TVP5150_CHROMA_PROC_CTL_2,0x14
+       },
+       { /* 0x1c */
+               TVP5150_INT_RESET_REG_B,0x00
+       },
+       { /* 0x1d */
+               TVP5150_INT_ENABLE_REG_B,0x00
+       },
+       { /* 0x1e */
+               TVP5150_INTT_CONFIG_REG_B,0x00
+       },
+       { /* 0x28 */
+               TVP5150_VIDEO_STD,0x00
+       },
+       { /* 0x2e */
+               TVP5150_MACROVISION_ON_CTR,0x0f
+       },
+       { /* 0x2f */
+               TVP5150_MACROVISION_OFF_CTR,0x01
+       },
+       { /* 0xbb */
+               TVP5150_TELETEXT_FIL_ENA,0x00
+       },
+       { /* 0xc0 */
+               TVP5150_INT_STATUS_REG_A,0x00
+       },
+       { /* 0xc1 */
+               TVP5150_INT_ENABLE_REG_A,0x00
+       },
+       { /* 0xc2 */
+               TVP5150_INT_CONF,0x04
+       },
+       { /* 0xc8 */
+               TVP5150_FIFO_INT_THRESHOLD,0x80
+       },
+       { /* 0xc9 */
+               TVP5150_FIFO_RESET,0x00
+       },
+       { /* 0xca */
+               TVP5150_LINE_NUMBER_INT,0x00
+       },
+       { /* 0xcb */
+               TVP5150_PIX_ALIGN_REG_LOW,0x4e
+       },
+       { /* 0xcc */
+               TVP5150_PIX_ALIGN_REG_HIGH,0x00
+       },
+       { /* 0xcd */
+               TVP5150_FIFO_OUT_CTRL,0x01
+       },
+       { /* 0xcf */
+               TVP5150_FULL_FIELD_ENA_1,0x00
+       },
+       { /* 0xd0 */
+               TVP5150_FULL_FIELD_ENA_2,0x00
+       },
+       { /* 0xfc */
+               TVP5150_FULL_FIELD_MODE_REG,0x7f
+       },
+       { /* end of data */
+               0xff,0xff
+       }
+};
+
+/* Default values as sugested at TVP5150AM1 datasheet */
+static const struct i2c_reg_value tvp5150_init_enable[] = {
+       {
+               TVP5150_CONF_SHARED_PIN, 2
+       },{     /* Automatic offset and AGC enabled */
+               TVP5150_ANAL_CHL_CTL, 0x15
+       },{     /* Activate YCrCb output 0x9 or 0xd ? */
+               TVP5150_MISC_CTL, 0x6f
+       },{     /* Activates video std autodetection for all standards */
+               TVP5150_AUTOSW_MSK, 0x0
+       },{     /* Default format: 0x47. For 4:2:2: 0x40 */
+               TVP5150_DATA_RATE_SEL, 0x47
+       },{
+               TVP5150_CHROMA_PROC_CTL_1, 0x0c
+       },{
+               TVP5150_CHROMA_PROC_CTL_2, 0x54
+       },{     /* Non documented, but initialized on WinTV USB2 */
+               0x27, 0x20
+       },{
+               0xff,0xff
+       }
+};
+
+struct i2c_vbi_ram_value {
+       u16 reg;
+       unsigned char values[26];
+};
+
+struct i2c_vbi_ram_value vbi_ram_default[] =
 {
-       struct tvp5150 *decoder = i2c_get_clientdata(c);
+       {0x010, /* WST SECAM 6 */
+               { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       },
+       {0x030, /* WST PAL B 6 */
+               { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       },
+       {0x050, /* WST PAL C 6 */
+               { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       },
+       {0x070, /* WST NTSC 6 */
+               { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       },
+       {0x090, /* NABTS, NTSC 6 */
+               { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x15, 0x0 }
+       },
+       {0x0b0, /* NABTS, NTSC-J 6 */
+               { 0xaa, 0xaa, 0xff, 0xff , 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       },
+       {0x0d0, /* CC, PAL/SECAM 6 */
+               { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+       },
+       {0x0f0, /* CC, NTSC 6 */
+               { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+       },
+       {0x110, /* WSS, PAL/SECAM 6 */
+               { 0x5b, 0x55, 0xc5, 0xff , 0x0, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x0, 0x0, 0x0, 0x3a, 0x0 }
+       },
+       {0x130, /* WSS, NTSC C */
+               { 0x38, 0x00, 0x3f, 0x00 , 0x0, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x0, 0x0, 0x0, 0x39, 0x0 }
+       },
+       {0x150, /* VITC, PAL/SECAM 6 */
+               { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+       },
+       {0x170, /* VITC, NTSC 6 */
+               { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+       },
+       { (u16)-1 }
+};
 
-       tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2);
+static int tvp5150_write_inittab(struct i2c_client *c,
+                                const struct i2c_reg_value *regs)
+{
+       while (regs->reg != 0xff) {
+               tvp5150_write(c, regs->reg, regs->value);
+               regs++;
+       }
+       return 0;
+}
 
-       /* Automatic offset and AGC enabled */
-       tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15);
+static int tvp5150_vdp_init(struct i2c_client *c,
+                                const struct i2c_vbi_ram_value *regs)
+{
+       unsigned int i;
 
-       /* Normal Operation */
-//      tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00);
+       /* Disable Full Field */
+       tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0);
 
-       /* Activate YCrCb output 0x9 or 0xd ? */
-       tvp5150_write(c, TVP5150_MISC_CTL, 0x6f);
+       /* Before programming, Line mode should be at 0xff */
+       for (i=TVP5150_FULL_FIELD_ENA_2; i<=TVP5150_LINE_MODE_REG_44; i++)
+               tvp5150_write(c, i, 0xff);
 
-       /* Activates video std autodetection for all standards */
-       tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0);
+       /* Load Ram Table */
+       while (regs->reg != (u16)-1 ) {
+               tvp5150_write(c, TVP5150_CONF_RAM_ADDR_HIGH,regs->reg>>8);
+               tvp5150_write(c, TVP5150_CONF_RAM_ADDR_LOW,regs->reg);
 
-       /* Default format: 0x47, 4:2:2: 0x40 */
-       tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47);
+               for (i=0;i<16;i++)
+                       tvp5150_write(c, TVP5150_VDP_CONF_RAM_DATA,regs->values[i]);
 
-       tvp5150_selmux(c, decoder->input);
+               regs++;
+       }
+       return 0;
+}
+
+static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std)
+{
+       struct tvp5150 *decoder = i2c_get_clientdata(c);
+       int fmt=0;
+
+       decoder->norm=std;
+
+       /* First tests should be against specific std */
+
+       if (std == V4L2_STD_ALL) {
+               fmt=0;  /* Autodetect mode */
+       } else if (std & V4L2_STD_NTSC_443) {
+               fmt=0xa;
+       } else if (std & V4L2_STD_PAL_M) {
+               fmt=0x6;
+       } else if (std & (V4L2_STD_PAL_N| V4L2_STD_PAL_Nc)) {
+               fmt=0x8;
+       } else {
+               /* Then, test against generic ones */
+               if (std & V4L2_STD_NTSC) {
+                       fmt=0x2;
+               } else if (std & V4L2_STD_PAL) {
+                       fmt=0x4;
+               } else if (std & V4L2_STD_SECAM) {
+                       fmt=0xc;
+               }
+       }
+
+       tvp5150_dbg(1,"Set video std register to %d.\n",fmt);
+       tvp5150_write(c, TVP5150_VIDEO_STD, fmt);
 
-       tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c);
-       tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54);
+       return 0;
+}
 
-       tvp5150_write(c, 0x27, 0x20);   /* ?????????? */
+static inline void tvp5150_reset(struct i2c_client *c)
+{
+       u8 type, ver_656, msb_id, lsb_id, msb_rom, lsb_rom;
+       struct tvp5150 *decoder = i2c_get_clientdata(c);
 
-       tvp5150_write(c, TVP5150_VIDEO_STD, 0x0);       /* Auto switch */
+       type=tvp5150_read(c,TVP5150_AUTOSW_MSK);
+       msb_id=tvp5150_read(c,TVP5150_MSB_DEV_ID);
+       lsb_id=tvp5150_read(c,TVP5150_LSB_DEV_ID);
+       msb_rom=tvp5150_read(c,TVP5150_ROM_MAJOR_VER);
+       lsb_rom=tvp5150_read(c,TVP5150_ROM_MINOR_VER);
+
+       if (type==0xdc) {
+               ver_656=tvp5150_read(c,TVP5150_REV_SELECT);
+               tvp5150_info("tvp%02x%02xam1 detected 656 version is %d.\n",msb_id, lsb_id,ver_656);
+       } else if (type==0xfc) {
+               tvp5150_info("tvp%02x%02xa detected.\n",msb_id, lsb_id);
+       } else {
+               tvp5150_info("unknown tvp%02x%02x chip detected(%d).\n",msb_id,lsb_id,type);
+       }
+       tvp5150_info("Rom ver is %d.%d\n",msb_rom,lsb_rom);
 
+       /* Initializes TVP5150 to its default values */
+       tvp5150_write_inittab(c, tvp5150_init_default);
+
+       /* Initializes VDP registers */
+       tvp5150_vdp_init(c, vbi_ram_default);
+
+       /* Selects decoder input */
+       tvp5150_selmux(c, decoder->input);
+
+       /* Initializes TVP5150 to stream enabled values */
+       tvp5150_write_inittab(c, tvp5150_init_enable);
+
+       /* Initialize image preferences */
        tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
        tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
        tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
        tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
+
+       tvp5150_set_std(c, decoder->norm);
 };
 
 static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
@@ -498,9 +803,8 @@ static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
        case V4L2_CID_HUE:
                ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
                return 0;
-       default:
-               return -EINVAL;
        }
+       return -EINVAL;
 }
 
 static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
@@ -520,28 +824,59 @@ static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
        case V4L2_CID_HUE:
                tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
                return 0;
-       default:
-               return -EINVAL;
        }
+       return -EINVAL;
 }
 
 /****************************************************************************
                        I2C Command
  ****************************************************************************/
-static int tvp5150_command(struct i2c_client *client,
+static int tvp5150_command(struct i2c_client *c,
                           unsigned int cmd, void *arg)
 {
-       struct tvp5150 *decoder = i2c_get_clientdata(client);
+       struct tvp5150 *decoder = i2c_get_clientdata(c);
 
        switch (cmd) {
 
        case 0:
+       case VIDIOC_INT_RESET:
        case DECODER_INIT:
-               tvp5150_reset(client);
+               tvp5150_reset(c);
+               break;
+       case VIDIOC_S_STD:
+               if (decoder->norm == *(v4l2_std_id *)arg)
+                       break;
+               return tvp5150_set_std(c, *(v4l2_std_id *)arg);
+       case VIDIOC_G_STD:
+               *(v4l2_std_id *)arg = decoder->norm;
+               break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_INT_G_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+
+               if (reg->i2c_id != I2C_DRIVERID_TVP5150)
+                       return -EINVAL;
+               reg->val = tvp5150_read(c, reg->reg & 0xff);
+               break;
+       }
+
+       case VIDIOC_INT_S_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+
+               if (reg->i2c_id != I2C_DRIVERID_TVP5150)
+                       return -EINVAL;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
                break;
+       }
+#endif
 
        case DECODER_DUMP:
-               dump_reg(client);
+               dump_reg(c);
                break;
 
        case DECODER_GET_CAPABILITIES:
@@ -600,7 +935,7 @@ static int tvp5150_command(struct i2c_client *client,
                        }
 
                        decoder->input = *iarg;
-                       tvp5150_selmux(client, decoder->input);
+                       tvp5150_selmux(c, decoder->input);
 
                        break;
                }
@@ -620,19 +955,18 @@ static int tvp5150_command(struct i2c_client *client,
 
                        decoder->enable = (*iarg != 0);
 
-                       tvp5150_selmux(client, decoder->input);
+                       tvp5150_selmux(c, decoder->input);
 
                        break;
                }
        case VIDIOC_QUERYCTRL:
                {
                        struct v4l2_queryctrl *qc = arg;
-                       u8 i, n;
+                       int i;
 
-                       dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");
+                       tvp5150_dbg(1, "VIDIOC_QUERYCTRL called\n");
 
-                       n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
-                       for (i = 0; i < n; i++)
+                       for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
                                if (qc->id && qc->id == tvp5150_qctrl[i].id) {
                                        memcpy(qc, &(tvp5150_qctrl[i]),
                                               sizeof(*qc));
@@ -644,16 +978,14 @@ static int tvp5150_command(struct i2c_client *client,
        case VIDIOC_G_CTRL:
                {
                        struct v4l2_control *ctrl = arg;
-                       dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL");
+                       tvp5150_dbg(1, "VIDIOC_G_CTRL called\n");
 
-                       return tvp5150_get_ctrl(client, ctrl);
+                       return tvp5150_get_ctrl(c, ctrl);
                }
-       case VIDIOC_S_CTRL_OLD: /* ??? */
        case VIDIOC_S_CTRL:
                {
                        struct v4l2_control *ctrl = arg;
                        u8 i, n;
-                       dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL");
                        n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
                        for (i = 0; i < n; i++)
                                if (ctrl->id == tvp5150_qctrl[i].id) {
@@ -662,11 +994,10 @@ static int tvp5150_command(struct i2c_client *client,
                                            || ctrl->value >
                                            tvp5150_qctrl[i].maximum)
                                                return -ERANGE;
-                                       dprintk(1,
-                                               KERN_DEBUG
-                                               "VIDIOC_S_CTRL: id=%d, value=%d",
+                                       tvp5150_dbg(1,
+                                               "VIDIOC_S_CTRL: id=%d, value=%d\n",
                                                ctrl->id, ctrl->value);
-                                       return tvp5150_set_ctrl(client, ctrl);
+                                       return tvp5150_set_ctrl(c, ctrl);
                                }
                        return -EINVAL;
                }
@@ -677,25 +1008,25 @@ static int tvp5150_command(struct i2c_client *client,
                        if (decoder->bright != pic->brightness) {
                                /* We want 0 to 255 we get 0-65535 */
                                decoder->bright = pic->brightness;
-                               tvp5150_write(client, TVP5150_BRIGHT_CTL,
+                               tvp5150_write(c, TVP5150_BRIGHT_CTL,
                                              decoder->bright >> 8);
                        }
                        if (decoder->contrast != pic->contrast) {
                                /* We want 0 to 255 we get 0-65535 */
                                decoder->contrast = pic->contrast;
-                               tvp5150_write(client, TVP5150_CONTRAST_CTL,
+                               tvp5150_write(c, TVP5150_CONTRAST_CTL,
                                              decoder->contrast >> 8);
                        }
                        if (decoder->sat != pic->colour) {
                                /* We want 0 to 255 we get 0-65535 */
                                decoder->sat = pic->colour;
-                               tvp5150_write(client, TVP5150_SATURATION_CTL,
+                               tvp5150_write(c, TVP5150_SATURATION_CTL,
                                              decoder->contrast >> 8);
                        }
                        if (decoder->hue != pic->hue) {
                                /* We want -128 to 127 we get 0-65535 */
                                decoder->hue = pic->hue;
-                               tvp5150_write(client, TVP5150_HUE_CTL,
+                               tvp5150_write(c, TVP5150_HUE_CTL,
                                              (decoder->hue - 32768) >> 8);
                        }
                        break;
@@ -720,12 +1051,12 @@ static struct i2c_client client_template = {
 static int tvp5150_detect_client(struct i2c_adapter *adapter,
                                 int address, int kind)
 {
-       struct i2c_client *client;
+       struct i2c_client *c;
        struct tvp5150 *core;
        int rv;
 
-       dprintk(1,
-               KERN_INFO
+       if (debug)
+               printk( KERN_INFO
                "tvp5150.c: detecting tvp5150 client on address 0x%x\n",
                address << 1);
 
@@ -738,22 +1069,22 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
             I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
                return 0;
 
-       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
+       c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (c == 0)
                return -ENOMEM;
-       memcpy(client, &client_template, sizeof(struct i2c_client));
+       memcpy(c, &client_template, sizeof(struct i2c_client));
 
        core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL);
        if (core == 0) {
-               kfree(client);
+               kfree(c);
                return -ENOMEM;
        }
        memset(core, 0, sizeof(struct tvp5150));
-       i2c_set_clientdata(client, core);
+       i2c_set_clientdata(c, core);
 
-       rv = i2c_attach_client(client);
+       rv = i2c_attach_client(c);
 
-       core->norm = VIDEO_MODE_AUTO;
+       core->norm = V4L2_STD_ALL;
        core->input = 2;
        core->enable = 1;
        core->bright = 32768;
@@ -762,37 +1093,41 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
        core->sat = 32768;
 
        if (rv) {
-               kfree(client);
+               kfree(c);
                kfree(core);
                return rv;
        }
 
        if (debug > 1)
-               dump_reg(client);
+               dump_reg(c);
        return 0;
 }
 
 static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
 {
-       dprintk(1,
-               KERN_INFO
+       if (debug)
+               printk( KERN_INFO
                "tvp5150.c: starting probe for adapter %s (0x%x)\n",
                adapter->name, adapter->id);
        return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
 }
 
-static int tvp5150_detach_client(struct i2c_client *client)
+static int tvp5150_detach_client(struct i2c_client *c)
 {
-       struct tvp5150 *decoder = i2c_get_clientdata(client);
+       struct tvp5150 *decoder = i2c_get_clientdata(c);
        int err;
 
-       err = i2c_detach_client(client);
+       tvp5150_dbg(1,
+               "tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
+               c->addr << 1);
+
+       err = i2c_detach_client(c);
        if (err) {
                return err;
        }
 
        kfree(decoder);
-       kfree(client);
+       kfree(c);
 
        return 0;
 }
@@ -803,9 +1138,7 @@ static struct i2c_driver driver = {
        .driver = {
                .name = "tvp5150",
        },
-
-       /* FIXME */
-       .id = I2C_DRIVERID_SAA7110,
+       .id = I2C_DRIVERID_TVP5150,
 
        .attach_adapter = tvp5150_attach_adapter,
        .detach_client = tvp5150_detach_client,
index 4134549d11a81c67f6d3156769a5da1201605b62..2ab5b4093800bc789c992e067e8bc21b9e54f442 100644 (file)
@@ -951,6 +951,10 @@ v4l_compat_translate_ioctl(struct inode         *inode,
                        dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
                        break;
                }
+               if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
+                       err = -EINVAL;
+                       break;
+               }
                memset(fmt, 0, sizeof(*fmt));
                fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
                fmt->sampling_rate    = fmt2->fmt.vbi.sampling_rate;
@@ -966,6 +970,11 @@ v4l_compat_translate_ioctl(struct inode         *inode,
        {
                struct vbi_format      *fmt = arg;
 
+               if (VIDEO_PALETTE_RAW != fmt->sample_format) {
+                       err = -EINVAL;
+                       break;
+               }
+
                fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
                memset(fmt2, 0, sizeof(*fmt2));
 
@@ -986,7 +995,7 @@ v4l_compat_translate_ioctl(struct inode         *inode,
 
                if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
                    fmt2->fmt.vbi.sampling_rate    != fmt->sampling_rate    ||
-                   VIDEO_PALETTE_RAW              != fmt->sample_format    ||
+                   fmt2->fmt.vbi.sample_format    != V4L2_PIX_FMT_GREY     ||
                    fmt2->fmt.vbi.start[0]         != fmt->start[0]         ||
                    fmt2->fmt.vbi.count[0]         != fmt->count[0]         ||
                    fmt2->fmt.vbi.start[1]         != fmt->start[1]         ||
index 597b8db35a135c935b07e19d5ba08d816ec91946..5dbd7c1b362a2d7f88e21fd914e8b639dae3a5be 100644 (file)
@@ -58,6 +58,8 @@
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/div64.h>
+#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -190,57 +192,174 @@ char *v4l2_type_names[] = {
        [V4L2_BUF_TYPE_VBI_OUTPUT]    = "vbi-out",
 };
 
-char *v4l2_ioctl_names[256] = {
-#if __GNUC__ >= 3
-       [0 ... 255]                      = "UNKNOWN",
+/* ------------------------------------------------------------------ */
+/* debug help functions                                               */
+
+#ifdef HAVE_V4L1
+static const char *v4l1_ioctls[] = {
+       [_IOC_NR(VIDIOCGCAP)]       = "VIDIOCGCAP",
+       [_IOC_NR(VIDIOCGCHAN)]      = "VIDIOCGCHAN",
+       [_IOC_NR(VIDIOCSCHAN)]      = "VIDIOCSCHAN",
+       [_IOC_NR(VIDIOCGTUNER)]     = "VIDIOCGTUNER",
+       [_IOC_NR(VIDIOCSTUNER)]     = "VIDIOCSTUNER",
+       [_IOC_NR(VIDIOCGPICT)]      = "VIDIOCGPICT",
+       [_IOC_NR(VIDIOCSPICT)]      = "VIDIOCSPICT",
+       [_IOC_NR(VIDIOCCAPTURE)]    = "VIDIOCCAPTURE",
+       [_IOC_NR(VIDIOCGWIN)]       = "VIDIOCGWIN",
+       [_IOC_NR(VIDIOCSWIN)]       = "VIDIOCSWIN",
+       [_IOC_NR(VIDIOCGFBUF)]      = "VIDIOCGFBUF",
+       [_IOC_NR(VIDIOCSFBUF)]      = "VIDIOCSFBUF",
+       [_IOC_NR(VIDIOCKEY)]        = "VIDIOCKEY",
+       [_IOC_NR(VIDIOCGFREQ)]      = "VIDIOCGFREQ",
+       [_IOC_NR(VIDIOCSFREQ)]      = "VIDIOCSFREQ",
+       [_IOC_NR(VIDIOCGAUDIO)]     = "VIDIOCGAUDIO",
+       [_IOC_NR(VIDIOCSAUDIO)]     = "VIDIOCSAUDIO",
+       [_IOC_NR(VIDIOCSYNC)]       = "VIDIOCSYNC",
+       [_IOC_NR(VIDIOCMCAPTURE)]   = "VIDIOCMCAPTURE",
+       [_IOC_NR(VIDIOCGMBUF)]      = "VIDIOCGMBUF",
+       [_IOC_NR(VIDIOCGUNIT)]      = "VIDIOCGUNIT",
+       [_IOC_NR(VIDIOCGCAPTURE)]   = "VIDIOCGCAPTURE",
+       [_IOC_NR(VIDIOCSCAPTURE)]   = "VIDIOCSCAPTURE",
+       [_IOC_NR(VIDIOCSPLAYMODE)]  = "VIDIOCSPLAYMODE",
+       [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
+       [_IOC_NR(VIDIOCGPLAYINFO)]  = "VIDIOCGPLAYINFO",
+       [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
+       [_IOC_NR(VIDIOCGVBIFMT)]    = "VIDIOCGVBIFMT",
+       [_IOC_NR(VIDIOCSVBIFMT)]    = "VIDIOCSVBIFMT"
+};
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+#endif
+
+static const char *v4l2_ioctls[] = {
+       [_IOC_NR(VIDIOC_QUERYCAP)]         = "VIDIOC_QUERYCAP",
+       [_IOC_NR(VIDIOC_RESERVED)]         = "VIDIOC_RESERVED",
+       [_IOC_NR(VIDIOC_ENUM_FMT)]         = "VIDIOC_ENUM_FMT",
+       [_IOC_NR(VIDIOC_G_FMT)]            = "VIDIOC_G_FMT",
+       [_IOC_NR(VIDIOC_S_FMT)]            = "VIDIOC_S_FMT",
+       [_IOC_NR(VIDIOC_G_MPEGCOMP)]       = "VIDIOC_G_MPEGCOMP",
+       [_IOC_NR(VIDIOC_S_MPEGCOMP)]       = "VIDIOC_S_MPEGCOMP",
+       [_IOC_NR(VIDIOC_REQBUFS)]          = "VIDIOC_REQBUFS",
+       [_IOC_NR(VIDIOC_QUERYBUF)]         = "VIDIOC_QUERYBUF",
+       [_IOC_NR(VIDIOC_G_FBUF)]           = "VIDIOC_G_FBUF",
+       [_IOC_NR(VIDIOC_S_FBUF)]           = "VIDIOC_S_FBUF",
+       [_IOC_NR(VIDIOC_OVERLAY)]          = "VIDIOC_OVERLAY",
+       [_IOC_NR(VIDIOC_QBUF)]             = "VIDIOC_QBUF",
+       [_IOC_NR(VIDIOC_DQBUF)]            = "VIDIOC_DQBUF",
+       [_IOC_NR(VIDIOC_STREAMON)]         = "VIDIOC_STREAMON",
+       [_IOC_NR(VIDIOC_STREAMOFF)]        = "VIDIOC_STREAMOFF",
+       [_IOC_NR(VIDIOC_G_PARM)]           = "VIDIOC_G_PARM",
+       [_IOC_NR(VIDIOC_S_PARM)]           = "VIDIOC_S_PARM",
+       [_IOC_NR(VIDIOC_G_STD)]            = "VIDIOC_G_STD",
+       [_IOC_NR(VIDIOC_S_STD)]            = "VIDIOC_S_STD",
+       [_IOC_NR(VIDIOC_ENUMSTD)]          = "VIDIOC_ENUMSTD",
+       [_IOC_NR(VIDIOC_ENUMINPUT)]        = "VIDIOC_ENUMINPUT",
+       [_IOC_NR(VIDIOC_G_CTRL)]           = "VIDIOC_G_CTRL",
+       [_IOC_NR(VIDIOC_S_CTRL)]           = "VIDIOC_S_CTRL",
+       [_IOC_NR(VIDIOC_G_TUNER)]          = "VIDIOC_G_TUNER",
+       [_IOC_NR(VIDIOC_S_TUNER)]          = "VIDIOC_S_TUNER",
+       [_IOC_NR(VIDIOC_G_AUDIO)]          = "VIDIOC_G_AUDIO",
+       [_IOC_NR(VIDIOC_S_AUDIO)]          = "VIDIOC_S_AUDIO",
+       [_IOC_NR(VIDIOC_QUERYCTRL)]        = "VIDIOC_QUERYCTRL",
+       [_IOC_NR(VIDIOC_QUERYMENU)]        = "VIDIOC_QUERYMENU",
+       [_IOC_NR(VIDIOC_G_INPUT)]          = "VIDIOC_G_INPUT",
+       [_IOC_NR(VIDIOC_S_INPUT)]          = "VIDIOC_S_INPUT",
+       [_IOC_NR(VIDIOC_G_OUTPUT)]         = "VIDIOC_G_OUTPUT",
+       [_IOC_NR(VIDIOC_S_OUTPUT)]         = "VIDIOC_S_OUTPUT",
+       [_IOC_NR(VIDIOC_ENUMOUTPUT)]       = "VIDIOC_ENUMOUTPUT",
+       [_IOC_NR(VIDIOC_G_AUDOUT)]         = "VIDIOC_G_AUDOUT",
+       [_IOC_NR(VIDIOC_S_AUDOUT)]         = "VIDIOC_S_AUDOUT",
+       [_IOC_NR(VIDIOC_G_MODULATOR)]      = "VIDIOC_G_MODULATOR",
+       [_IOC_NR(VIDIOC_S_MODULATOR)]      = "VIDIOC_S_MODULATOR",
+       [_IOC_NR(VIDIOC_G_FREQUENCY)]      = "VIDIOC_G_FREQUENCY",
+       [_IOC_NR(VIDIOC_S_FREQUENCY)]      = "VIDIOC_S_FREQUENCY",
+       [_IOC_NR(VIDIOC_CROPCAP)]          = "VIDIOC_CROPCAP",
+       [_IOC_NR(VIDIOC_G_CROP)]           = "VIDIOC_G_CROP",
+       [_IOC_NR(VIDIOC_S_CROP)]           = "VIDIOC_S_CROP",
+       [_IOC_NR(VIDIOC_G_JPEGCOMP)]       = "VIDIOC_G_JPEGCOMP",
+       [_IOC_NR(VIDIOC_S_JPEGCOMP)]       = "VIDIOC_S_JPEGCOMP",
+       [_IOC_NR(VIDIOC_QUERYSTD)]         = "VIDIOC_QUERYSTD",
+       [_IOC_NR(VIDIOC_TRY_FMT)]          = "VIDIOC_TRY_FMT",
+       [_IOC_NR(VIDIOC_ENUMAUDIO)]        = "VIDIOC_ENUMAUDIO",
+       [_IOC_NR(VIDIOC_ENUMAUDOUT)]       = "VIDIOC_ENUMAUDOUT",
+       [_IOC_NR(VIDIOC_G_PRIORITY)]       = "VIDIOC_G_PRIORITY",
+       [_IOC_NR(VIDIOC_S_PRIORITY)]       = "VIDIOC_S_PRIORITY",
+#if 1
+       [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
 #endif
-       [_IOC_NR(VIDIOC_QUERYCAP)]       = "VIDIOC_QUERYCAP",
-       [_IOC_NR(VIDIOC_RESERVED)]       = "VIDIOC_RESERVED",
-       [_IOC_NR(VIDIOC_ENUM_FMT)]       = "VIDIOC_ENUM_FMT",
-       [_IOC_NR(VIDIOC_G_FMT)]          = "VIDIOC_G_FMT",
-       [_IOC_NR(VIDIOC_S_FMT)]          = "VIDIOC_S_FMT",
-       [_IOC_NR(VIDIOC_REQBUFS)]        = "VIDIOC_REQBUFS",
-       [_IOC_NR(VIDIOC_QUERYBUF)]       = "VIDIOC_QUERYBUF",
-       [_IOC_NR(VIDIOC_G_FBUF)]         = "VIDIOC_G_FBUF",
-       [_IOC_NR(VIDIOC_S_FBUF)]         = "VIDIOC_S_FBUF",
-       [_IOC_NR(VIDIOC_OVERLAY)]        = "VIDIOC_OVERLAY",
-       [_IOC_NR(VIDIOC_QBUF)]           = "VIDIOC_QBUF",
-       [_IOC_NR(VIDIOC_DQBUF)]          = "VIDIOC_DQBUF",
-       [_IOC_NR(VIDIOC_STREAMON)]       = "VIDIOC_STREAMON",
-       [_IOC_NR(VIDIOC_STREAMOFF)]      = "VIDIOC_STREAMOFF",
-       [_IOC_NR(VIDIOC_G_PARM)]         = "VIDIOC_G_PARM",
-       [_IOC_NR(VIDIOC_S_PARM)]         = "VIDIOC_S_PARM",
-       [_IOC_NR(VIDIOC_G_STD)]          = "VIDIOC_G_STD",
-       [_IOC_NR(VIDIOC_S_STD)]          = "VIDIOC_S_STD",
-       [_IOC_NR(VIDIOC_ENUMSTD)]        = "VIDIOC_ENUMSTD",
-       [_IOC_NR(VIDIOC_ENUMINPUT)]      = "VIDIOC_ENUMINPUT",
-       [_IOC_NR(VIDIOC_G_CTRL)]         = "VIDIOC_G_CTRL",
-       [_IOC_NR(VIDIOC_S_CTRL)]         = "VIDIOC_S_CTRL",
-       [_IOC_NR(VIDIOC_G_TUNER)]        = "VIDIOC_G_TUNER",
-       [_IOC_NR(VIDIOC_S_TUNER)]        = "VIDIOC_S_TUNER",
-       [_IOC_NR(VIDIOC_G_AUDIO)]        = "VIDIOC_G_AUDIO",
-       [_IOC_NR(VIDIOC_S_AUDIO)]        = "VIDIOC_S_AUDIO",
-       [_IOC_NR(VIDIOC_QUERYCTRL)]      = "VIDIOC_QUERYCTRL",
-       [_IOC_NR(VIDIOC_QUERYMENU)]      = "VIDIOC_QUERYMENU",
-       [_IOC_NR(VIDIOC_G_INPUT)]        = "VIDIOC_G_INPUT",
-       [_IOC_NR(VIDIOC_S_INPUT)]        = "VIDIOC_S_INPUT",
-       [_IOC_NR(VIDIOC_G_OUTPUT)]       = "VIDIOC_G_OUTPUT",
-       [_IOC_NR(VIDIOC_S_OUTPUT)]       = "VIDIOC_S_OUTPUT",
-       [_IOC_NR(VIDIOC_ENUMOUTPUT)]     = "VIDIOC_ENUMOUTPUT",
-       [_IOC_NR(VIDIOC_G_AUDOUT)]       = "VIDIOC_G_AUDOUT",
-       [_IOC_NR(VIDIOC_S_AUDOUT)]       = "VIDIOC_S_AUDOUT",
-       [_IOC_NR(VIDIOC_G_MODULATOR)]    = "VIDIOC_G_MODULATOR",
-       [_IOC_NR(VIDIOC_S_MODULATOR)]    = "VIDIOC_S_MODULATOR",
-       [_IOC_NR(VIDIOC_G_FREQUENCY)]    = "VIDIOC_G_FREQUENCY",
-       [_IOC_NR(VIDIOC_S_FREQUENCY)]    = "VIDIOC_S_FREQUENCY",
-       [_IOC_NR(VIDIOC_CROPCAP)]        = "VIDIOC_CROPCAP",
-       [_IOC_NR(VIDIOC_G_CROP)]         = "VIDIOC_G_CROP",
-       [_IOC_NR(VIDIOC_S_CROP)]         = "VIDIOC_S_CROP",
-       [_IOC_NR(VIDIOC_G_JPEGCOMP)]     = "VIDIOC_G_JPEGCOMP",
-       [_IOC_NR(VIDIOC_S_JPEGCOMP)]     = "VIDIOC_S_JPEGCOMP",
-       [_IOC_NR(VIDIOC_QUERYSTD)]       = "VIDIOC_QUERYSTD",
-       [_IOC_NR(VIDIOC_TRY_FMT)]        = "VIDIOC_TRY_FMT",
+       [_IOC_NR(VIDIOC_LOG_STATUS)]       = "VIDIOC_LOG_STATUS"
 };
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+static const char *v4l2_int_ioctls[] = {
+#ifdef HAVE_VIDEO_DECODER
+       [_IOC_NR(DECODER_GET_CAPABILITIES)]    = "DECODER_GET_CAPABILITIES",
+       [_IOC_NR(DECODER_GET_STATUS)]          = "DECODER_GET_STATUS",
+       [_IOC_NR(DECODER_SET_NORM)]            = "DECODER_SET_NORM",
+       [_IOC_NR(DECODER_SET_INPUT)]           = "DECODER_SET_INPUT",
+       [_IOC_NR(DECODER_SET_OUTPUT)]          = "DECODER_SET_OUTPUT",
+       [_IOC_NR(DECODER_ENABLE_OUTPUT)]       = "DECODER_ENABLE_OUTPUT",
+       [_IOC_NR(DECODER_SET_PICTURE)]         = "DECODER_SET_PICTURE",
+       [_IOC_NR(DECODER_SET_GPIO)]            = "DECODER_SET_GPIO",
+       [_IOC_NR(DECODER_INIT)]                = "DECODER_INIT",
+       [_IOC_NR(DECODER_SET_VBI_BYPASS)]      = "DECODER_SET_VBI_BYPASS",
+       [_IOC_NR(DECODER_DUMP)]                = "DECODER_DUMP",
+#endif
+       [_IOC_NR(AUDC_SET_RADIO)]              = "AUDC_SET_RADIO",
+       [_IOC_NR(AUDC_SET_INPUT)]              = "AUDC_SET_INPUT",
+
+       [_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
+       [_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
+       [_IOC_NR(TDA9887_SET_CONFIG)]          = "TDA9887_SET_CONFIG",
+
+       [_IOC_NR(VIDIOC_INT_S_REGISTER)]       = "VIDIOC_INT_S_REGISTER",
+       [_IOC_NR(VIDIOC_INT_G_REGISTER)]       = "VIDIOC_INT_G_REGISTER",
+       [_IOC_NR(VIDIOC_INT_RESET)]            = "VIDIOC_INT_RESET",
+       [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
+       [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)]  = "VIDIOC_INT_DECODE_VBI_LINE",
+       [_IOC_NR(VIDIOC_INT_S_VBI_DATA)]       = "VIDIOC_INT_S_VBI_DATA",
+       [_IOC_NR(VIDIOC_INT_G_VBI_DATA)]       = "VIDIOC_INT_G_VBI_DATA",
+       [_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)]     = "VIDIOC_INT_G_CHIP_IDENT",
+       [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)]   = "VIDIOC_INT_I2S_CLOCK_FREQ"
+};
+#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
+
+/* Common ioctl debug function. This function can be used by
+   external ioctl messages as well as internal V4L ioctl */
+void v4l_printk_ioctl(unsigned int cmd)
+{
+       char *dir;
+
+       switch (_IOC_DIR(cmd)) {
+       case _IOC_NONE:              dir = "--"; break;
+       case _IOC_READ:              dir = "r-"; break;
+       case _IOC_WRITE:             dir = "-w"; break;
+       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+       default:                     dir = "*ERR*"; break;
+       }
+       switch (_IOC_TYPE(cmd)) {
+       case 'd':
+               printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n",
+                      (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
+                      v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+               break;
+#ifdef HAVE_V4L1
+       case 'v':
+               printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
+                      (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+                      v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+               break;
+#endif
+       case 'V':
+               printk("v4l2 ioctl %s, dir=%s (0x%08x)\n",
+                      (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+                      v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+               break;
+
+       default:
+               printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n",
+                      _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
+       }
+}
 
 /* ----------------------------------------------------------------- */
 
@@ -255,7 +374,7 @@ EXPORT_SYMBOL(v4l2_prio_check);
 
 EXPORT_SYMBOL(v4l2_field_names);
 EXPORT_SYMBOL(v4l2_type_names);
-EXPORT_SYMBOL(v4l2_ioctl_names);
+EXPORT_SYMBOL(v4l_printk_ioctl);
 
 /*
  * Local variables:
index 6de5b0094b8253bd4a0b1dafc4822f43a1d1f982..9a9902c56ae72f81d06ebf58088baf73e05cc28a 100644 (file)
@@ -68,7 +68,8 @@ static void video_release(struct class_device *cd)
 {
        struct video_device *vfd = container_of(cd, struct video_device, class_dev);
 
-#if 1 /* needed until all drivers are fixed */
+#if 1
+       /* needed until all drivers are fixed */
        if (!vfd->release)
                return;
 #endif
@@ -338,13 +339,14 @@ int video_register_device(struct video_device *vfd, int type, int nr)
        if (vfd->dev)
                vfd->class_dev.dev = vfd->dev;
        vfd->class_dev.class       = &video_class;
-       vfd->class_dev.devt       = MKDEV(VIDEO_MAJOR, vfd->minor);
+       vfd->class_dev.devt        = MKDEV(VIDEO_MAJOR, vfd->minor);
        strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE);
        class_device_register(&vfd->class_dev);
        class_device_create_file(&vfd->class_dev,
-                                &class_device_attr_name);
+                               &class_device_attr_name);
 
-#if 1 /* needed until all drivers are fixed */
+#if 1
+       /* needed until all drivers are fixed */
        if (!vfd->release)
                printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
                       "Please fix your driver for proper sysfs support, see "
index c318ba32fbafa9ba88f31abf647b91dbef32ccb5..b7b0afffd21434b0fb7bc2c0e24c79175b063b42 100644 (file)
@@ -187,6 +187,7 @@ static struct file_operations w9966_fops = {
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
        .ioctl          = w9966_v4l_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .read           = w9966_v4l_read,
        .llseek         = no_llseek,
 };
index bbfd55cd9948f6433ba2e7d3a61923cb0b711848..c2e6d2e9f5f12ad70bcd52c6421debeef62dda25 100644 (file)
@@ -25,7 +25,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-#define wm8775_err(fmt, arg...) do { \
-       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define wm8775_info(fmt, arg...) do { \
-       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-
 static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
 
 
@@ -70,7 +61,7 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
        int i;
 
        if (reg < 0 || reg >= TOT_REGS) {
-               wm8775_err("Invalid register R%d\n", reg);
+               v4l_err(client, "Invalid register R%d\n", reg);
                return -1;
        }
 
@@ -80,7 +71,7 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
                        return 0;
                }
        }
-       wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg);
+       v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
        return -1;
 }
 
@@ -88,38 +79,53 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
                          void *arg)
 {
        struct wm8775_state *state = i2c_get_clientdata(client);
-       int *input = arg;
+       struct v4l2_audio *input = arg;
+       struct v4l2_control *ctrl = arg;
 
        switch (cmd) {
-       case AUDC_SET_INPUT:
+       case VIDIOC_S_AUDIO:
+               /* There are 4 inputs and one output. Zero or more inputs
+                  are multiplexed together to the output. Hence there are
+                  16 combinations.
+                  If only one input is active (the normal case) then the
+                  input values 1, 2, 4 or 8 should be used. */
+               if (input->index > 15) {
+                       v4l_err(client, "Invalid input %d.\n", input->index);
+                       return -EINVAL;
+               }
+               state->input = input->index;
+               if (state->muted)
+                       break;
                wm8775_write(client, R21, 0x0c0);
                wm8775_write(client, R14, 0x1d4);
                wm8775_write(client, R15, 0x1d4);
+               wm8775_write(client, R21, 0x100 + state->input);
+               break;
 
-               if (*input == AUDIO_RADIO) {
-                       wm8775_write(client, R21, 0x108);
-                       state->input = 8;
-                       state->muted = 0;
-                       break;
-               }
-               if (*input == AUDIO_MUTE) {
-                       state->muted = 1;
-                       break;
-               }
-               if (*input == AUDIO_UNMUTE) {
+       case VIDIOC_G_AUDIO:
+               memset(input, 0, sizeof(*input));
+               input->index = state->input;
+               break;
+
+       case VIDIOC_G_CTRL:
+               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               ctrl->value = state->muted;
+               break;
+
+       case VIDIOC_S_CTRL:
+               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               state->muted = ctrl->value;
+               wm8775_write(client, R21, 0x0c0);
+               wm8775_write(client, R14, 0x1d4);
+               wm8775_write(client, R15, 0x1d4);
+               if (!state->muted)
                        wm8775_write(client, R21, 0x100 + state->input);
-                       state->muted = 0;
-                       break;
-               }
-               /* All other inputs... */
-               wm8775_write(client, R21, 0x102);
-               state->input = 2;
-               state->muted = 0;
                break;
 
        case VIDIOC_LOG_STATUS:
-               wm8775_info("Input: %s%s\n",
-                           state->input == 8 ? "radio" : "default",
+               v4l_info(client, "Input: %d%s\n", state->input,
                            state->muted ? " (muted)" : "");
                break;
 
@@ -170,7 +176,7 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
        client->driver = &i2c_driver;
        snprintf(client->name, sizeof(client->name) - 1, "wm8775");
 
-       wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
 
        state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
        if (state == NULL) {
@@ -206,11 +212,7 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
 
 static int wm8775_probe(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
        if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-       if (adapter->id == I2C_HW_B_BT848)
-#endif
                return i2c_probe(adapter, &addr_data, wm8775_attach);
        return 0;
 }
@@ -235,12 +237,10 @@ static struct i2c_driver i2c_driver = {
        .driver = {
                .name = "wm8775",
        },
-
-       .id = I2C_DRIVERID_WM8775,
-
+       .id             = I2C_DRIVERID_WM8775,
        .attach_adapter = wm8775_probe,
-       .detach_client = wm8775_detach,
-       .command = wm8775_command,
+       .detach_client  = wm8775_detach,
+       .command        = wm8775_command,
 };
 
 
index 4034f1b45366922bffe95a4f3005c298ee7510d9..15283f44e79f6b56ba6bd708f8710ed9779156aa 100644 (file)
@@ -4678,6 +4678,7 @@ static struct file_operations zoran_fops = {
        .open = zoran_open,
        .release = zoran_close,
        .ioctl = zoran_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek = no_llseek,
        .read = zoran_read,
        .write = zoran_write,
index 07286816d7dfd4828df6aa879f17e02c864ac2d1..d4c633b8a7f5cc71420ee3816614907c522f22db 100644 (file)
@@ -1490,6 +1490,7 @@ static struct video_device zr36120_template=
        .write          = zoran_write,
        .poll           = zoran_poll,
        .ioctl          = zoran_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .mmap           = zoran_mmap,
        .minor          = -1,
 };
index 5b1febed313344e13370583ad799986f95fad700..b09fb6307153740efc92e674ae65dade0046c8aa 100644 (file)
@@ -662,6 +662,13 @@ static int i2o_block_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       i2o_block_biosparam(get_capacity(bdev->bd_disk),
+                           &geo->cylinders, &geo->heads, &geo->sectors);
+       return 0;
+}
+
 /**
  *     i2o_block_ioctl - Issue device specific ioctl calls.
  *     @cmd: ioctl command
@@ -676,7 +683,6 @@ static int i2o_block_ioctl(struct inode *inode, struct file *file,
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
        struct i2o_block_device *dev = disk->private_data;
-       void __user *argp = (void __user *)arg;
 
        /* Anyone capable of this syscall can do *real bad* things */
 
@@ -684,15 +690,6 @@ static int i2o_block_ioctl(struct inode *inode, struct file *file,
                return -EPERM;
 
        switch (cmd) {
-       case HDIO_GETGEO:
-               {
-                       struct hd_geometry g;
-                       i2o_block_biosparam(get_capacity(disk),
-                                           &g.cylinders, &g.heads, &g.sectors);
-                       g.start = get_start_sect(inode->i_bdev);
-                       return copy_to_user(argp, &g, sizeof(g)) ? -EFAULT : 0;
-               }
-
        case BLKI2OGRSTRAT:
                return put_user(dev->rcache, (int __user *)arg);
        case BLKI2OGWSTRAT:
@@ -962,6 +959,7 @@ static struct block_device_operations i2o_block_fops = {
        .open = i2o_block_open,
        .release = i2o_block_release,
        .ioctl = i2o_block_ioctl,
+       .getgeo = i2o_block_getgeo,
        .media_changed = i2o_block_media_changed
 };
 
index e335d54c4659ce2161bdb88e8a80a13e46915614..b42e0fbab59b6f880897e1d2303e48342341b8f7 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <asm/dma.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
 
 #include "ucb1x00.h"
 
@@ -507,14 +506,14 @@ static int ucb1x00_probe(struct mcp *mcp)
                goto err_free;
        }
 
-       ret = request_irq(ucb->irq, ucb1x00_irq, 0, "UCB1x00", ucb);
+       ret = request_irq(ucb->irq, ucb1x00_irq, SA_TRIGGER_RISING,
+                         "UCB1x00", ucb);
        if (ret) {
                printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
                        ucb->irq, ret);
                goto err_free;
        }
 
-       set_irq_type(ucb->irq, IRQT_RISING);
        mcp_set_drvdata(mcp, ucb);
 
        ret = class_device_register(&ucb->cdev);
index 551061c2eadfea93be0743d02528c51a9047b00c..79fd062ccb34bee7e02804f4271a82d6291a2950 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/suspend.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
-#include <linux/delay.h>
 
 #include <asm/dma.h>
 #include <asm/semaphore.h>
index f43cdfcbfd2cdd0ad503b50fe9667b92e81b1512..f2c42b13945d9bc4b0d13b8d7159c7e65abc174b 100644 (file)
@@ -113,31 +113,18 @@ static int mmc_blk_release(struct inode *inode, struct file *filp)
 }
 
 static int
-mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct block_device *bdev = inode->i_bdev;
-
-       if (cmd == HDIO_GETGEO) {
-               struct hd_geometry geo;
-
-               memset(&geo, 0, sizeof(struct hd_geometry));
-
-               geo.cylinders   = get_capacity(bdev->bd_disk) / (4 * 16);
-               geo.heads       = 4;
-               geo.sectors     = 16;
-               geo.start       = get_start_sect(bdev);
-
-               return copy_to_user((void __user *)arg, &geo, sizeof(geo))
-                       ? -EFAULT : 0;
-       }
-
-       return -ENOTTY;
+       geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
+       geo->heads = 4;
+       geo->sectors = 16;
+       return 0;
 }
 
 static struct block_device_operations mmc_bdops = {
        .open                   = mmc_blk_open,
        .release                = mmc_blk_release,
-       .ioctl                  = mmc_blk_ioctl,
+       .getgeo                 = mmc_blk_getgeo,
        .owner                  = THIS_MODULE,
 };
 
index 339cb1218eaa0b9d7e7431f069ec89a354051873..7f3ff500b68e37e3d5028bac85e4c22b9312db40 100644 (file)
@@ -194,6 +194,14 @@ static int blktrans_release(struct inode *i, struct file *f)
        return ret;
 }
 
+static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data;
+
+       if (dev->tr->getgeo)
+               return dev->tr->getgeo(dev, geo);
+       return -ENOTTY;
+}
 
 static int blktrans_ioctl(struct inode *inode, struct file *file,
                              unsigned int cmd, unsigned long arg)
@@ -207,22 +215,6 @@ static int blktrans_ioctl(struct inode *inode, struct file *file,
                        return tr->flush(dev);
                /* The core code did the work, we had nothing to do. */
                return 0;
-
-       case HDIO_GETGEO:
-               if (tr->getgeo) {
-                       struct hd_geometry g;
-                       int ret;
-
-                       memset(&g, 0, sizeof(g));
-                       ret = tr->getgeo(dev, &g);
-                       if (ret)
-                               return ret;
-
-                       g.start = get_start_sect(inode->i_bdev);
-                       if (copy_to_user((void __user *)arg, &g, sizeof(g)))
-                               return -EFAULT;
-                       return 0;
-               } /* else */
        default:
                return -ENOTTY;
        }
@@ -233,6 +225,7 @@ struct block_device_operations mtd_blktrans_ops = {
        .open           = blktrans_open,
        .release        = blktrans_release,
        .ioctl          = blktrans_ioctl,
+       .getgeo         = blktrans_getgeo,
 };
 
 int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
index 45c077d0f0630289f9763e35beeccf11ca285cc4..af06a80f44de2278011cae50f9cff905a6fd2436 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/onenand.h>
index 20ce212638fcc33178c4ff939cd505bf05d21060..a3e00a4635a5392180290e6d9b41d6bfd2fb07a8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mtd/blktrans.h>
 #include <linux/mtd/mtd.h>
 #include <linux/vmalloc.h>
+#include <linux/slab.h>
 #include <linux/jiffies.h>
 
 #include <asm/types.h>
index 5c5eebdb69146e5fb83f86ff6870f796d5e95933..dcc98afa65d717c7abe1f7360c0c9a90c75c3ce7 100644 (file)
@@ -148,14 +148,6 @@ el2_pio_probe(struct net_device *dev)
     return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       /* NB: el2_close() handles free_irq */
-       release_region(dev->base_addr, EL2_IO_EXTENT);
-       if (ei_status.mem)
-               iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init el2_probe(int unit)
 {
@@ -726,6 +718,14 @@ init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       /* NB: el2_close() handles free_irq */
+       release_region(dev->base_addr, EL2_IO_EXTENT);
+       if (ei_status.mem)
+               iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
index c10f009ce9b6dd3278cd8c2d0e71041b421e9532..53b5b071df08f3a341d474a94eeb4232f8a22416 100644 (file)
 
 struct mc32_mailbox
 {
-       u16     mbox __attribute((packed));
-       u16     data[1] __attribute((packed));
-};
+       u16 mbox;
+       u16 data[1];
+} __attribute((packed));
 
 struct skb_header
 {
-       u8      status __attribute((packed));
-       u8      control __attribute((packed));
-       u16     next __attribute((packed));     /* Do not change! */
-       u16     length __attribute((packed));
-       u32     data __attribute((packed));
-};
+       u8 status;
+       u8 control;
+       u16 next;       /* Do not change! */
+       u16 length;
+       u32 data;
+} __attribute((packed));
 
 struct mc32_stats
 {
        /* RX Errors */
-       u32     rx_crc_errors       __attribute((packed));      
-       u32     rx_alignment_errors  __attribute((packed));     
-       u32     rx_overrun_errors    __attribute((packed));
-       u32     rx_tooshort_errors  __attribute((packed));
-       u32     rx_toolong_errors   __attribute((packed));
-       u32     rx_outofresource_errors  __attribute((packed)); 
+       u32 rx_crc_errors;
+       u32 rx_alignment_errors;
+       u32 rx_overrun_errors;
+       u32 rx_tooshort_errors;
+       u32 rx_toolong_errors;
+       u32 rx_outofresource_errors;
 
-       u32     rx_discarded   __attribute((packed));  /* via card pattern match filter */ 
+       u32 rx_discarded;  /* via card pattern match filter */
 
        /* TX Errors */
-       u32     tx_max_collisions __attribute((packed)); 
-       u32     tx_carrier_errors __attribute((packed)); 
-       u32     tx_underrun_errors __attribute((packed)); 
-       u32     tx_cts_errors     __attribute((packed)); 
-       u32     tx_timeout_errors __attribute((packed)) ;
+       u32 tx_max_collisions;
+       u32 tx_carrier_errors;
+       u32 tx_underrun_errors;
+       u32 tx_cts_errors;
+       u32 tx_timeout_errors;
        
        /* various cruft */
-       u32     dataA[6] __attribute((packed));   
-        u16    dataB[5] __attribute((packed));   
-       u32     dataC[14] __attribute((packed));        
-};
+       u32 dataA[6];
+       u16 dataB[5];
+       u32 dataC[14];
+} __attribute((packed));
 
 #define STATUS_MASK    0x0F
 #define COMPLETED      (1<<7)
index e2fa29b612cdffbea7c7488ebcd0a77ddf62f726..733bc25b2bf96ea64513cf4a71a3d4cab71aaee2 100644 (file)
@@ -129,7 +129,7 @@ config NET_SB1000
 
          If you don't have this card, of course say N.
 
-       source "drivers/net/arcnet/Kconfig"
+source "drivers/net/arcnet/Kconfig"
 
 source "drivers/net/phy/Kconfig"
 
@@ -844,7 +844,7 @@ config SMC9194
 
 config DM9000
        tristate "DM9000 support"
-       depends on ARM && NET_ETHERNET
+       depends on (ARM || MIPS) && NET_ETHERNET
        select CRC32
        select MII
        ---help---
@@ -1374,7 +1374,7 @@ config FORCEDETH
 
 config CS89x0
        tristate "CS89x0 support"
-       depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105
+       depends on NET_PCI && (ISA || ARCH_IXDP2X01 || ARCH_PNX010X)
        ---help---
          Support for CS89x0 chipset based Ethernet cards. If you have a
          network (Ethernet) card of this type, say Y and read the
index 8a0af5453e21c93ed6eb19e7d8d925b65cc16cee..7952dc6d77e3f3f7f03900b00fad0a767320eae2 100644 (file)
@@ -123,14 +123,6 @@ static int __init do_ac3200_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       /* Someday free_irq may be in ac_close_card() */
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, AC_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init ac3200_probe(int unit)
 {
@@ -406,6 +398,14 @@ init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       /* Someday free_irq may be in ac_close_card() */
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr, AC_IO_EXTENT);
+       iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
index 015c7f1d1bc0843e3be52454505a8d99ad068fc9..f20bb85c1ea57f8ccf4f07ced53236cbcd1aeb5a 100644 (file)
@@ -205,7 +205,7 @@ struct bonding {
  *
  * Caller must hold bond lock for read
  */
-extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev)
+static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev)
 {
        struct slave *slave = NULL;
        int i;
@@ -219,7 +219,7 @@ extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct n
        return slave;
 }
 
-extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
+static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
 {
        if (!slave || !slave->dev->master) {
                return NULL;
@@ -228,13 +228,13 @@ extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
        return (struct bonding *)slave->dev->master->priv;
 }
 
-extern inline void bond_set_slave_inactive_flags(struct slave *slave)
+static inline void bond_set_slave_inactive_flags(struct slave *slave)
 {
        slave->state = BOND_STATE_BACKUP;
        slave->dev->flags |= IFF_NOARP;
 }
 
-extern inline void bond_set_slave_active_flags(struct slave *slave)
+static inline void bond_set_slave_active_flags(struct slave *slave)
 {
        slave->state = BOND_STATE_ACTIVE;
        slave->dev->flags &= ~IFF_NOARP;
index a6078ad9b654ff0295901a885a72c730a4188c8b..907c0100974665b57e80c695f357e3d02f78cd04 100644 (file)
@@ -175,7 +175,7 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0};
 #include <asm/irq.h>
 static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
-#elif defined(CONFIG_ARCH_PNX0105)
+#elif defined(CONFIG_ARCH_PNX010X)
 #include <asm/irq.h>
 #include <asm/arch/gpio.h>
 #define CIRRUS_DEFAULT_BASE    IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000)      /* = Physical address 0x48200000 */
@@ -338,30 +338,86 @@ out:
 }
 #endif
 
+#if defined(CONFIG_ARCH_IXDP2X01)
 static int
-readreg(struct net_device *dev, int portno)
+readword(unsigned long base_addr, int portno)
 {
-       outw(portno, dev->base_addr + ADD_PORT);
-       return inw(dev->base_addr + DATA_PORT);
+       return (u16)__raw_readl(base_addr + (portno << 1));
 }
 
 static void
-writereg(struct net_device *dev, int portno, int value)
+writeword(unsigned long base_addr, int portno, int value)
 {
-       outw(portno, dev->base_addr + ADD_PORT);
-       outw(value, dev->base_addr + DATA_PORT);
+       __raw_writel((u16)value, base_addr + (portno << 1));
+}
+#else
+#if defined(CONFIG_ARCH_PNX010X)
+static int
+readword(unsigned long base_addr, int portno)
+{
+       return inw(base_addr + (portno << 1));
+}
+
+static void
+writeword(unsigned long base_addr, int portno, int value)
+{
+       outw(value, base_addr + (portno << 1));
+}
+#else
+static int
+readword(unsigned long base_addr, int portno)
+{
+       return inw(base_addr + portno);
+}
+
+static void
+writeword(unsigned long base_addr, int portno, int value)
+{
+       outw(value, base_addr + portno);
+}
+#endif
+#endif
+
+static void
+readwords(unsigned long base_addr, int portno, void *buf, int length)
+{
+       u8 *buf8 = (u8 *)buf;
+
+       do {
+               u32 tmp32;
+
+               tmp32 = readword(base_addr, portno);
+               *buf8++ = (u8)tmp32;
+               *buf8++ = (u8)(tmp32 >> 8);
+       } while (--length);
+}
+
+static void
+writewords(unsigned long base_addr, int portno, void *buf, int length)
+{
+       u8 *buf8 = (u8 *)buf;
+
+       do {
+               u32 tmp32;
+
+               tmp32 = *buf8++;
+               tmp32 |= (*buf8++) << 8;
+               writeword(base_addr, portno, tmp32);
+       } while (--length);
 }
 
 static int
-readword(struct net_device *dev, int portno)
+readreg(struct net_device *dev, int regno)
 {
-       return inw(dev->base_addr + portno);
+       writeword(dev->base_addr, ADD_PORT, regno);
+       return readword(dev->base_addr, DATA_PORT);
 }
 
 static void
-writeword(struct net_device *dev, int portno, int value)
+writereg(struct net_device *dev, int regno, int value)
 {
-       outw(value, dev->base_addr + portno);
+       writeword(dev->base_addr, ADD_PORT, regno);
+       writeword(dev->base_addr, DATA_PORT, value);
 }
 
 static int __init
@@ -456,7 +512,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
 #endif
         }
 
-#ifdef CONFIG_ARCH_PNX0105
+#ifdef CONFIG_ARCH_PNX010X
        initialize_ebi();
 
        /* Map GPIO registers for the pins connected to the CS8900a. */
@@ -491,8 +547,8 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
 
 #ifdef CONFIG_SH_HICOSH4
        /* truely reset the chip */
-       outw(0x0114, ioaddr + ADD_PORT);
-       outw(0x0040, ioaddr + DATA_PORT);
+       writeword(ioaddr, ADD_PORT, 0x0114);
+       writeword(ioaddr, DATA_PORT, 0x0040);
 #endif
 
        /* if they give us an odd I/O address, then do ONE write to
@@ -503,24 +559,24 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
                if (net_debug > 1)
                        printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr);
                if ((ioaddr & 2) != 2)
-                       if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) {
+                       if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) {
                                printk(KERN_ERR "%s: bad signature 0x%x\n",
-                                       dev->name, inw((ioaddr & ~3)+ ADD_PORT));
+                                       dev->name, readword(ioaddr & ~3, ADD_PORT));
                                retval = -ENODEV;
                                goto out2;
                        }
        }
-       printk(KERN_DEBUG "PP_addr at %x: 0x%x\n",
-                       ioaddr + ADD_PORT, inw(ioaddr + ADD_PORT));
+       printk(KERN_DEBUG "PP_addr at %x[%x]: 0x%x\n",
+                       ioaddr, ADD_PORT, readword(ioaddr, ADD_PORT));
 
        ioaddr &= ~3;
-       outw(PP_ChipID, ioaddr + ADD_PORT);
+       writeword(ioaddr, ADD_PORT, PP_ChipID);
 
-       tmp = inw(ioaddr + DATA_PORT);
+       tmp = readword(ioaddr, DATA_PORT);
        if (tmp != CHIP_EISA_ID_SIG) {
-               printk(KERN_DEBUG "%s: incorrect signature at %x: 0x%x!="
+               printk(KERN_DEBUG "%s: incorrect signature at %x[%x]: 0x%x!="
                        CHIP_EISA_ID_SIG_STR "\n",
-                       dev->name, ioaddr + DATA_PORT, tmp);
+                       dev->name, ioaddr, DATA_PORT, tmp);
                retval = -ENODEV;
                goto out2;
        }
@@ -724,7 +780,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
        } else {
                i = lp->isa_config & INT_NO_MASK;
                if (lp->chip_type == CS8900) {
-#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X)
                        i = cs8900_irq_map[0];
 #else
                        /* Translate the IRQ using the IRQ mapping table. */
@@ -790,7 +846,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
                goto out3;
        return 0;
 out3:
-       outw(PP_ChipID, dev->base_addr + ADD_PORT);
+       writeword(dev->base_addr, ADD_PORT, PP_ChipID);
 out2:
        release_region(ioaddr & ~3, NETCARD_IO_EXTENT);
 out1:
@@ -970,11 +1026,11 @@ void  __init reset_chip(struct net_device *dev)
 #ifndef CONFIG_ARCH_IXDP2X01
        if (lp->chip_type != CS8900) {
                /* Hardware problem requires PNP registers to be reconfigured after a reset */
-               outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT);
+               writeword(ioaddr, ADD_PORT, PP_CS8920_ISAINT);
                outb(dev->irq, ioaddr + DATA_PORT);
                outb(0,      ioaddr + DATA_PORT + 1);
 
-               outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT);
+               writeword(ioaddr, ADD_PORT, PP_CS8920_ISAMemB);
                outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT);
                outb((dev->mem_start >> 8) & 0xff,   ioaddr + DATA_PORT + 1);
        }
@@ -1104,8 +1160,8 @@ send_test_pkt(struct net_device *dev)
        memcpy(test_packet,          dev->dev_addr, ETH_ALEN);
        memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN);
 
-        writeword(dev, TX_CMD_PORT, TX_AFTER_ALL);
-        writeword(dev, TX_LEN_PORT, ETH_ZLEN);
+        writeword(dev->base_addr, TX_CMD_PORT, TX_AFTER_ALL);
+        writeword(dev->base_addr, TX_LEN_PORT, ETH_ZLEN);
 
        /* Test to see if the chip has allocated memory for the packet */
        while (jiffies - timenow < 5)
@@ -1115,7 +1171,7 @@ send_test_pkt(struct net_device *dev)
                return 0;       /* this shouldn't happen */
 
        /* Write the contents of the packet */
-       outsw(dev->base_addr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);
+       writewords(dev->base_addr, TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);
 
        if (net_debug > 1) printk("Sending test packet ");
        /* wait a couple of jiffies for packet to be received */
@@ -1200,7 +1256,7 @@ net_open(struct net_device *dev)
        int i;
        int ret;
 
-#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */
+#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX010X) /* uses irq#1, so this won't work */
        if (dev->irq < 2) {
                /* Allow interrupts to be generated by the chip */
 /* Cirrus' release had this: */
@@ -1231,7 +1287,7 @@ net_open(struct net_device *dev)
        else
 #endif
        {
-#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105)
+#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)
                if (((1 << dev->irq) & lp->irq_map) == 0) {
                        printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
@@ -1316,7 +1372,7 @@ net_open(struct net_device *dev)
        case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
         default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
         }
-#ifdef CONFIG_ARCH_PNX0105
+#ifdef CONFIG_ARCH_PNX010X
        result = A_CNF_10B_T;
 #endif
         if (!result) {
@@ -1457,8 +1513,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
        netif_stop_queue(dev);
 
        /* initiate a transmit sequence */
-       writeword(dev, TX_CMD_PORT, lp->send_cmd);
-       writeword(dev, TX_LEN_PORT, skb->len);
+       writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd);
+       writeword(dev->base_addr, TX_LEN_PORT, skb->len);
 
        /* Test to see if the chip has allocated memory for the packet */
        if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
@@ -1472,7 +1528,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
                return 1;
        }
        /* Write the contents of the packet */
-       outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
+       writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
        spin_unlock_irq(&lp->lock);
        lp->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
@@ -1512,7 +1568,7 @@ static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
            course, if you're on a slow machine, and packets are arriving
            faster than you can read them off, you're screwed.  Hasta la
            vista, baby!  */
-       while ((status = readword(dev, ISQ_PORT))) {
+       while ((status = readword(dev->base_addr, ISQ_PORT))) {
                if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
                handled = 1;
                switch(status & ISQ_EVENT_MASK) {
@@ -1606,8 +1662,8 @@ net_rx(struct net_device *dev)
        int status, length;
 
        int ioaddr = dev->base_addr;
-       status = inw(ioaddr + RX_FRAME_PORT);
-       length = inw(ioaddr + RX_FRAME_PORT);
+       status = readword(ioaddr, RX_FRAME_PORT);
+       length = readword(ioaddr, RX_FRAME_PORT);
 
        if ((status & RX_OK) == 0) {
                count_rx_errors(status, lp);
@@ -1626,9 +1682,9 @@ net_rx(struct net_device *dev)
        skb_reserve(skb, 2);    /* longword align L3 header */
        skb->dev = dev;
 
-       insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1);
+       readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1);
        if (length & 1)
-               skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT);
+               skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT);
 
        if (net_debug > 3) {
                printk( "%s: received %d byte packet of type %x\n",
@@ -1901,7 +1957,7 @@ void
 cleanup_module(void)
 {
        unregister_netdev(dev_cs89x0);
-       outw(PP_ChipID, dev_cs89x0->base_addr + ADD_PORT);
+       writeword(dev_cs89x0->base_addr, ADD_PORT, PP_ChipID);
        release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT);
        free_netdev(dev_cs89x0);
 }
index decea264f1214c615b557e2678f34ce6225b8643..bd954aaa636f2490850e29aec57b9fb265f2dca8 100644 (file)
 
 #include <linux/config.h>
 
-#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
-/* IXDP2401/IXDP2801 uses dword-aligned register addressing */
-#define CS89x0_PORT(reg) ((reg) * 2)
-#else
-#define CS89x0_PORT(reg) (reg)
-#endif
-
 #define PP_ChipID 0x0000       /* offset   0h -> Corp -ID              */
                                /* offset   2h -> Model/Product Number  */
                                /* offset   3h -> Chip Revision Number  */
 #define RAM_SIZE       0x1000       /*  The card has 4k bytes or RAM */
 #define PKT_START PP_TxFrame  /*  Start of packet RAM */
 
-#define RX_FRAME_PORT  CS89x0_PORT(0x0000)
+#define RX_FRAME_PORT  0x0000
 #define TX_FRAME_PORT RX_FRAME_PORT
-#define TX_CMD_PORT    CS89x0_PORT(0x0004)
+#define TX_CMD_PORT    0x0004
 #define TX_NOW         0x0000       /*  Tx packet after   5 bytes copied */
 #define TX_AFTER_381   0x0040       /*  Tx packet after 381 bytes copied */
 #define TX_AFTER_ALL   0x00c0       /*  Tx packet after all bytes copied */
-#define TX_LEN_PORT    CS89x0_PORT(0x0006)
-#define ISQ_PORT       CS89x0_PORT(0x0008)
-#define ADD_PORT       CS89x0_PORT(0x000A)
-#define DATA_PORT      CS89x0_PORT(0x000C)
+#define TX_LEN_PORT    0x0006
+#define ISQ_PORT       0x0008
+#define ADD_PORT       0x000A
+#define DATA_PORT      0x000C
 
 #define EEPROM_WRITE_EN                0x00F0
 #define EEPROM_WRITE_DIS       0x0000
index 38695d5b46377ca035cff87e47fd32c9d5f69015..ccbbe5ad8e0fb230cd8477fe4df0b2907cea4756 100644 (file)
@@ -545,7 +545,7 @@ e1000_check_fiber_options(struct e1000_adapter *adapter)
 static void __devinit
 e1000_check_copper_options(struct e1000_adapter *adapter)
 {
-       int speed, dplx;
+       int speed, dplx, an;
        int bd = adapter->bd_number;
 
        { /* Speed */
@@ -641,8 +641,12 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
                                         .p = an_list }}
                };
 
-               int an = AutoNeg[bd];
-               e1000_validate_option(&an, &opt, adapter);
+               if (num_AutoNeg > bd) {
+                       an = AutoNeg[bd];
+                       e1000_validate_option(&an, &opt, adapter);
+               } else {
+                       an = opt.def;
+               }
                adapter->hw.autoneg_advertised = an;
        }
 
index f5a4dd7d856440d5ae6b5a41784ee80952dec4b3..e5c5cd2a271263c21e85c23bf96ec739c25f0db5 100644 (file)
@@ -140,13 +140,6 @@ static int  __init do_e2100_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       /* NB: e21_close() handles free_irq */
-       iounmap(ei_status.mem);
-       release_region(dev->base_addr, E21_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init e2100_probe(int unit)
 {
@@ -463,6 +456,13 @@ init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       /* NB: e21_close() handles free_irq */
+       iounmap(ei_status.mem);
+       release_region(dev->base_addr, E21_IO_EXTENT);
+}
+
 void
 cleanup_module(void)
 {
index 50f8e23bb9e503782693aa7a7c2f8b76c564f983..6b0ab1eac3fb6179ddeafacb8a05ae8265be94bb 100644 (file)
@@ -155,13 +155,6 @@ static int __init do_es_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, ES_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init es_probe(int unit)
 {
@@ -456,6 +449,13 @@ init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr, ES_IO_EXTENT);
+       iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
index c39344adecce590376c848311856122c63c77c2c..3682ec61e8a8f539a6860f415ad3cd83b9a2d720 100644 (file)
  *     0.46: 20 Oct 2005: Add irq optimization modes.
  *     0.47: 26 Oct 2005: Add phyaddr 0 in phy scan.
  *     0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single
+ *     0.49: 10 Dec 2005: Fix tso for large buffers.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.48"
+#define FORCEDETH_VERSION              "0.49"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
@@ -349,6 +350,8 @@ typedef union _ring_type {
 #define NV_TX2_VALID           (1<<31)
 #define NV_TX2_TSO             (1<<28)
 #define NV_TX2_TSO_SHIFT       14
+#define NV_TX2_TSO_MAX_SHIFT   14
+#define NV_TX2_TSO_MAX_SIZE    (1<<NV_TX2_TSO_MAX_SHIFT)
 #define NV_TX2_CHECKSUM_L3     (1<<27)
 #define NV_TX2_CHECKSUM_L4     (1<<26)
 
@@ -408,15 +411,15 @@ typedef union _ring_type {
 #define NV_WATCHDOG_TIMEO      (5*HZ)
 
 #define RX_RING                128
-#define TX_RING                64
+#define TX_RING                256
 /* 
  * If your nic mysteriously hangs then try to reduce the limits
  * to 1/0: It might be required to set NV_TX_LASTPACKET in the
  * last valid ring entry. But this would be impossible to
  * implement - probably a disassembly error.
  */
-#define TX_LIMIT_STOP  63
-#define TX_LIMIT_START 62
+#define TX_LIMIT_STOP  255
+#define TX_LIMIT_START 254
 
 /* rx/tx mac addr + type + vlan + align + slack*/
 #define NV_RX_HEADERS          (64)
@@ -535,6 +538,7 @@ struct fe_priv {
        unsigned int next_tx, nic_tx;
        struct sk_buff *tx_skbuff[TX_RING];
        dma_addr_t tx_dma[TX_RING];
+       unsigned int tx_dma_len[TX_RING];
        u32 tx_flags;
 };
 
@@ -935,6 +939,7 @@ static void nv_init_tx(struct net_device *dev)
                else
                        np->tx_ring.ex[i].FlagLen = 0;
                np->tx_skbuff[i] = NULL;
+               np->tx_dma[i] = 0;
        }
 }
 
@@ -945,30 +950,27 @@ static int nv_init_ring(struct net_device *dev)
        return nv_alloc_rx(dev);
 }
 
-static void nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
 {
        struct fe_priv *np = netdev_priv(dev);
-       struct sk_buff *skb = np->tx_skbuff[skbnr];
-       unsigned int j, entry, fragments;
-                       
-       dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n",
-               dev->name, skbnr, np->tx_skbuff[skbnr]);
-       
-       entry = skbnr;
-       if ((fragments = skb_shinfo(skb)->nr_frags) != 0) {
-               for (j = fragments; j >= 1; j--) {
-                       skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1];
-                       pci_unmap_page(np->pci_dev, np->tx_dma[entry],
-                                      frag->size,
-                                      PCI_DMA_TODEVICE);
-                       entry = (entry - 1) % TX_RING;
-               }
+
+       dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
+               dev->name, skbnr);
+
+       if (np->tx_dma[skbnr]) {
+               pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
+                              np->tx_dma_len[skbnr],
+                              PCI_DMA_TODEVICE);
+               np->tx_dma[skbnr] = 0;
+       }
+
+       if (np->tx_skbuff[skbnr]) {
+               dev_kfree_skb_irq(np->tx_skbuff[skbnr]);
+               np->tx_skbuff[skbnr] = NULL;
+               return 1;
+       } else {
+               return 0;
        }
-       pci_unmap_single(np->pci_dev, np->tx_dma[entry],
-                        skb->len - skb->data_len,
-                        PCI_DMA_TODEVICE);
-       dev_kfree_skb_irq(skb);
-       np->tx_skbuff[skbnr] = NULL;
 }
 
 static void nv_drain_tx(struct net_device *dev)
@@ -981,10 +983,8 @@ static void nv_drain_tx(struct net_device *dev)
                        np->tx_ring.orig[i].FlagLen = 0;
                else
                        np->tx_ring.ex[i].FlagLen = 0;
-               if (np->tx_skbuff[i]) {
-                       nv_release_txskb(dev, i);
+               if (nv_release_txskb(dev, i))
                        np->stats.tx_dropped++;
-               }
        }
 }
 
@@ -1021,68 +1021,105 @@ static void drain_ring(struct net_device *dev)
 static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
+       u32 tx_flags = 0;
        u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
        unsigned int fragments = skb_shinfo(skb)->nr_frags;
-       unsigned int nr = (np->next_tx + fragments) % TX_RING;
+       unsigned int nr = (np->next_tx - 1) % TX_RING;
+       unsigned int start_nr = np->next_tx % TX_RING;
        unsigned int i;
+       u32 offset = 0;
+       u32 bcnt;
+       u32 size = skb->len-skb->data_len;
+       u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+
+       /* add fragments to entries count */
+       for (i = 0; i < fragments; i++) {
+               entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+                          ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+       }
 
        spin_lock_irq(&np->lock);
 
-       if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) {
+       if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) {
                spin_unlock_irq(&np->lock);
                netif_stop_queue(dev);
                return NETDEV_TX_BUSY;
        }
 
-       np->tx_skbuff[nr] = skb;
-       
-       if (fragments) {
-               dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments);
-               /* setup descriptors in reverse order */
-               for (i = fragments; i >= 1; i--) {
-                       skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
-                       np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size,
-                                                       PCI_DMA_TODEVICE);
+       /* setup the header buffer */
+       do {
+               bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+               nr = (nr + 1) % TX_RING;
+
+               np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+                                               PCI_DMA_TODEVICE);
+               np->tx_dma_len[nr] = bcnt;
+
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+                       np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+                       np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+               } else {
+                       np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+                       np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+                       np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+               }
+               tx_flags = np->tx_flags;
+               offset += bcnt;
+               size -= bcnt;
+       } while(size);
+
+       /* setup the fragments */
+       for (i = 0; i < fragments; i++) {
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+               u32 size = frag->size;
+               offset = 0;
+
+               do {
+                       bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+                       nr = (nr + 1) % TX_RING;
+
+                       np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+                                                     PCI_DMA_TODEVICE);
+                       np->tx_dma_len[nr] = bcnt;
 
                        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                                np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-                               np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+                               np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
                        } else {
                                np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
                                np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-                               np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+                               np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
                        }
-                       
-                       nr = (nr - 1) % TX_RING;
+                       offset += bcnt;
+                       size -= bcnt;
+               } while (size);
+       }
 
-                       if (np->desc_ver == DESC_VER_1)
-                               tx_flags_extra &= ~NV_TX_LASTPACKET;
-                       else
-                               tx_flags_extra &= ~NV_TX2_LASTPACKET;           
-               }
+       /* set last fragment flag  */
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+               np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+       } else {
+               np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
        }
 
+       np->tx_skbuff[nr] = skb;
+
 #ifdef NETIF_F_TSO
        if (skb_shinfo(skb)->tso_size)
-               tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+               tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
        else
 #endif
-       tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+       tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
 
-       np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len,
-                                       PCI_DMA_TODEVICE);
-       
+       /* set tx flags */
        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-               np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-               np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+               np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
        } else {
-               np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-               np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-               np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+               np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
        }       
 
-       dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n",
-                               dev->name, np->next_tx, tx_flags_extra);
+       dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
+               dev->name, np->next_tx, entries, tx_flags_extra);
        {
                int j;
                for (j=0; j<64; j++) {
@@ -1093,7 +1130,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dprintk("\n");
        }
 
-       np->next_tx += 1 + fragments;
+       np->next_tx += entries;
 
        dev->trans_start = jiffies;
        spin_unlock_irq(&np->lock);
@@ -1140,7 +1177,6 @@ static void nv_tx_done(struct net_device *dev)
                                        np->stats.tx_packets++;
                                        np->stats.tx_bytes += skb->len;
                                }
-                               nv_release_txskb(dev, i);
                        }
                } else {
                        if (Flags & NV_TX2_LASTPACKET) {
@@ -1156,9 +1192,9 @@ static void nv_tx_done(struct net_device *dev)
                                        np->stats.tx_packets++;
                                        np->stats.tx_bytes += skb->len;
                                }                               
-                               nv_release_txskb(dev, i);
                        }
                }
+               nv_release_txskb(dev, i);
                np->nic_tx++;
        }
        if (np->next_tx - np->nic_tx < TX_LIMIT_START)
@@ -2456,7 +2492,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
                dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
 #ifdef NETIF_F_TSO
-               /* disabled dev->features |= NETIF_F_TSO; */
+               dev->features |= NETIF_F_TSO;
 #endif
        }
 
index 94a91da84fbb7ac5abe74cd6e63332c48ca9afa5..cb9d66ac3ab999db27455027f553c321047a4cfc 100644 (file)
@@ -718,14 +718,14 @@ struct gfar_private {
        uint32_t msg_enable;
 };
 
-extern inline u32 gfar_read(volatile unsigned *addr)
+static inline u32 gfar_read(volatile unsigned *addr)
 {
        u32 val;
        val = in_be32(addr);
        return val;
 }
 
-extern inline void gfar_write(volatile unsigned *addr, u32 val)
+static inline void gfar_write(volatile unsigned *addr, u32 val)
 {
        out_be32(addr, val);
 }
index 3e9accf137e717ac47fe209cfc3621e7bf32960c..41b3d83c2ab83d7e9a6a7da72586b3d147824c3e 100644 (file)
@@ -524,6 +524,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
        ax->dev->trans_start = jiffies;
        ax->xleft = count - actual;
        ax->xhead = ax->xbuff + actual;
+       spin_unlock_bh(&ax->buflock);
 }
 
 /* Encapsulate an AX.25 packet and kick it into a TTY queue. */
index 0abf5dd08b4c5030e4c1b26021eb7f969fef20d2..74e167e7dea77bf8c908aef9ca87e456a6a6e675 100644 (file)
@@ -138,12 +138,6 @@ static int __init do_hpp_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       /* NB: hpp_close() handles free_irq */
-       release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init hp_plus_probe(int unit)
 {
@@ -473,6 +467,12 @@ init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       /* NB: hpp_close() handles free_irq */
+       release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
+}
+
 void
 cleanup_module(void)
 {
index 59cf841b14abc06ad2fa11f44ca55ac0dfa6f157..cf9fb3698a6bda38f8ac83f96b9cdad39b986fd8 100644 (file)
@@ -102,12 +102,6 @@ static int __init do_hp_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init hp_probe(int unit)
 {
@@ -444,6 +438,12 @@ init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
+}
+
 void
 cleanup_module(void)
 {
index 644edbff4f94f6d6e582df3edaacc51af6f6759b..c2dae6092c4c44a67703d4b0bdc486cc642a26f1 100644 (file)
@@ -110,6 +110,7 @@ struct emac_regs {
 #define EMAC_MR1_TFS_2K                        0x00080000
 #define EMAC_MR1_TR0_MULT              0x00008000
 #define EMAC_MR1_JPSM                  0x00000000
+#define EMAC_MR1_MWSW_001              0x00000000
 #define EMAC_MR1_BASE(opb)             (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT)
 #else
 #define EMAC_MR1_RFS_4K                        0x00180000
@@ -130,7 +131,7 @@ struct emac_regs {
                                         (freq) <= 83  ? EMAC_MR1_OBCI_83 : \
                                         (freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P)
 #define EMAC_MR1_BASE(opb)             (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \
-                                        EMAC_MR1_MWSW_001 | EMAC_MR1_OBCI(opb))
+                                        EMAC_MR1_OBCI(opb))
 #endif
 
 /* EMACx_TMR0 */
index 1da8a66f91e115cf913f6c0492c3c2187cd6be75..591c5864ffb12b346bf29331ec59748da7dfa69d 100644 (file)
@@ -408,7 +408,7 @@ static int emac_configure(struct ocp_enet_private *dev)
        /* Mode register */
        r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST;
        if (dev->phy.duplex == DUPLEX_FULL)
-               r |= EMAC_MR1_FDE;
+               r |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;
        dev->stop_timeout = STOP_TIMEOUT_10;
        switch (dev->phy.speed) {
        case SPEED_1000:
index 741aecc655dfe7d9da06d610c77a1eb8e4a60618..a82a4ba8de4fc2a6f27280a127a5997dfbd39637 100644 (file)
@@ -577,8 +577,8 @@ struct ring_descr_hw {
                struct {
                        u8              addr_res[3];
                        volatile u8     status;         /* descriptor status */
-               } rd_s __attribute__((packed));
-       } rd_u __attribute((packed));
+               } __attribute__((packed)) rd_s;
+       } __attribute((packed)) rd_u;
 } __attribute__ ((packed));
 
 #define rd_addr                rd_u.addr
index 1d75ca0bb939429587b354ff6cd8e3f4463b247c..d1d714faa6ce04a939ddd1e210ca4136e79ca199 100644 (file)
@@ -309,17 +309,6 @@ static void lance_tx_timeout (struct net_device *dev);
 
 \f
 
-static void cleanup_card(struct net_device *dev)
-{
-       struct lance_private *lp = dev->priv;
-       if (dev->dma != 4)
-               free_dma(dev->dma);
-       release_region(dev->base_addr, LANCE_TOTAL_SIZE);
-       kfree(lp->tx_bounce_buffs);
-       kfree((void*)lp->rx_buffs);
-       kfree(lp);
-}
-
 #ifdef MODULE
 #define MAX_CARDS              8       /* Max number of interfaces (cards) per module */
 
@@ -367,6 +356,17 @@ int init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       struct lance_private *lp = dev->priv;
+       if (dev->dma != 4)
+               free_dma(dev->dma);
+       release_region(dev->base_addr, LANCE_TOTAL_SIZE);
+       kfree(lp->tx_bounce_buffs);
+       kfree((void*)lp->rx_buffs);
+       kfree(lp);
+}
+
 void cleanup_module(void)
 {
        int this_dev;
index 309d254842cf2f85ab2d0ea7653b98d4132b7248..646e89fc3562f975848af257b45249491db0f673 100644 (file)
@@ -145,13 +145,6 @@ static int __init do_lne390_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, LNE390_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init lne390_probe(int unit)
 {
@@ -440,6 +433,13 @@ int init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr, LNE390_IO_EXTENT);
+       iounmap(ei_status.mem);
+}
+
 void cleanup_module(void)
 {
        int this_dev;
index 3cb9b3fe0cf144000aa69ae7f11a1778c7608e39..22c3a37bba5a3eaed8e8117e7045efe5257bcfa4 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 2002 rabeeh@galileo.co.il
  *
  * Copyright (C) 2003 PMC-Sierra, Inc.,
- *     written by Manish Lachwani (lachwani@pmc-sierra.com)
+ *     written by Manish Lachwani
  *
  * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org>
  *
index 0de8fdd2aa86f338fa026e7c308cb3ca6be2b13c..94f782d51f0f0ccc6941673e4061acf8da8487a5 100644 (file)
@@ -212,15 +212,6 @@ static int __init do_ne_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
-       if (idev)
-               pnp_device_detach(idev);
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, NE_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init ne_probe(int unit)
 {
@@ -859,6 +850,15 @@ int init_module(void)
        return -ENODEV;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+       if (idev)
+               pnp_device_detach(idev);
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr, NE_IO_EXTENT);
+}
+
 void cleanup_module(void)
 {
        int this_dev;
index 6d62ada85de61c03eb90f7399dee5657df1a9578..e6df375a1d4bb20b0f0915afeae665bf4ccbbe46 100644 (file)
@@ -278,14 +278,6 @@ static int __init do_ne2_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       mca_mark_as_unused(ei_status.priv);
-       mca_set_adapter_procfn( ei_status.priv, NULL, NULL);
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, NE_IO_EXTENT);
-}
-
 #ifndef MODULE
 struct net_device * __init ne2_probe(int unit)
 {
@@ -812,6 +804,14 @@ int init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       mca_mark_as_unused(ei_status.priv);
+       mca_set_adapter_procfn( ei_status.priv, NULL, NULL);
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr, NE_IO_EXTENT);
+}
+
 void cleanup_module(void)
 {
        int this_dev;
index 9a76ac180b11519e69d09263a6bf1eafd8c1376a..197edd74fbb543c4c22c4f495f6771ae63c9cbf9 100644 (file)
@@ -282,26 +282,22 @@ SK_U32 Val)               /* pointer to store the read value */
  * Description:
  *     This function initialize the PCI resources and IO
  *
- * Returns: N/A
- *     
+ * Returns:
+ *     0 - indicate everything worked ok.
+ *     != 0 - error indication
  */
-int SkGeInitPCI(SK_AC *pAC)
+static __devinit int SkGeInitPCI(SK_AC *pAC)
 {
        struct SK_NET_DEVICE *dev = pAC->dev[0];
        struct pci_dev *pdev = pAC->PciDev;
        int retval;
 
-       if (pci_enable_device(pdev) != 0) {
-               return 1;
-       }
-
        dev->mem_start = pci_resource_start (pdev, 0);
        pci_set_master(pdev);
 
-       if (pci_request_regions(pdev, "sk98lin") != 0) {
-               retval = 2;
-               goto out_disable;
-       }
+       retval = pci_request_regions(pdev, "sk98lin");
+       if (retval)
+               goto out;
 
 #ifdef SK_BIG_ENDIAN
        /*
@@ -320,9 +316,8 @@ int SkGeInitPCI(SK_AC *pAC)
         * Remap the regs into kernel space.
         */
        pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000);
-
-       if (!pAC->IoBase){
-               retval = 3;
+       if (!pAC->IoBase) {
+               retval = -EIO;
                goto out_release;
        }
 
@@ -330,8 +325,7 @@ int SkGeInitPCI(SK_AC *pAC)
 
  out_release:
        pci_release_regions(pdev);
- out_disable:
-       pci_disable_device(pdev);
+ out:
        return retval;
 }
 
@@ -492,7 +486,7 @@ module_param_array(AutoSizing, charp, NULL, 0);
  *     0, if everything is ok
  *     !=0, on error
  */
-static int __init SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
+static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
 {
 short  i;
 unsigned long Flags;
@@ -529,7 +523,7 @@ SK_BOOL     DualNet;
        if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) {
                printk("HWInit (0) failed.\n");
                spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
-               return(-EAGAIN);
+               return -EIO;
        }
        SkI2cInit(  pAC, pAC->IoBase, SK_INIT_DATA);
        SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA);
@@ -551,7 +545,7 @@ SK_BOOL     DualNet;
        if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
                printk("sk98lin: HWInit (1) failed.\n");
                spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
-               return(-EAGAIN);
+               return -EIO;
        }
        SkI2cInit(  pAC, pAC->IoBase, SK_INIT_IO);
        SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
@@ -583,20 +577,20 @@ SK_BOOL   DualNet;
        } else {
                printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n",
                       pAC->GIni.GIMacsFound);
-               return -EAGAIN;
+               return -EIO;
        }
 
        if (Ret) {
                printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n",
                       dev->irq);
-               return -EAGAIN;
+               return Ret;
        }
        pAC->AllocFlag |= SK_ALLOC_IRQ;
 
        /* Alloc memory for this board (Mem for RxD/TxD) : */
        if(!BoardAllocMem(pAC)) {
                printk("No memory for descriptor rings.\n");
-                       return(-EAGAIN);
+               return -ENOMEM;
        }
 
        BoardInitMem(pAC);
@@ -612,7 +606,7 @@ SK_BOOL     DualNet;
                DualNet)) {
                BoardFreeMem(pAC);
                printk("sk98lin: SkGeInitAssignRamToQueues failed.\n");
-               return(-EAGAIN);
+               return -EIO;
        }
 
        return (0);
@@ -633,8 +627,7 @@ SK_BOOL     DualNet;
  *     SK_TRUE, if all memory could be allocated
  *     SK_FALSE, if not
  */
-static SK_BOOL BoardAllocMem(
-SK_AC  *pAC)
+static __devinit SK_BOOL BoardAllocMem(SK_AC   *pAC)
 {
 caddr_t                pDescrMem;      /* pointer to descriptor memory area */
 size_t         AllocLength;    /* length of complete descriptor area */
@@ -727,8 +720,7 @@ size_t              AllocLength;    /* length of complete descriptor area */
  *
  * Returns:    N/A
  */
-static void BoardInitMem(
-SK_AC  *pAC)   /* pointer to adapter context */
+static __devinit void BoardInitMem(SK_AC *pAC)
 {
 int    i;              /* loop counter */
 int    RxDescrSize;    /* the size of a rx descriptor rounded up to alignment*/
@@ -4776,32 +4768,47 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
        struct net_device       *dev = NULL;
        static int boards_found = 0;
        int error = -ENODEV;
+       int using_dac = 0;
        char DeviceStr[80];
 
        if (pci_enable_device(pdev))
                goto out;
  
        /* Configure DMA attributes. */
-       if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
-           pci_set_dma_mask(pdev, DMA_32BIT_MASK))
-               goto out_disable_device;
-
+       if (sizeof(dma_addr_t) > sizeof(u32) &&
+           !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+               using_dac = 1;
+               error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+               if (error < 0) {
+                       printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA "
+                              "for consistent allocations\n", pci_name(pdev));
+                       goto out_disable_device;
+               }
+       } else {
+               error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (error) {
+                       printk(KERN_ERR "sk98lin %s no usable DMA configuration\n",
+                              pci_name(pdev));
+                       goto out_disable_device;
+               }
+       }
 
-       if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) {
-               printk(KERN_ERR "Unable to allocate etherdev "
+       error = -ENOMEM;
+       dev = alloc_etherdev(sizeof(DEV_NET));
+       if (!dev) {
+               printk(KERN_ERR "sk98lin: unable to allocate etherdev "
                       "structure!\n");
                goto out_disable_device;
        }
 
        pNet = netdev_priv(dev);
-       pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL);
+       pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL);
        if (!pNet->pAC) {
-               printk(KERN_ERR "Unable to allocate adapter "
+               printk(KERN_ERR "sk98lin: unable to allocate adapter "
                       "structure!\n");
                goto out_free_netdev;
        }
 
-       memset(pNet->pAC, 0, sizeof(SK_AC));
        pAC = pNet->pAC;
        pAC->PciDev = pdev;
 
@@ -4810,6 +4817,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
        pAC->CheckQueue = SK_FALSE;
 
        dev->irq = pdev->irq;
+
        error = SkGeInitPCI(pAC);
        if (error) {
                printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error);
@@ -4844,19 +4852,25 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
 #endif
        }
 
+       if (using_dac)
+               dev->features |= NETIF_F_HIGHDMA;
+
        pAC->Index = boards_found++;
 
-       if (SkGeBoardInit(dev, pAC))
+       error = SkGeBoardInit(dev, pAC);
+       if (error)
                goto out_free_netdev;
 
        /* Read Adapter name from VPD */
        if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) {
+               error = -EIO;
                printk(KERN_ERR "sk98lin: Could not read VPD data.\n");
                goto out_free_resources;
        }
 
        /* Register net device */
-       if (register_netdev(dev)) {
+       error = register_netdev(dev);
+       if (error) {
                printk(KERN_ERR "sk98lin: Could not register device.\n");
                goto out_free_resources;
        }
@@ -4883,15 +4897,17 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
 
        boards_found++;
 
+       pci_set_drvdata(pdev, dev);
+
        /* More then one port found */
        if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
-               if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) {
-                       printk(KERN_ERR "Unable to allocate etherdev "
+               dev = alloc_etherdev(sizeof(DEV_NET));
+               if (!dev) {
+                       printk(KERN_ERR "sk98lin: unable to allocate etherdev "
                                "structure!\n");
-                       goto out;
+                       goto single_port;
                }
 
-               pAC->dev[1]   = dev;
                pNet          = netdev_priv(dev);
                pNet->PortNr  = 1;
                pNet->NetNr   = 1;
@@ -4920,20 +4936,28 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
 #endif
                }
 
-               if (register_netdev(dev)) {
-                       printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n");
+               if (using_dac)
+                       dev->features |= NETIF_F_HIGHDMA;
+
+               error = register_netdev(dev);
+               if (error) {
+                       printk(KERN_ERR "sk98lin: Could not register device"
+                              " for second port. (%d)\n", error);
                        free_netdev(dev);
-                       pAC->dev[1] = pAC->dev[0];
-               } else {
-                       memcpy(&dev->dev_addr,
-                                       &pAC->Addr.Net[1].CurrentMacAddress, 6);
-                       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-       
-                       printk("%s: %s\n", dev->name, DeviceStr);
-                       printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
+                       goto single_port;
                }
+
+               pAC->dev[1]   = dev;
+               memcpy(&dev->dev_addr,
+                      &pAC->Addr.Net[1].CurrentMacAddress, 6);
+               memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+               printk("%s: %s\n", dev->name, DeviceStr);
+               printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
        }
 
+single_port:
+
        /* Save the hardware revision */
        pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
                (pAC->GIni.GIPciHwRev & 0x0F);
@@ -4945,7 +4969,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
        memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA));
        memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA));
 
-       pci_set_drvdata(pdev, dev);
        return 0;
 
  out_free_resources:
index ba8593ac3f8ab8d690eac367207298bb662099ca..3db30cd0625e5fd7151f18af72b414bebe47e054 100644 (file)
@@ -168,18 +168,6 @@ static int __init do_ultra_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       /* NB: ultra_close_card() does free_irq */
-#ifdef __ISAPNP__
-       struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
-       if (idev)
-               pnp_device_detach(idev);
-#endif
-       release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init ultra_probe(int unit)
 {
@@ -594,6 +582,18 @@ init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       /* NB: ultra_close_card() does free_irq */
+#ifdef __ISAPNP__
+       struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+       if (idev)
+               pnp_device_detach(idev);
+#endif
+       release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
+       iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
index 28bf2e69eb5e1a1c9f181d2810447f8dd30ac10a..7ec08127c9d6c4f8594d805392155e3bddccd875 100644 (file)
@@ -88,7 +88,6 @@ static const char version[] =
 #include <linux/skbuff.h>
 
 #include <asm/io.h>
-#include <asm/irq.h>
 
 #include "smc91x.h"
 
@@ -2007,12 +2006,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
        }
 
        /* Grab the IRQ */
-       retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
+       retval = request_irq(dev->irq, &smc_interrupt, SMC_IRQ_FLAGS, dev->name, dev);
        if (retval)
                goto err_out;
 
-       set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE);
-
 #ifdef SMC_USE_PXA_DMA
        {
                int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW,
index 5c2824be4ee6399a73a49cad2fc986e8e704bba1..e0efd1964e72fc78f384da66e7260158375035fd 100644 (file)
@@ -90,7 +90,7 @@
                        __l--;                                          \
                }                                                       \
        } while (0)
-#define set_irq_type(irq, type)
+#define SMC_IRQ_FLAGS          (0)
 
 #elif defined(CONFIG_SA1100_PLEB)
 /* We can only do 16-bit reads and writes in the static memory space. */
 #define SMC_outw(v, a, r)      writew(v, (a) + (r))
 #define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
 
-#define set_irq_type(irq, type) do {} while (0)
+#define SMC_IRQ_FLAGS          (0)
 
 #elif defined(CONFIG_SA1100_ASSABET)
 
@@ -185,11 +185,11 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #include <asm/mach-types.h>
 #include <asm/arch/cpu.h>
 
-#define        SMC_IRQ_TRIGGER_TYPE (( \
+#define        SMC_IRQ_FLAGS (( \
                   machine_is_omap_h2() \
                || machine_is_omap_h3() \
                || (machine_is_omap_innovator() && !cpu_is_omap1510()) \
-       ) ? IRQT_FALLING : IRQT_RISING)
+       ) ? SA_TRIGGER_FALLING : SA_TRIGGER_RISING)
 
 
 #elif  defined(CONFIG_SH_SH4202_MICRODEV)
@@ -209,7 +209,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define SMC_insw(a, r, p, l)   insw((a) + (r) - 0xa0000000, p, l)
 #define SMC_outsw(a, r, p, l)  outsw((a) + (r) - 0xa0000000, p, l)
 
-#define set_irq_type(irq, type)        do {} while(0)
+#define SMC_IRQ_FLAGS          (0)
 
 #elif  defined(CONFIG_ISA)
 
@@ -237,7 +237,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define SMC_insw(a, r, p, l)   insw(((u32)a) + (r), p, l)
 #define SMC_outsw(a, r, p, l)  outsw(((u32)a) + (r), p, l)
 
-#define set_irq_type(irq, type)        do {} while(0)
+#define SMC_IRQ_FLAGS          (0)
 
 #define RPC_LSA_DEFAULT                RPC_LED_TX_RX
 #define RPC_LSB_DEFAULT                RPC_LED_100_10
@@ -319,7 +319,7 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l)
                        au_writew(*_p++ , _a); \
        } while(0)
 
-#define set_irq_type(irq, type) do {} while (0)
+#define SMC_IRQ_FLAGS          (0)
 
 #else
 
@@ -342,8 +342,8 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l)
 
 #endif
 
-#ifndef        SMC_IRQ_TRIGGER_TYPE
-#define        SMC_IRQ_TRIGGER_TYPE    IRQT_RISING
+#ifndef        SMC_IRQ_FLAGS
+#define        SMC_IRQ_FLAGS           SA_TRIGGER_RISING
 #endif
 
 #ifdef SMC_USE_PXA_DMA
index 125ed00e95a5b933445bfe79708702e43324d264..c67c91251d048d74bc60a01029343ba7cbd959c6 100644 (file)
@@ -1564,7 +1564,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
                            dev->dev_addr, 6);
                }
 #endif
-#if defined(__i386__)          /* Patch up x86 BIOS bug. */
+#if defined(__i386__) || defined(__x86_64__)   /* Patch up x86 BIOS bug. */
                if (last_irq)
                        irq = last_irq;
 #endif
index 036adc4f8ba7e85dab072fb7595cbe8f57e1e8d5..22e794071cf41627e48081c5177f7c03a506c68b 100644 (file)
@@ -329,9 +329,9 @@ static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr)
 
 struct _dlci_stat 
 {
-       short dlci              __attribute__((packed));
-       char  flags             __attribute__((packed));
-};
+       short dlci;
+       char  flags;
+} __attribute__((packed));
 
 struct _frad_stat 
 {
index b03feae459fcf335db90ca08d7d8506b64c86779..7caa8dc88a5869716c098a5c819ce5b89c8cf750 100644 (file)
@@ -127,13 +127,6 @@ static int __init do_wd_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-static void cleanup_card(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
 #ifndef MODULE
 struct net_device * __init wd_probe(int unit)
 {
@@ -538,6 +531,13 @@ init_module(void)
        return -ENXIO;
 }
 
+static void cleanup_card(struct net_device *dev)
+{
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
+       iounmap(ei_status.mem);
+}
+
 void
 cleanup_module(void)
 {
index 44cd3fcd15720916d0cf9984a02bc8adb2afcb83..cf05661fb1bda768d037d5eb950ad9a283651ef7 100644 (file)
@@ -7153,7 +7153,7 @@ static int ipw2100_wx_get_range(struct net_device *dev,
 
        /* Set the Wireless Extension versions */
        range->we_version_compiled = WIRELESS_EXT;
-       range->we_version_source = 16;
+       range->we_version_source = 18;
 
 //      range->retry_capa;      /* What retry options are supported */
 //      range->retry_flags;     /* How to decode max/min retry limit */
@@ -7184,6 +7184,9 @@ static int ipw2100_wx_get_range(struct net_device *dev,
                                IW_EVENT_CAPA_MASK(SIOCGIWAP));
        range->event_capa[1] = IW_EVENT_CAPA_K_1;
 
+       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+               IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
        IPW_DEBUG_WX("GET Range\n");
 
        return 0;
index 531b0731314162e4afea759d8e52ada9bb11a1f8..b2e8e49c865987e42f4a3e9a9d9c0e5f353df1e4 100644 (file)
@@ -43,13 +43,16 @@ static void process_task_mortuary(void);
  * list for processing. Only after two full buffer syncs
  * does the task eventually get freed, because by then
  * we are sure we will not reference it again.
+ * Can be invoked from softirq via RCU callback due to
+ * call_rcu() of the task struct, hence the _irqsave.
  */
 static int task_free_notify(struct notifier_block * self, unsigned long val, void * data)
 {
+       unsigned long flags;
        struct task_struct * task = data;
-       spin_lock(&task_mortuary);
+       spin_lock_irqsave(&task_mortuary, flags);
        list_add(&task->tasks, &dying_tasks);
-       spin_unlock(&task_mortuary);
+       spin_unlock_irqrestore(&task_mortuary, flags);
        return NOTIFY_OK;
 }
 
@@ -431,25 +434,22 @@ static void increment_tail(struct oprofile_cpu_buffer * b)
  */
 static void process_task_mortuary(void)
 {
-       struct list_head * pos;
-       struct list_head * pos2;
+       unsigned long flags;
+       LIST_HEAD(local_dead_tasks);
        struct task_struct * task;
+       struct task_struct * ttask;
 
-       spin_lock(&task_mortuary);
+       spin_lock_irqsave(&task_mortuary, flags);
 
-       list_for_each_safe(pos, pos2, &dead_tasks) {
-               task = list_entry(pos, struct task_struct, tasks);
-               list_del(&task->tasks);
-               free_task(task);
-       }
+       list_splice_init(&dead_tasks, &local_dead_tasks);
+       list_splice_init(&dying_tasks, &dead_tasks);
 
-       list_for_each_safe(pos, pos2, &dying_tasks) {
-               task = list_entry(pos, struct task_struct, tasks);
+       spin_unlock_irqrestore(&task_mortuary, flags);
+
+       list_for_each_entry_safe(task, ttask, &local_dead_tasks, tasks) {
                list_del(&task->tasks);
-               list_add_tail(&task->tasks, &dead_tasks);
+               free_task(task);
        }
-
-       spin_unlock(&task_mortuary);
 }
 
 
index 026f671ea55870bcecfe82e510004d33967eb5ad..78193e4bbdb564981a98b00437bdad6a8b851500 100644 (file)
@@ -52,7 +52,8 @@ int alloc_cpu_buffers(void)
        for_each_online_cpu(i) {
                struct oprofile_cpu_buffer * b = &cpu_buffer[i];
  
-               b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size);
+               b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size,
+                       cpu_to_node(i));
                if (!b->buffer)
                        goto fail;
  
index b8241561da4592877609bd8dc9d43c166c88ce1f..a665951b1586c4e53d4f280407cf7c27615f9fdf 100644 (file)
@@ -34,7 +34,7 @@ config PARPORT
 
 config PARPORT_PC
        tristate "PC-style hardware"
-       depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R
+       depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV
        ---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 18e85ccdae67f633cab56bf115979af028eb1723..9302b8fd7461ffec629acf9b351bba81158cd0ed 100644 (file)
@@ -2371,8 +2371,10 @@ void parport_pc_unregister_port (struct parport *p)
        spin_lock(&ports_lock);
        list_del_init(&priv->list);
        spin_unlock(&ports_lock);
+#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA)
        if (p->dma != PARPORT_DMA_NONE)
                free_dma(p->dma);
+#endif
        if (p->irq != PARPORT_IRQ_NONE)
                free_irq(p->irq, p);
        release_region(p->base, 3);
@@ -2380,13 +2382,11 @@ void parport_pc_unregister_port (struct parport *p)
                release_region(p->base + 3, p->size - 3);
        if (p->modes & PARPORT_MODE_ECP)
                release_region(p->base_hi, 3);
-#ifdef CONFIG_PARPORT_PC_FIFO
-#ifdef HAS_DMA
+#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA)
        if (priv->dma_buf)
                pci_free_consistent(priv->dev, PAGE_SIZE,
                                    priv->dma_buf,
                                    priv->dma_handle);
-#endif
 #endif
        kfree (p->private_data);
        parport_put_port(p);
index 6a61b9f286e14a320e59815dfcaf53832bea93e3..0aac6a61337d166c0d8c10f2a8e9e32aa6f2705d 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/sched.h>               /* signal_pending() */
 #include <linux/pcieport_if.h>
 #include "pci_hotplug.h"
 
index 0b8b26beb1636ca5875d24e6891504ac81f33899..ac1e495c314ead9d803658a0ae296f4010c56898 100644 (file)
@@ -30,6 +30,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/signal.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
index 4f7ed4bd3be93d2f4870090ec5911e264afde7bd..94e30fe4b8f3242b17f8adc5c1623669d2a513b6 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
 
 #include "rio.h"
 
index 30a11436e2411acd05f20d019bbf4e1f96791348..bef9316e95df8b610302f0716f930b52bae383c7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/rio.h>
 #include <linux/rio_drv.h>
 #include <linux/stat.h>
+#include <linux/sched.h>       /* for capable() */
 
 #include "rio.h"
 
index 3ca1011ceaac7fa24b6b2e42c2365201d9495188..5e382470faa27fdb538e263ed6e83dee556d7f47 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/rio_regs.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
 
 #include "rio.h"
 
index f779f674dfa0414b498f1cf0be497e4a87a89291..2472fa1a1be14c72a6e324ec28e42070ea4fb253 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/buffer_head.h>
+#include <linux/hdreg.h>
 
 #include <asm/ccwdev.h>
 #include <asm/ebcdic.h>
@@ -1723,12 +1724,34 @@ dasd_release(struct inode *inp, struct file *filp)
        return 0;
 }
 
+/*
+ * Return disk geometry.
+ */
+static int
+dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       struct dasd_device *device;
+
+       device = bdev->bd_disk->private_data;
+       if (!device)
+               return -ENODEV;
+
+       if (!device->discipline ||
+           !device->discipline->fill_geometry)
+               return -EINVAL;
+
+       device->discipline->fill_geometry(device, geo);
+       geo->start = get_start_sect(bdev) >> device->s2b_shift;
+       return 0;
+}
+
 struct block_device_operations
 dasd_device_operations = {
        .owner          = THIS_MODULE,
        .open           = dasd_open,
        .release        = dasd_release,
        .ioctl          = dasd_ioctl,
+       .getgeo         = dasd_getgeo,
 };
 
 
index 044b7537199075b132c73047c7a29078b7659ae7..8e4dcd58599eb7ba4db58377865fa0eef8684296 100644 (file)
@@ -485,33 +485,6 @@ dasd_ioctl_set_ro(struct block_device *bdev, int no, long args)
        return rc;
 }
 
-/*
- * Return disk geometry.
- */
-static int
-dasd_ioctl_getgeo(struct block_device *bdev, int no, long args)
-{
-       struct hd_geometry geo = { 0, };
-       struct dasd_device *device;
-
-       device =  bdev->bd_disk->private_data;
-       if (device == NULL)
-               return -ENODEV;
-
-       if (device == NULL || device->discipline == NULL ||
-           device->discipline->fill_geometry == NULL)
-               return -EINVAL;
-
-       geo = (struct hd_geometry) {};
-       device->discipline->fill_geometry(device, &geo);
-       geo.start = get_start_sect(bdev) >> device->s2b_shift;
-       if (copy_to_user((struct hd_geometry __user *) args, &geo,
-                        sizeof (struct hd_geometry)))
-               return -EFAULT;
-
-       return 0;
-}
-
 /*
  * List of static ioctls.
  */
@@ -528,7 +501,6 @@ static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] =
        { BIODASDPRRST, dasd_ioctl_reset_profile },
        { BLKROSET, dasd_ioctl_set_ro },
        { DASDAPIVER, dasd_ioctl_api_version },
-       { HDIO_GETGEO, dasd_ioctl_getgeo },
        { -1, NULL }
 };
 
index bf3a67c3cc5e6b0cb44599602fd23aa64bf22d2f..54ecd548c3185b1aac9a78e7343b079bce771ea9 100644 (file)
@@ -328,31 +328,27 @@ fail:
        return 0;
 }
 
-static int xpram_ioctl (struct inode *inode, struct file *filp,
-                unsigned int cmd, unsigned long arg)
+static int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct hd_geometry __user *geo;
        unsigned long size;
-       if (cmd != HDIO_GETGEO)
-               return -EINVAL;
+
        /*
         * get geometry: we have to fake one...  trim the size to a
         * multiple of 64 (32k): tell we have 16 sectors, 4 heads,
         * whatever cylinders. Tell also that data starts at sector. 4.
         */
-       geo = (struct hd_geometry __user *) arg;
        size = (xpram_pages * 8) & ~0x3f;
-       put_user(size >> 6, &geo->cylinders);
-       put_user(4, &geo->heads);
-       put_user(16, &geo->sectors);
-       put_user(4, &geo->start);
+       geo->cylinders = size >> 6;
+       geo->heads = 4;
+       geo->sectors = 16;
+       geo->start = 4;
        return 0;
 }
 
 static struct block_device_operations xpram_devops =
 {
        .owner  = THIS_MODULE,
-       .ioctl  = xpram_ioctl,
+       .getgeo = xpram_getgeo,
 };
 
 /*
index 932dcf0366ebf9a215e38defed99d05a089ae8d0..311a4122bd7094b6ddd49af223abe08d3a40dc01 100644 (file)
@@ -432,11 +432,12 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
        struct Scsi_Host *host;
        void *dma_cmd_space;
        unsigned char *clkprop;
-       int proplen;
+       int proplen, rc = -ENODEV;
 
        if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
-               printk(KERN_ERR "mac53c94: expected 2 addrs and intrs (got %d/%d)\n",
-                      node->n_addrs, node->n_intrs);
+               printk(KERN_ERR "mac53c94: expected 2 addrs and intrs"
+                      " (got %d/%d)\n",
+                      macio_resource_count(mdev), macio_irq_count(mdev));
                return -ENODEV;
        }
 
@@ -448,6 +449,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
                host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state));
        if (host == NULL) {
                printk(KERN_ERR "mac53c94: couldn't register host");
+               rc = -ENOMEM;
                goto out_release;
        }
 
@@ -486,6 +488,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
                if (dma_cmd_space == 0) {
                        printk(KERN_ERR "mac53c94: couldn't allocate dma "
                               "command space for %s\n", node->full_name);
+               rc = -ENOMEM;
                        goto out_free;
                }
        state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space);
@@ -495,18 +498,21 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
 
        mac53c94_init(state);
 
-       if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94", state)) {
+       if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94",state)) {
                printk(KERN_ERR "mac53C94: can't get irq %d for %s\n",
                       state->intr, node->full_name);
                goto out_free_dma;
        }
 
-       /* XXX FIXME: handle failure */
-       scsi_add_host(host, &mdev->ofdev.dev);
-       scsi_scan_host(host);
+       rc = scsi_add_host(host, &mdev->ofdev.dev);
+       if (rc != 0)
+               goto out_release_irq;
 
+       scsi_scan_host(host);
        return 0;
 
+ out_release_irq:
+       free_irq(state->intr, state);
  out_free_dma:
        kfree(state->dma_cmd_space);
  out_free:
@@ -518,7 +524,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
  out_release:
        macio_release_resources(mdev);
 
-       return  -ENODEV;
+       return rc;
 }
 
 static int mac53c94_remove(struct macio_dev *mdev)
index bdccf73cf9fe246d880c9b4e2efbd48b5ec5820f..d6d2125f9044452d6f55a0721bf628cc16130dc9 100644 (file)
@@ -1869,7 +1869,8 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
 
        if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
                        printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
-                      " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs);
+                      " (got %d,%d)\n", macio_resource_count(mdev),
+                      macio_irq_count(mdev));
                return -ENODEV;
        }
 
index c0cf52cb975a9386ba7a4b03ec54fcfb35caa08c..bbbb55eeb73a521d52797bf9da858fbad7040911 100644 (file)
  *  NV-specific details such as register offsets, SATA phy location,
  *  hotplug info, etc.
  *
+ *  0.10
+ *     - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB
+ *       drive.  Also made the check_hotplug() callbacks return whether there
+ *       was a hotplug interrupt or not.  This was not the source of the
+ *       spurious interrupts, but is the right thing to do anyway.
+ *
  *  0.09
  *     - Fixed bug introduced by 0.08's MCP51 and MCP55 support.
  *
@@ -124,10 +130,10 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void nv_host_stop (struct ata_host_set *host_set);
 static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
 static void nv_disable_hotplug(struct ata_host_set *host_set);
-static void nv_check_hotplug(struct ata_host_set *host_set);
+static int nv_check_hotplug(struct ata_host_set *host_set);
 static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
 static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
-static void nv_check_hotplug_ck804(struct ata_host_set *host_set);
+static int nv_check_hotplug_ck804(struct ata_host_set *host_set);
 
 enum nv_host_type
 {
@@ -176,7 +182,7 @@ struct nv_host_desc
        enum nv_host_type       host_type;
        void                    (*enable_hotplug)(struct ata_probe_ent *probe_ent);
        void                    (*disable_hotplug)(struct ata_host_set *host_set);
-       void                    (*check_hotplug)(struct ata_host_set *host_set);
+       int                     (*check_hotplug)(struct ata_host_set *host_set);
 
 };
 static struct nv_host_desc nv_device_tbl[] = {
@@ -309,12 +315,16 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
                        qc = ata_qc_from_tag(ap, ap->active_tag);
                        if (qc && (!(qc->tf.ctl & ATA_NIEN)))
                                handled += ata_host_intr(ap, qc);
+                       else
+                               // No request pending?  Clear interrupt status
+                               // anyway, in case there's one pending.
+                               ap->ops->check_status(ap);
                }
 
        }
 
        if (host->host_desc->check_hotplug)
-               host->host_desc->check_hotplug(host_set);
+               handled += host->host_desc->check_hotplug(host_set);
 
        spin_unlock_irqrestore(&host_set->lock, flags);
 
@@ -497,7 +507,7 @@ static void nv_disable_hotplug(struct ata_host_set *host_set)
        outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
 }
 
-static void nv_check_hotplug(struct ata_host_set *host_set)
+static int nv_check_hotplug(struct ata_host_set *host_set)
 {
        u8 intr_status;
 
@@ -522,7 +532,11 @@ static void nv_check_hotplug(struct ata_host_set *host_set)
                if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
                        printk(KERN_WARNING "nv_sata: "
                                "Secondary device removed\n");
+
+               return 1;
        }
+
+       return 0;
 }
 
 static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
@@ -560,7 +574,7 @@ static void nv_disable_hotplug_ck804(struct ata_host_set *host_set)
        pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
 }
 
-static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
+static int nv_check_hotplug_ck804(struct ata_host_set *host_set)
 {
        u8 intr_status;
 
@@ -585,7 +599,11 @@ static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
                if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
                        printk(KERN_WARNING "nv_sata: "
                                "Secondary device removed\n");
+
+               return 1;
        }
+
+       return 0;
 }
 
 static int __init nv_init(void)
index 180676d7115a5861007e92dd9f34a85098d4ad59..ee5f4dfdab149b7d5a52bf9d624d862c6d82233c 100644 (file)
@@ -69,7 +69,6 @@
 #include "scsi_logging.h"
 
 static void scsi_done(struct scsi_cmnd *cmd);
-static int scsi_retry_command(struct scsi_cmnd *cmd);
 
 /*
  * Definitions and constants.
@@ -752,7 +751,7 @@ static void scsi_done(struct scsi_cmnd *cmd)
  * isn't running --- used by scsi_times_out */
 void __scsi_done(struct scsi_cmnd *cmd)
 {
-       unsigned long flags;
+       struct request *rq = cmd->request;
 
        /*
         * Set the serial numbers back to zero
@@ -763,71 +762,14 @@ void __scsi_done(struct scsi_cmnd *cmd)
        if (cmd->result)
                atomic_inc(&cmd->device->ioerr_cnt);
 
+       BUG_ON(!rq);
+
        /*
-        * Next, enqueue the command into the done queue.
-        * It is a per-CPU queue, so we just disable local interrupts
-        * and need no spinlock.
+        * The uptodate/nbytes values don't matter, as we allow partial
+        * completes and thus will check this in the softirq callback
         */
-       local_irq_save(flags);
-       list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q));
-       raise_softirq_irqoff(SCSI_SOFTIRQ);
-       local_irq_restore(flags);
-}
-
-/**
- * scsi_softirq - Perform post-interrupt processing of finished SCSI commands.
- *
- * This is the consumer of the done queue.
- *
- * This is called with all interrupts enabled.  This should reduce
- * interrupt latency, stack depth, and reentrancy of the low-level
- * drivers.
- */
-static void scsi_softirq(struct softirq_action *h)
-{
-       int disposition;
-       LIST_HEAD(local_q);
-
-       local_irq_disable();
-       list_splice_init(&__get_cpu_var(scsi_done_q), &local_q);
-       local_irq_enable();
-
-       while (!list_empty(&local_q)) {
-               struct scsi_cmnd *cmd = list_entry(local_q.next,
-                                                  struct scsi_cmnd, eh_entry);
-               /* The longest time any command should be outstanding is the
-                * per command timeout multiplied by the number of retries.
-                *
-                * For a typical command, this is 2.5 minutes */
-               unsigned long wait_for 
-                       = cmd->allowed * cmd->timeout_per_command;
-               list_del_init(&cmd->eh_entry);
-
-               disposition = scsi_decide_disposition(cmd);
-               if (disposition != SUCCESS &&
-                   time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
-                       sdev_printk(KERN_ERR, cmd->device,
-                                   "timing out command, waited %lus\n",
-                                   wait_for/HZ);
-                       disposition = SUCCESS;
-               }
-                       
-               scsi_log_completion(cmd, disposition);
-               switch (disposition) {
-               case SUCCESS:
-                       scsi_finish_command(cmd);
-                       break;
-               case NEEDS_RETRY:
-                       scsi_retry_command(cmd);
-                       break;
-               case ADD_TO_MLQUEUE:
-                       scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
-                       break;
-               default:
-                       if (!scsi_eh_scmd_add(cmd, 0))
-                               scsi_finish_command(cmd);
-               }
-       }
+       rq->completion_data = cmd;
+       blk_complete_request(rq);
 }
 
 /*
@@ -840,7 +782,7 @@ static void scsi_softirq(struct softirq_action *h)
  *              level drivers should not become re-entrant as a result of
  *              this.
  */
-static int scsi_retry_command(struct scsi_cmnd *cmd)
+int scsi_retry_command(struct scsi_cmnd *cmd)
 {
        /*
         * Restore the SCSI command state.
@@ -1273,38 +1215,6 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery)
 }
 EXPORT_SYMBOL(scsi_device_cancel);
 
-#ifdef CONFIG_HOTPLUG_CPU
-static int scsi_cpu_notify(struct notifier_block *self,
-                          unsigned long action, void *hcpu)
-{
-       int cpu = (unsigned long)hcpu;
-
-       switch(action) {
-       case CPU_DEAD:
-               /* Drain scsi_done_q. */
-               local_irq_disable();
-               list_splice_init(&per_cpu(scsi_done_q, cpu),
-                                &__get_cpu_var(scsi_done_q));
-               raise_softirq_irqoff(SCSI_SOFTIRQ);
-               local_irq_enable();
-               break;
-       default:
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block __devinitdata scsi_cpu_nb = {
-       .notifier_call  = scsi_cpu_notify,
-};
-
-#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb)
-#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb)
-#else
-#define register_scsi_cpu()
-#define unregister_scsi_cpu()
-#endif /* CONFIG_HOTPLUG_CPU */
-
 MODULE_DESCRIPTION("SCSI core");
 MODULE_LICENSE("GPL");
 
@@ -1338,8 +1248,6 @@ static int __init init_scsi(void)
                INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
 
        devfs_mk_dir("scsi");
-       open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
-       register_scsi_cpu();
        printk(KERN_NOTICE "SCSI subsystem initialized\n");
        return 0;
 
@@ -1367,7 +1275,6 @@ static void __exit exit_scsi(void)
        devfs_remove("scsi");
        scsi_exit_procfs();
        scsi_exit_queue();
-       unregister_scsi_cpu();
 }
 
 subsys_initcall(init_scsi);
index ba93d6e66d481506dc065c5763eb53f6f91fed7e..00c9bf383e2309f357ae0e23416c0b27557ebc53 100644 (file)
@@ -1493,6 +1493,41 @@ static void scsi_kill_request(struct request *req, request_queue_t *q)
        __scsi_done(cmd);
 }
 
+static void scsi_softirq_done(struct request *rq)
+{
+       struct scsi_cmnd *cmd = rq->completion_data;
+       unsigned long wait_for = cmd->allowed * cmd->timeout_per_command;
+       int disposition;
+
+       INIT_LIST_HEAD(&cmd->eh_entry);
+
+       disposition = scsi_decide_disposition(cmd);
+       if (disposition != SUCCESS &&
+           time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
+               sdev_printk(KERN_ERR, cmd->device,
+                           "timing out command, waited %lus\n",
+                           wait_for/HZ);
+               disposition = SUCCESS;
+       }
+                       
+       scsi_log_completion(cmd, disposition);
+
+       switch (disposition) {
+               case SUCCESS:
+                       scsi_finish_command(cmd);
+                       break;
+               case NEEDS_RETRY:
+                       scsi_retry_command(cmd);
+                       break;
+               case ADD_TO_MLQUEUE:
+                       scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+                       break;
+               default:
+                       if (!scsi_eh_scmd_add(cmd, 0))
+                               scsi_finish_command(cmd);
+       }
+}
+
 /*
  * Function:    scsi_request_fn()
  *
@@ -1667,6 +1702,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
        blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
        blk_queue_segment_boundary(q, shost->dma_boundary);
        blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+       blk_queue_softirq_done(q, scsi_softirq_done);
 
        if (!shost->use_clustering)
                clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
index f04e7e11f57a884ac08766e670aa82a81c8d5125..14a6198cb8d2b6ad3cf4635019a8f5caf8e5085b 100644 (file)
@@ -44,6 +44,7 @@ extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
                struct scsi_request *sreq);
 extern void __scsi_release_request(struct scsi_request *sreq);
 extern void __scsi_done(struct scsi_cmnd *cmd);
+extern int scsi_retry_command(struct scsi_cmnd *cmd);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
index 32d4d8d7b9f393e6524153ac7a71c9c00784116c..4c5127ed379c6560dd22e17e0aa408b7b51979f8 100644 (file)
@@ -527,7 +527,7 @@ static int sd_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user *loc)
+static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
        struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
        struct scsi_device *sdp = sdkp->device;
@@ -545,15 +545,9 @@ static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user *
        else
                scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
 
-       if (put_user(diskinfo[0], &loc->heads))
-               return -EFAULT;
-       if (put_user(diskinfo[1], &loc->sectors))
-               return -EFAULT;
-       if (put_user(diskinfo[2], &loc->cylinders))
-               return -EFAULT;
-       if (put_user((unsigned)get_start_sect(bdev),
-                    (unsigned long __user *)&loc->start))
-               return -EFAULT;
+       geo->heads = diskinfo[0];
+       geo->sectors = diskinfo[1];
+       geo->cylinders = diskinfo[2];
        return 0;
 }
 
@@ -593,12 +587,6 @@ static int sd_ioctl(struct inode * inode, struct file * filp,
        if (!scsi_block_when_processing_errors(sdp) || !error)
                return error;
 
-       if (cmd == HDIO_GETGEO) {
-               if (!arg)
-                       return -EINVAL;
-               return sd_hdio_getgeo(bdev, p);
-       }
-
        /*
         * Send SCSI addressing ioctls directly to mid level, send other
         * ioctls to block level and then onto mid level if they can't be
@@ -800,6 +788,7 @@ static struct block_device_operations sd_fops = {
        .open                   = sd_open,
        .release                = sd_release,
        .ioctl                  = sd_ioctl,
+       .getgeo                 = sd_getgeo,
 #ifdef CONFIG_COMPAT
        .compat_ioctl           = sd_compat_ioctl,
 #endif
index 221e96e2620a66f3b9cb264e9c387c85f9ef7add..78aad9582bcfbef87399ac33e02fa60b39712cdc 100644 (file)
@@ -2493,7 +2493,7 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
        }
        if (resp) {
                if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-                       memset(resp, 0, resSz);
+                       memset(page_address(resp), 0, resSz);
                if (retSzp)
                        *retSzp = resSz;
        }
index 987d22b53c220966152eb22a2b92b07d00517f07..16af5626c243bedba451412e5c77abbdbba7f107 100644 (file)
@@ -608,7 +608,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
 
                p = cpm2cpu_addr(bdp->cbd_bufaddr);
 
-               *p++ = xmit->buf[xmit->tail];
+               *p++ = port->x_char;
                bdp->cbd_datlen = 1;
                bdp->cbd_sc |= BD_SC_READY;
                /* Get next BD. */
index 5ddd8ab1f108afb3af7b3acd0e38bc142c026c5f..ea24129eb6b9f50911c960524af4650dc023202a 100644 (file)
@@ -1431,11 +1431,14 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
                char    name[1];
        } *slots;
        int len;
+       struct resource r_ports, r_rxdma, r_txdma;
 
        /*
         * Request & map chip registers
         */
-       uap->port.mapbase = np->addrs[0].address;
+       if (of_address_to_resource(np, 0, &r_ports))
+               return -ENODEV;
+       uap->port.mapbase = r_ports.start;
        uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
       
        uap->control_reg = uap->port.membase;
@@ -1445,16 +1448,20 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
         * Request & map DBDMA registers
         */
 #ifdef HAS_DBDMA
-       if (np->n_addrs >= 3 && np->n_intrs >= 3)
+       if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
+           of_address_to_resource(np, 2, &r_rxdma) == 0)
                uap->flags |= PMACZILOG_FLAG_HAS_DMA;
+#else
+       memset(&r_txdma, 0, sizeof(struct resource));
+       memset(&r_rxdma, 0, sizeof(struct resource));
 #endif 
        if (ZS_HAS_DMA(uap)) {
-               uap->tx_dma_regs = ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
+               uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
                if (uap->tx_dma_regs == NULL) { 
                        uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
                        goto no_dma;
                }
-               uap->rx_dma_regs = ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
+               uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
                if (uap->rx_dma_regs == NULL) { 
                        iounmap(uap->tx_dma_regs);
                        uap->tx_dma_regs = NULL;
index c44bbedec817df655b7b61e12b0433818e7abdc4..4ddc453023a264362f8681d9ec050678da877dba 100644 (file)
@@ -186,7 +186,7 @@ static void update_bus(struct dentry *bus)
 
        down(&bus->d_inode->i_sem);
 
-       list_for_each_entry(dev, &bus->d_subdirs, d_child)
+       list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child)
                if (dev->d_inode)
                        update_dev(dev);
 
@@ -203,7 +203,7 @@ static void update_sb(struct super_block *sb)
 
        down(&root->d_inode->i_sem);
 
-       list_for_each_entry(bus, &root->d_subdirs, d_child) {
+       list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) {
                if (bus->d_inode) {
                        switch (S_IFMT & bus->d_inode->i_mode) {
                        case S_IFDIR:
@@ -319,7 +319,7 @@ static int usbfs_empty (struct dentry *dentry)
        spin_lock(&dcache_lock);
 
        list_for_each(list, &dentry->d_subdirs) {
-               struct dentry *de = list_entry(list, struct dentry, d_child);
+               struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
                if (usbfs_positive(de)) {
                        spin_unlock(&dcache_lock);
                        return 0;
index d9cf3b327d96e14a3a5840126cc404659a703f3f..77cd6ac07e3c5d4076129c13aad23211197db4ab 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <linux/platform_device.h>
+#include <linux/signal.h>
 
 #include <asm/mach-au1x00/au1000.h>
 
index 3959ccc88332fb07e8e6f7f037c41fcbc73ffa8e..0020ed7a39d0c9eada4b93d54115bf160353651c 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/platform_device.h>
+#include <linux/signal.h>
 
 #include <asm/hardware.h>
 
index 2ec6a78bd65e6673113141fcf68fb35305a055d3..b2a8dfa488707e78d92caffd7242d371b59cc257 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/platform_device.h>
+#include <linux/signal.h>
 
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
index 6a5700e9d4280eb7575426be882920953f1705dd..25646804d5be012c0e121bf0e44eb6b943162272 100644 (file)
@@ -127,6 +127,7 @@ static struct file_operations usb_dsbr100_fops = {
        .open =         usb_dsbr100_open,
        .release =      usb_dsbr100_close,
        .ioctl =        usb_dsbr100_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .llseek =       no_llseek,
 };
 
index 3a0e8ce67ebedc10c22b38a224db5b3fcad63fc1..8af665bbe330b40478b7d2588a263ccc8849f739 100644 (file)
@@ -4774,6 +4774,7 @@ static struct file_operations ov511_fops = {
        .read =         ov51x_v4l1_read,
        .mmap =         ov51x_v4l1_mmap,
        .ioctl =        ov51x_v4l1_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .llseek =       no_llseek,
 };
 
index 09ca6128ac209a213ca76e2c656d1daca2d662ac..4f9b0dc6fd7bdd6fd22e71588c23b045c2747ec2 100644 (file)
@@ -154,6 +154,7 @@ static struct file_operations pwc_fops = {
        .poll =         pwc_video_poll,
        .mmap =         pwc_video_mmap,
        .ioctl =        pwc_video_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .llseek =       no_llseek,
 };
 static struct video_device pwc_template = {
index b2ae29af59404f89434b7e5d7f1f2d7cd229d7cc..2ba562285fda9b42c3e39f5d3f376e0332c1907e 100644 (file)
@@ -1193,6 +1193,7 @@ static struct file_operations se401_fops = {
         .read =         se401_read,
         .mmap =         se401_mmap,
        .ioctl =        se401_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .llseek =       no_llseek,
 };
 static struct video_device se401_template = {
index 774038b352cd1e7644eb42c97fc0cbe9e877fc89..b497a6a0a2060eccf5ff81da5ef558728d2f9f84 100644 (file)
@@ -1343,6 +1343,7 @@ static struct file_operations stv680_fops = {
        .read =         stv680_read,
        .mmap =         stv680_mmap,
        .ioctl =        stv680_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .llseek =       no_llseek,
 };
 static struct video_device stv680_template = {
index 4bd113325ef9b1441d7b244a7cb2ea8b106a69e1..63a72e550a1bd049d0346d10d1ea440554d5354f 100644 (file)
@@ -953,6 +953,7 @@ static struct file_operations usbvideo_fops = {
        .read =   usbvideo_v4l_read,
        .mmap =   usbvideo_v4l_mmap,
        .ioctl =  usbvideo_v4l_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .llseek = no_llseek,
 };
 static const struct video_device usbvideo_template = {
index 1c73155c8d772cda08a5ca0934021161488563bd..5df1440738712622a3570ccbe154f4816c2258c1 100644 (file)
@@ -1236,6 +1236,7 @@ static struct file_operations vicam_fops = {
        .read           = vicam_read,
        .mmap           = vicam_mmap,
        .ioctl          = vicam_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
index 3605a6f3067b0b7602fff8f4fac14402287d1c47..bff9434c8e5578fcf0648dc6c6e09356e61613aa 100644 (file)
@@ -3490,6 +3490,7 @@ static struct file_operations w9968cf_fops = {
        .release = w9968cf_release,
        .read =    w9968cf_read,
        .ioctl =   w9968cf_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .mmap =    w9968cf_mmap,
        .llseek =  no_llseek,
 };
index cc8e3bf5001b44e5393ae7783427fe2ad3204cbf..3f04427c9026ed6b741bae3de1883cb313b689d4 100644 (file)
@@ -1151,7 +1151,7 @@ config FB_VOODOO1
 
 config FB_CYBLA
        tristate "Cyberblade/i1 support"
-       depends on FB && PCI
+       depends on FB && PCI && X86_32 && !64BIT
        select FB_CFB_IMAGEBLIT
        select VIDEO_SELECT
        ---help---
index a5d09e159cd111d80d12754e1f08afccc39e8268..6ee449858a5c90501c336df4be5601e1840628c1 100644 (file)
@@ -6,7 +6,7 @@ menu "Console display driver support"
 
 config VGA_CONSOLE
        bool "VGA text console" if EMBEDDED || !X86
-       depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !ARCH_VERSATILE
+       depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE
        default y
        help
          Saying Y here will allow you to use Linux in text mode through a
index 167de397e4b430def9bb9b470153842a8d5803dc..12d9329d1408bc4201fc07bb9d7d0ac0af15ad0f 100644 (file)
@@ -56,6 +56,8 @@
 static DEFINE_SPINLOCK(vga_lock);
 static int cursor_size_lastfrom;
 static int cursor_size_lastto;
+static u32 vgacon_xres;
+static u32 vgacon_yres;
 static struct vgastate state;
 
 #define BLANK 0x0020
@@ -69,7 +71,7 @@ static struct vgastate state;
  * appear.
  */
 #undef TRIDENT_GLITCH
-
+#define VGA_FONTWIDTH       8   /* VGA does not support fontwidths != 8 */
 /*
  *  Interface used by the world
  */
@@ -325,6 +327,10 @@ static const char __init *vgacon_startup(void)
                vga_scan_lines =
                    vga_video_font_height * vga_video_num_lines;
        }
+
+       vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH;
+       vgacon_yres = vga_scan_lines;
+
        return display_desc;
 }
 
@@ -503,10 +509,18 @@ static int vgacon_doresize(struct vc_data *c,
 {
        unsigned long flags;
        unsigned int scanlines = height * c->vc_font.height;
-       u8 scanlines_lo, r7, vsync_end, mode;
+       u8 scanlines_lo, r7, vsync_end, mode, max_scan;
 
        spin_lock_irqsave(&vga_lock, flags);
 
+       outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
+       max_scan = inb_p(vga_video_port_val);
+
+       if (max_scan & 0x80)
+               scanlines <<= 1;
+
+       vgacon_xres = width * VGA_FONTWIDTH;
+       vgacon_yres = height * c->vc_font.height;
        outb_p(VGA_CRTC_MODE, vga_video_port_reg);
        mode = inb_p(vga_video_port_val);
 
@@ -551,6 +565,10 @@ static int vgacon_doresize(struct vc_data *c,
 
 static int vgacon_switch(struct vc_data *c)
 {
+       int x = c->vc_cols * VGA_FONTWIDTH;
+       int y = c->vc_rows * c->vc_font.height;
+       int rows = ORIG_VIDEO_LINES * vga_default_font_height/
+               c->vc_font.height;
        /*
         * We need to save screen size here as it's the only way
         * we can spot the screen has been resized and we need to
@@ -566,10 +584,11 @@ static int vgacon_switch(struct vc_data *c)
                scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
                            c->vc_screenbuf_size > vga_vram_size ?
                                vga_vram_size : c->vc_screenbuf_size);
-               if (!(vga_video_num_columns % 2) &&
-                   vga_video_num_columns <= ORIG_VIDEO_COLS &&
-                   vga_video_num_lines <= (ORIG_VIDEO_LINES *
-                       vga_default_font_height) / c->vc_font.height)
+
+               if ((vgacon_xres != x || vgacon_yres != y) &&
+                   (!(vga_video_num_columns % 2) &&
+                    vga_video_num_columns <= ORIG_VIDEO_COLS &&
+                    vga_video_num_lines <= rows))
                        vgacon_doresize(c, c->vc_cols, c->vc_rows);
        }
 
@@ -993,7 +1012,8 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigne
        if (vga_video_type < VIDEO_TYPE_EGAM)
                return -EINVAL;
 
-       if (font->width != 8 || (charcount != 256 && charcount != 512))
+       if (font->width != VGA_FONTWIDTH ||
+           (charcount != 256 && charcount != 512))
                return -EINVAL;
 
        rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
@@ -1010,7 +1030,7 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font)
        if (vga_video_type < VIDEO_TYPE_EGAM)
                return -EINVAL;
 
-       font->width = 8;
+       font->width = VGA_FONTWIDTH;
        font->height = c->vc_font.height;
        font->charcount = vga_512_chars ? 512 : 256;
        if (!font->data)
index 403d17377f8db67fce024dbf52e4091225e6a743..03798e9c882d813d2ab0a62a1b85f5e3272273f8 100644 (file)
@@ -133,12 +133,6 @@ static int controlfb_mmap(struct fb_info *info, struct file *file,
 static int controlfb_set_par (struct fb_info *info);
 static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
 
-/*
- * inititialization
- */
-int control_init(void);
-void control_setup(char *);
-
 /******************** Prototypes for internal functions **********************/
 
 static void set_control_clock(unsigned char *params);
@@ -550,9 +544,46 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro
 
 
 /*
- * Called from fbmem.c for probing & initializing
+ * Parse user speficied options (`video=controlfb:')
  */
-int __init control_init(void)
+static void __init control_setup(char *options)
+{
+       char *this_opt;
+
+       if (!options || !*options)
+               return;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!strncmp(this_opt, "vmode:", 6)) {
+                       int vmode = simple_strtoul(this_opt+6, NULL, 0);
+                       if (vmode > 0 && vmode <= VMODE_MAX &&
+                           control_mac_modes[vmode - 1].m[1] >= 0)
+                               default_vmode = vmode;
+               } else if (!strncmp(this_opt, "cmode:", 6)) {
+                       int depth = simple_strtoul(this_opt+6, NULL, 0);
+                       switch (depth) {
+                        case CMODE_8:
+                        case CMODE_16:
+                        case CMODE_32:
+                               default_cmode = depth;
+                               break;
+                        case 8:
+                               default_cmode = CMODE_8;
+                               break;
+                        case 15:
+                        case 16:
+                               default_cmode = CMODE_16;
+                               break;
+                        case 24:
+                        case 32:
+                               default_cmode = CMODE_32;
+                               break;
+                       }
+               }
+       }
+}
+
+static int __init control_init(void)
 {
        struct device_node *dp;
        char *option = NULL;
@@ -651,15 +682,16 @@ static void __init find_vram_size(struct fb_info_control *p)
 static int __init control_of_init(struct device_node *dp)
 {
        struct fb_info_control  *p;
-       unsigned long           addr;
-       int                     i;
+       struct resource         fb_res, reg_res;
 
        if (control_fb) {
                printk(KERN_ERR "controlfb: only one control is supported\n");
                return -ENXIO;
        }
-       if(dp->n_addrs != 2) {
-               printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs);
+
+       if (of_pci_address_to_resource(dp, 2, &fb_res) ||
+           of_pci_address_to_resource(dp, 1, &reg_res)) {
+               printk(KERN_ERR "can't get 2 addresses for control\n");
                return -ENXIO;
        }
        p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -669,18 +701,12 @@ static int __init control_of_init(struct device_node *dp)
        memset(p, 0, sizeof(*p));
 
        /* Map in frame buffer and registers */
-       for (i = 0; i < dp->n_addrs; ++i) {
-               addr = dp->addrs[i].address;
-               if (dp->addrs[i].size >= 0x800000) {
-                       p->fb_orig_base = addr;
-                       p->fb_orig_size = dp->addrs[i].size;
-                       /* use the big-endian aperture (??) */
-                       p->frame_buffer_phys = addr + 0x800000;
-               } else {
-                       p->control_regs_phys = addr;
-                       p->control_regs_size = dp->addrs[i].size;
-               }
-       }
+       p->fb_orig_base = fb_res.start;
+       p->fb_orig_size = fb_res.end - fb_res.start + 1;
+       /* use the big-endian aperture (??) */
+       p->frame_buffer_phys = fb_res.start + 0x800000;
+       p->control_regs_phys = reg_res.start;
+       p->control_regs_size = reg_res.end - reg_res.start + 1;
 
        if (!p->fb_orig_base ||
            !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) {
@@ -1059,43 +1085,3 @@ static void control_cleanup(void)
 }
 
 
-/*
- * Parse user speficied options (`video=controlfb:')
- */
-void __init control_setup(char *options)
-{
-       char *this_opt;
-
-       if (!options || !*options)
-               return;
-
-       while ((this_opt = strsep(&options, ",")) != NULL) {
-               if (!strncmp(this_opt, "vmode:", 6)) {
-                       int vmode = simple_strtoul(this_opt+6, NULL, 0);
-                       if (vmode > 0 && vmode <= VMODE_MAX &&
-                           control_mac_modes[vmode - 1].m[1] >= 0)
-                               default_vmode = vmode;
-               } else if (!strncmp(this_opt, "cmode:", 6)) {
-                       int depth = simple_strtoul(this_opt+6, NULL, 0);
-                       switch (depth) {
-                        case CMODE_8:
-                        case CMODE_16:
-                        case CMODE_32:
-                               default_cmode = depth;
-                               break;
-                        case 8:
-                               default_cmode = CMODE_8;
-                               break;
-                        case 15:
-                        case 16:
-                               default_cmode = CMODE_16;
-                               break;
-                        case 24:
-                        case 32:
-                               default_cmode = CMODE_32;
-                               break;
-                       }
-               }
-       }
-}
-
index 03fbe83d71a840660ac1486111c2707d71db3ba2..e9f5dee67e3ccec6c873119ea8e3964954b94d7e 100644 (file)
@@ -7,11 +7,12 @@
  *     tridentfb.c by Jani Monoses
  *     see files above for further credits
  *
- * TODO:
- *
  */
 
 #define CYBLAFB_DEBUG 0
+#define CYBLAFB_KD_GRAPHICS_QUIRK 1
+
+#define CYBLAFB_PIXMAPSIZE 8192
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -22,7 +23,7 @@
 #include <asm/types.h>
 #include <video/cyblafb.h>
 
-#define VERSION "0.54"
+#define VERSION "0.62"
 
 struct cyblafb_par {
        u32 pseudo_pal[16];
@@ -32,7 +33,9 @@ struct cyblafb_par {
 static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
        .id = "CyBla",
        .type = FB_TYPE_PACKED_PIXELS,
+       .xpanstep = 1,
        .ypanstep = 1,
+       .ywrapstep = 1,
        .visual = FB_VISUAL_PSEUDOCOLOR,
        .accel = FB_ACCEL_NONE,
 };
@@ -43,8 +46,9 @@ static int ref __devinitdata = 75;
 static int fp __devinitdata;
 static int crt __devinitdata;
 static int memsize __devinitdata;
-static int vesafb __devinitdata;
 
+static int basestride;
+static int vesafb;
 static int nativex;
 static int center;
 static int stretch;
@@ -52,26 +56,50 @@ static int pciwb = 1;
 static int pcirb = 1;
 static int pciwr = 1;
 static int pcirr = 1;
+static int disabled;
 static int verbosity;
 static int displaytype;
 
-static void __iomem * io_virt; // iospace virtual memory address
-
-module_param(mode,charp,0);
-module_param(bpp,int,0);
-module_param(ref,int,0);
-module_param(fp,int,0);
-module_param(crt,int,0);
-module_param(nativex,int,0);
-module_param(center,int,0);
-module_param(stretch,int,0);
-module_param(pciwb,int,0);
-module_param(pcirb,int,0);
-module_param(pciwr,int,0);
-module_param(pcirr,int,0);
-module_param(memsize,int,0);
-module_param(verbosity,int,0);
-module_param(vesafb,int,0);
+static void __iomem *io_virt;  // iospace virtual memory address
+
+module_param(mode, charp, 0);
+module_param(bpp, int, 0);
+module_param(ref, int, 0);
+module_param(fp, int, 0);
+module_param(crt, int, 0);
+module_param(nativex, int, 0);
+module_param(center, int, 0);
+module_param(stretch, int, 0);
+module_param(pciwb, int, 0);
+module_param(pcirb, int, 0);
+module_param(pciwr, int, 0);
+module_param(pcirr, int, 0);
+module_param(memsize, int, 0);
+module_param(verbosity, int, 0);
+
+//=========================================
+//
+// Well, we have to fix the upper layers.
+// Until this has been done, we work around
+// the bugs.
+//
+//=========================================
+
+#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
+       if (disabled) { \
+               printk("********\n");\
+               dump_stack();\
+               return val;\
+       }
+
+#elif CYBLAFB_KD_GRAPHICS_QUIRK
+#define KD_GRAPHICS_RETURN(val)\
+       if (disabled) {\
+               return val;\
+       }
+#else
+#define KD_GRAPHICS_RETURN(val)
+#endif
 
 //=========================================
 //
@@ -79,10 +107,10 @@ module_param(vesafb,int,0);
 //
 //=========================================
 
-#define out8(r,v) writeb(v,io_virt+r)
-#define out32(r,v) writel(v,io_virt+r)
-#define in8(r) readb(io_virt+r)
-#define in32(r) readl(io_virt+r)
+#define out8(r, v) writeb(v, io_virt + r)
+#define out32(r, v) writel(v, io_virt + r)
+#define in8(r) readb(io_virt + r)
+#define in32(r) readl(io_virt + r)
 
 //======================================
 //
@@ -90,47 +118,47 @@ module_param(vesafb,int,0);
 //
 //======================================
 
-static inline unsigned char read3X4(int reg)
+static inline u8 read3X4(u32 reg)
 {
-       out8(0x3D4,reg);
+       out8(0x3D4, reg);
        return in8(0x3D5);
 }
 
-static inline unsigned char read3C4(int reg)
+static inline u8 read3C4(u32 reg)
 {
-       out8(0x3C4,reg);
+       out8(0x3C4, reg);
        return in8(0x3C5);
 }
 
-static inline unsigned char read3CE(int reg)
+static inline u8 read3CE(u32 reg)
 {
-       out8(0x3CE,reg);
+       out8(0x3CE, reg);
        return in8(0x3CF);
 }
 
-static inline void write3X4(int reg,unsigned char val)
+static inline void write3X4(u32 reg, u8 val)
 {
-       out8(0x3D4,reg);
-       out8(0x3D5,val);
+       out8(0x3D4, reg);
+       out8(0x3D5, val);
 }
 
-static inline void write3C4(int reg,unsigned char val)
+static inline void write3C4(u32 reg, u8 val)
 {
-       out8(0x3C4,reg);
-       out8(0x3C5,val);
+       out8(0x3C4, reg);
+       out8(0x3C5, val);
 }
 
-static inline void write3CE(int reg,unsigned char val)
+static inline void write3CE(u32 reg, u8 val)
 {
-       out8(0x3CE,reg);
-       out8(0x3CF,val);
+       out8(0x3CE, reg);
+       out8(0x3CF, val);
 }
 
-static inline void write3C0(int reg,unsigned char val)
+static inline void write3C0(u32 reg, u8 val)
 {
-       in8(0x3DA);     // read to reset index
-       out8(0x3C0,reg);
-       out8(0x3C0,val);
+       in8(0x3DA);             // read to reset index
+       out8(0x3C0, reg);
+       out8(0x3C0, val);
 }
 
 //=================================================
@@ -139,58 +167,62 @@ static inline void write3C0(int reg,unsigned char val)
 //
 //=================================================
 
-static inline void enable_mmio(void)
+static void enable_mmio(void)
 {
-       int tmp;
+       u8 tmp;
 
-       outb(0x0B,0x3C4);
+       outb(0x0B, 0x3C4);
        inb(0x3C5);             // Set NEW mode
-       outb(SR0E,0x3C4);       // write enable a lot of extended ports
-       outb(0x80,0x3C5);
+       outb(SR0E, 0x3C4);      // write enable a lot of extended ports
+       outb(0x80, 0x3C5);
 
-       outb(SR11,0x3C4);       // write enable those extended ports that
-       outb(0x87,0x3C5);       // are not affected by SR0E_New
+       outb(SR11, 0x3C4);      // write enable those extended ports that
+       outb(0x87, 0x3C5);      // are not affected by SR0E_New
 
-       outb(CR1E,0x3d4);       // clear write protect bit for port 0x3c2
-       tmp=inb(0x3d5) & 0xBF;
-       outb(CR1E,0x3d4);
-       outb(tmp,0x3d5);
+       outb(CR1E, 0x3d4);      // clear write protect bit for port 0x3c2
+       tmp = inb(0x3d5) & 0xBF;
+       outb(CR1E, 0x3d4);
+       outb(tmp, 0x3d5);
 
-       outb(CR39,0x3D4);
-       outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched
+       outb(CR39, 0x3D4);
+       outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
 }
 
 //=================================================
 //
 // Set pixel clock VCLK1
-//   - multipliers set elswhere
-//   - freq in units of 0.01 MHz
+// - multipliers set elswhere
+// - freq in units of 0.01 MHz
+//
+// Hardware bug: SR18 >= 250 is broken for the
+//              cyberblade/i1
 //
 //=================================================
 
 static void set_vclk(struct cyblafb_par *par, int freq)
 {
-       u32 m,n,k;
-       int f,fi,d,di;
-       u8 lo=0,hi=0;
+       u32 m, n, k;
+       int f, fi, d, di;
+       u8 lo = 0, hi = 0;
 
        d = 2000;
        k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
-       for(m = 0;m<64;m++)
-       for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 !
-               fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12);
-               if ((di = abs(fi - freq)) < d) {
-                       d = di;
-                       f = fi;
-                       lo = (u8) n;
-                       hi = (u8) ((k<<6) | m);
+       for (m = 0; m < 64; m++)
+               for (n = 0; n < 250; n++) {
+                       fi = (int)(((5864727 * (n + 8)) /
+                                   ((m + 2) * (1 << k))) >> 12);
+                       if ((di = abs(fi - freq)) < d) {
+                               d = di;
+                               f = fi;
+                               lo = (u8) n;
+                               hi = (u8) ((k << 6) | m);
+                       }
                }
-       }
-       write3C4(SR19,hi);
-       write3C4(SR18,lo);
-       if(verbosity > 1)
+       write3C4(SR19, hi);
+       write3C4(SR18, lo);
+       if (verbosity > 0)
                output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
-               freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo);
+                      freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
 }
 
 //================================================
@@ -199,83 +231,83 @@ static void set_vclk(struct cyblafb_par *par, int freq)
 //
 //================================================
 
-static void cyblafb_setup_GE(int pitch,int bpp)
+static void cyblafb_setup_GE(int pitch, int bpp)
 {
-       int base = (pitch>>3)<<20;
+       KD_GRAPHICS_RETURN();
 
        switch (bpp) {
-               case  8: base |= (0<<29); break;
-               case 15: base |= (5<<29); break;
-               case 16: base |= (1<<29); break;
-               case 24:
-               case 32: base |= (2<<29); break;
+       case 8:
+               basestride = ((pitch >> 3) << 20) | (0 << 29);
+               break;
+       case 15:
+               basestride = ((pitch >> 3) << 20) | (5 << 29);
+               break;
+       case 16:
+               basestride = ((pitch >> 3) << 20) | (1 << 29);
+               break;
+       case 24:
+       case 32:
+               basestride = ((pitch >> 3) << 20) | (2 << 29);
+               break;
        }
 
-       write3X4(CR36,0x90);    // reset GE
-       write3X4(CR36,0x80);    // enable GE
-
-       out32(GE24,1<<7);       // reset all GE pointers
-       out32(GE24,0);
-
-       write3X4(CR2D,0x00);    // GE Timinigs, no delays
-
-       out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133
-       out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133
-       out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133
-       out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133
-       out32(GEC8,base); // Source Stride / Buffer Base 0, p 133
-       out32(GECC,base); // Source Stride / Buffer Base 1, p 133
-       out32(GED0,base); // Source Stride / Buffer Base 2, p 133
-       out32(GED4,base); // Source Stride / Buffer Base 3, p 133
-       out32(GE6C,0);    // Pattern and Style, p 129, ok
+       write3X4(CR36, 0x90);   // reset GE
+       write3X4(CR36, 0x80);   // enable GE
+       out32(GE24, 1 << 7);    // reset all GE pointers by toggling
+       out32(GE24, 0);         //   d7 of GE24
+       write3X4(CR2D, 0x00);   // GE Timinigs, no delays
+       out32(GE6C, 0);         // Pattern and Style, p 129, ok
 }
 
 //=====================================================================
 //
-// Although this is a .fb_sync function that could be enabled in
-// cyblafb_ops, we do not include it there. We sync immediately before
-// new GE operations to improve performance.
+// Cyberblade specific syncing
+//
+//   A timeout might be caused by disabled mmio.
+//   Cause:
+//     - bit CR39 & 1 == 0 upon return, X trident driver bug
+//     - kdm bug (KD_GRAPHICS not set on first switch)
+//     - kernel design flaw (it believes in the correctness
+//      of kdm/X
+//   First we try to sync ignoring that problem, as most of the
+//   time that will succeed immediately and the enable_mmio()
+//   would only degrade performance.
 //
 //=====================================================================
 
 static int cyblafb_sync(struct fb_info *info)
 {
-       int status, i=100000;
-       while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
+       u32 status, i = 100000;
+
+       KD_GRAPHICS_RETURN(0);
+
+       while (((status = in32(GE20)) & 0xFe800000) && i != 0)
                i--;
 
        if (i == 0) {
-               // The timeout might be caused by disabled mmio.
-               // Cause:
-               //   - bit CR39 & 1 == 0 upon return, X trident driver bug
-               //   - kdm bug (KD_GRAPHICS not set on first switch)
-               //   - kernel design flaw (it believes in the correctness
-               //     of kdm/X
-               // So we make sure that mmio is enabled first ...
                enable_mmio();
-//             show_trace(NULL,&status);
-               i=1000000;
-               while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
+               i = 1000000;
+               while (((status = in32(GE20)) & 0xFA800000) && i != 0)
                        i--;
                if (i == 0) {
-                       output("GE Timeout, status: %x\n",status);
-                       if(status & 0x80000000)
+                       output("GE Timeout, status: %x\n", status);
+                       if (status & 0x80000000)
                                output("Bresenham Engine : Busy\n");
-                       if(status & 0x40000000)
+                       if (status & 0x40000000)
                                output("Setup Engine     : Busy\n");
-                       if(status & 0x20000000)
+                       if (status & 0x20000000)
                                output("SP / DPE         : Busy\n");
-                       if(status & 0x10000000)
+                       if (status & 0x10000000)
                                output("Memory Interface : Busy\n");
-                       if(status & 0x08000000)
+                       if (status & 0x08000000)
                                output("Com Lst Proc     : Busy\n");
-                       if(status & 0x04000000)
+                       if (status & 0x04000000)
                                output("Block Write      : Busy\n");
-                       if(status & 0x02000000)
+                       if (status & 0x02000000)
                                output("Command Buffer   : Full\n");
-                       if(status & 0x01000000)
+                       if (status & 0x01000000)
                                output("RESERVED         : Busy\n");
-                       if(status & 0x00800000)
+                       if (status & 0x00800000)
                                output("PCI Write Buffer : Busy\n");
                        cyblafb_setup_GE(info->var.xres,
                                         info->var.bits_per_pixel);
@@ -291,142 +323,193 @@ static int cyblafb_sync(struct fb_info *info)
 //
 //==============================
 
-static void cyblafb_fillrect(struct fb_info * info,
-                            const struct fb_fillrect *fr)
+static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
 {
-       int bpp = info->var.bits_per_pixel;
-       int col;
+       u32 bpp = info->var.bits_per_pixel, col, desty, height;
+
+       KD_GRAPHICS_RETURN();
 
        switch (bpp) {
-               default:
-               case 8: col = fr->color;
-                       col |= col <<8;
-                       col |= col <<16;
-                       break;
-               case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
-                        col |= col <<16;
-                        break;
-               case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
-                        break;
+       default:
+       case 8:
+               col = fr->color;
+               col |= col << 8;
+               col |= col << 16;
+               break;
+       case 16:
+               col = ((u32 *) (info->pseudo_palette))[fr->color];
+               col |= col << 16;
+               break;
+       case 32:
+               col = ((u32 *) (info->pseudo_palette))[fr->color];
+               break;
        }
 
-       cyblafb_sync(info);
-
-       out32(GE60,col);
-       out32(GE48,fr->rop ? 0x66:ROP_S);
-       out32(GE44,0x20000000|1<<19|1<<4|2<<2);
-       out32(GE08,point(fr->dx,fr->dy));
-       out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1));
-
+       desty = fr->dy;
+       height = fr->height;
+       while (height) {
+               out32(GEB8, basestride | ((desty * info->var.xres_virtual *
+                                          bpp) >> 6));
+               out32(GE60, col);
+               out32(GE48, fr->rop ? 0x66 : ROP_S);
+               out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
+               out32(GE08, point(fr->dx, 0));
+               out32(GE0C, point(fr->dx + fr->width - 1,
+                                 height > 4096 ? 4095 : height - 1));
+               if (likely(height <= 4096))
+                       return;
+               desty += 4096;
+               height -= 4096;
+       }
 }
 
-//==============================
+//================================================
 //
 // Cyberblade specific copyarea
 //
-//==============================
+// This function silently assumes that it never
+// will be called with width or height exceeding
+// 4096.
+//
+//================================================
 
-static void cyblafb_copyarea(struct fb_info *info,
-                            const struct fb_copyarea *ca)
+static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
 {
-       __u32 s1,s2,d1,d2;
-       int direction;
+       u32 s1, s2, d1, d2, direction;
+
+       KD_GRAPHICS_RETURN();
+
+       s1 = point(ca->sx, 0);
+       s2 = point(ca->sx + ca->width - 1, ca->height - 1);
+       d1 = point(ca->dx, 0);
+       d2 = point(ca->dx + ca->width - 1, ca->height - 1);
 
-       s1 = point(ca->sx,ca->sy);
-       s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1);
-       d1 = point(ca->dx,ca->dy);
-       d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1);
        if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
                direction = 0;
        else
                direction = 2;
 
-       cyblafb_sync(info);
-
-       out32(GE44,0xa0000000|1<<19|1<<2|direction);
-       out32(GE00,direction?s2:s1);
-       out32(GE04,direction?s1:s2);
-       out32(GE08,direction?d2:d1);
-       out32(GE0C,direction?d1:d2);
-
+       out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
+                                  info->var.bits_per_pixel) >> 6));
+       out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
+                                  info->var.bits_per_pixel) >> 6));
+       out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
+       out32(GE00, direction ? s2 : s1);
+       out32(GE04, direction ? s1 : s2);
+       out32(GE08, direction ? d2 : d1);
+       out32(GE0C, direction ? d1 : d2);
 }
 
 //=======================================================================
 //
 // Cyberblade specific imageblit
 //
-// Accelerated for the most usual case, blitting 1-bit deep character
-// character images. Everything else is passed to the generic imageblit.
+// Accelerated for the most usual case, blitting 1 - bit deep
+// character images. Everything else is passed to the generic imageblit
+// unless it is so insane that it is better to printk an alert.
+//
+// Hardware bug: _Never_ blit across pixel column 2048, that will lock
+// the system. We split those blit requests into three blitting
+// operations.
 //
 //=======================================================================
 
 static void cyblafb_imageblit(struct fb_info *info,
                              const struct fb_image *image)
 {
-
        u32 fgcol, bgcol;
+       u32 *pd = (u32 *) image->data;
+       u32 bpp = info->var.bits_per_pixel;
 
-       int i;
-       int bpp = info->var.bits_per_pixel;
-       int index = 0;
-       int index_end=image->height * image->width / 8;
-       int width_dds=image->width / 32;
-       int width_dbs=image->width % 32;
-
-       if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 ||
-           image->width % 8 != 0 || image->width == 0 || image->height == 0) {
-               cfb_imageblit(info,image);
+       KD_GRAPHICS_RETURN();
+
+       // Used only for drawing the penguine (image->depth > 1)
+       if (image->depth != 1) {
+               cfb_imageblit(info, image);
+               return;
+       }
+       // That should never happen, but it would be fatal
+       if (image->width == 0 || image->height == 0) {
+               output("imageblit: width/height 0 detected\n");
                return;
        }
 
        if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
            info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
-               fgcol = ((u32*)(info->pseudo_palette))[image->fg_color];
-               bgcol = ((u32*)(info->pseudo_palette))[image->bg_color];
+               fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
+               bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
        } else {
                fgcol = image->fg_color;
                bgcol = image->bg_color;
        }
 
        switch (bpp) {
-               case 8:
-                       fgcol |= fgcol <<8; fgcol |= fgcol <<16;
-                       bgcol |= bgcol <<8; bgcol |= bgcol <<16;
-                       break;
-               case 16:
-                       fgcol |= fgcol <<16;
-                       bgcol |= bgcol <<16;
-                       break;
-               default:
-                        break;
+       case 8:
+               fgcol |= fgcol << 8;
+               bgcol |= bgcol << 8;
+       case 16:
+               fgcol |= fgcol << 16;
+               bgcol |= bgcol << 16;
+       default:
+               break;
        }
 
-       cyblafb_sync(info);
-
-       out32(GE60,fgcol);
-       out32(GE64,bgcol);
-       out32(GE44,0xa0000000 | 1<<20 | 1<<19);
-       out32(GE08,point(image->dx,image->dy));
-       out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1));
+       out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
+                                  bpp) >> 6));
+       out32(GE60, fgcol);
+       out32(GE64, bgcol);
+
+       if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
+               u32 dds = ((image->width + 31) >> 5) * image->height;
+               out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+               out32(GE08, point(image->dx, 0));
+               out32(GE0C, point(image->dx + image->width - 1,
+                                 image->height - 1));
+               while (dds--)
+                       out32(GE9C, *pd++);
+       } else {
+               int i, j;
+               u32 ddstotal = (image->width + 31) >> 5;
+               u32 ddsleft = (2048 - image->dx + 31) >> 5;
+               u32 skipleft = ddstotal - ddsleft;
+
+               out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+               out32(GE08, point(image->dx, 0));
+               out32(GE0C, point(2048 - 1, image->height - 1));
+               for (i = 0; i < image->height; i++) {
+                       for (j = 0; j < ddsleft; j++)
+                               out32(GE9C, *pd++);
+                       pd += skipleft;
+               }
 
-       while(index < index_end) {
-               const char *p = image->data + index;
-               for(i=0;i<width_dds;i++) {
-                       out32(GE9C,*(u32*)p);
-                       p+=4;
-                       index+=4;
+               if (image->dx % 32) {
+                       out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+                       out32(GE08, point(2048, 0));
+                       if (image->width > ddsleft << 5)
+                               out32(GE0C, point(image->dx + (ddsleft << 5) -
+                                                 1, image->height - 1));
+                       else
+                               out32(GE0C, point(image->dx + image->width - 1,
+                                                 image->height - 1));
+                       pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
+                       for (i = 0; i < image->height; i++) {
+                               out32(GE9C, swab32(swab32(*pd) << ((32 -
+                                           (image->dx & 31)) & 31)));
+                               pd += ddstotal;
+                       }
                }
-               switch(width_dbs) {
-               case 0: break;
-               case 8: out32(GE9C,*(u8*)p);
-                       index+=1;
-                       break;
-               case 16: out32(GE9C,*(u16*)p);
-                       index+=2;
-                       break;
-               case 24: out32(GE9C,*(u16*)p | *(u8*)(p+2)<<16);
-                       index+=3;
-                       break;
+
+               if (skipleft) {
+                       out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+                       out32(GE08, point(image->dx + (ddsleft << 5), 0));
+                       out32(GE0C, point(image->dx + image->width - 1,
+                                         image->height - 1));
+                       pd = (u32 *) image->data;
+                       for (i = 0; i < image->height; i++) {
+                               pd += ddsleft;
+                               for (j = 0; j < skipleft; j++)
+                                       out32(GE9C, *pd++);
+                       }
                }
        }
 }
@@ -443,7 +526,6 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
                             struct fb_info *info)
 {
        int bpp = var->bits_per_pixel;
-       int s,t,maxvyres;
 
        //
        // we try to support 8, 16, 24 and 32 bpp modes,
@@ -453,9 +535,9 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
        // (This is what tridentfb does ... will be changed in the future)
        //
        //
-       if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
+       if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
                bpp = 8;
-       if (bpp == 24 )
+       if (bpp == 24)
                bpp = var->bits_per_pixel = 32;
 
        //
@@ -472,65 +554,93 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
                return -EINVAL;
 
        //
-       // xres != xres_virtual is broken, fail if such an
-       // unusual mode is requested
+       // we do not allow vclk to exceed 230 MHz. If the requested
+       // vclk is too high, we default to 200 MHz
        //
-       if (var->xres != var->xres_virtual)
-               return -EINVAL;
+       if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
+               var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
 
        //
-       // we do not allow vclk to exceed 230 MHz
+       // enforce (h|v)sync_len limits
        //
-       if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
-               return -EINVAL;
+       var->hsync_len &= ~7;
+       if(var->hsync_len > 248)
+               var->hsync_len = 248;
+
+       var->vsync_len &= 15;
 
        //
-       // calc max yres_virtual that would fit in memory
-       // and max yres_virtual that could be used for scrolling
-       // and use minimum of the results as maxvyres
-       //
-       // adjust vyres_virtual to maxvyres if necessary
-       // fail if requested yres is bigger than maxvyres
+       // Enforce horizontal and vertical hardware limits.
+       // 1600x1200 is mentioned as a maximum, but higher resolutions could
+       // work with slow refresh, small margins and short sync.
        //
-       s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
-       t = info->fix.smem_len / (var->xres * bpp/8);
-       maxvyres = t < s ? t : s;
-       if (maxvyres < var->yres_virtual)
-               var->yres_virtual=maxvyres;
-       if (maxvyres < var->yres)
+       var->xres &= ~7;
+
+       if (((var->xres + var->left_margin + var->right_margin +
+                       var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
+                       ((var->yres + var->upper_margin + var->lower_margin +
+                       var->vsync_len) > 2047))
                return -EINVAL;
 
-       switch (bpp) {
-               case 8:
-                       var->red.offset = 0;
-                       var->green.offset = 0;
-                       var->blue.offset = 0;
-                       var->red.length = 6;
-                       var->green.length = 6;
-                       var->blue.length = 6;
-                       break;
-               case 16:
-                       var->red.offset = 11;
-                       var->green.offset = 5;
-                       var->blue.offset = 0;
-                       var->red.length = 5;
-                       var->green.length = 6;
-                       var->blue.length = 5;
-                       break;
-               case 32:
-                       var->red.offset = 16;
-                       var->green.offset = 8;
-                       var->blue.offset = 0;
-                       var->red.length = 8;
-                       var->green.length = 8;
-                       var->blue.length = 8;
-                       break;
-               default:
+       if ((var->xres > 1600) || (var->yres > 1200))
+               output("Mode %dx%d exceeds documented limits.\n",
+                                          var->xres, var->yres);
+       //
+       // try to be smart about (x|y)res_virtual problems.
+       //
+       if (var->xres > var->xres_virtual)
+               var->xres_virtual = var->xres;
+       if (var->yres > var->yres_virtual)
+               var->yres_virtual = var->yres;
+
+       if (bpp == 8 || bpp == 16) {
+               if (var->xres_virtual > 4088)
+                       var->xres_virtual = 4088;
+       } else {
+               if (var->xres_virtual > 2040)
+                       var->xres_virtual = 2040;
+       }
+       var->xres_virtual &= ~7;
+       while (var->xres_virtual * var->yres_virtual * bpp / 8 >
+              info->fix.smem_len) {
+               if (var->yres_virtual > var->yres)
+                       var->yres_virtual--;
+               else if (var->xres_virtual > var->xres)
+                       var->xres_virtual -= 8;
+               else
                        return -EINVAL;
        }
 
-       return 0;
+       switch (bpp) {
+       case 8:
+               var->red.offset = 0;
+               var->green.offset = 0;
+               var->blue.offset = 0;
+               var->red.length = 6;
+               var->green.length = 6;
+               var->blue.length = 6;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               break;
+       default:
+               return -EINVAL;
+       }
 
+       return 0;
 }
 
 //=====================================================================
@@ -543,23 +653,25 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
 // it, so it is also safe to be used here. BTW: datasheet CR0E on page
 // 90 really is CR1E, the real CRE is documented on page 72.
 //
+// BUT:
+//
+// As of internal version 0.60 we do not use vga panning any longer.
+// Vga panning did not allow us the use of all available video memory
+// and thus prevented ywrap scrolling. We do use the "right view"
+// register now.
+//
+//
 //=====================================================================
 
 static int cyblafb_pan_display(struct fb_var_screeninfo *var,
                               struct fb_info *info)
 {
-       unsigned int offset;
+       KD_GRAPHICS_RETURN(0);
 
-       offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
        info->var.xoffset = var->xoffset;
        info->var.yoffset = var->yoffset;
-
-       write3X4(CR0D,offset & 0xFF);
-       write3X4(CR0C,(offset & 0xFF00) >> 8);
-       write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
-       write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
-       write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
-
+       out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
+                   var->xres_virtual)) * var->bits_per_pixel / 32));
        return 0;
 }
 
@@ -578,56 +690,96 @@ static void regdump(struct cyblafb_par *par)
                return;
 
        printk("\n");
-       for(i=0; i<=0xff; i++) {
-               outb(i,0x3d4);
-               printk("CR%02x=%02x ",i,inb(0x3d5));
-               if (i%16==15)
+       for (i = 0; i <= 0xff; i++) {
+               outb(i, 0x3d4);
+               printk("CR%02x=%02x ", i, inb(0x3d5));
+               if (i % 16 == 15)
                        printk("\n");
        }
 
-       outb(0x30,0x3ce);
-       outb(inb(0x3cf) | 0x40,0x3cf);
-       for(i=0; i<=0x1f; i++) {
-               if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
-                       outb(i,0x3d4);
-                       printk("CR%02x=%02x ",i,inb(0x3d5));
+       outb(0x30, 0x3ce);
+       outb(inb(0x3cf) | 0x40, 0x3cf);
+       for (i = 0; i <= 0x1f; i++) {
+               if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
+                   || i == 0x16) {
+                       outb(i, 0x3d4);
+                       printk("CR%02x=%02x ", i, inb(0x3d5));
                } else
                        printk("------- ");
-               if (i%16==15)
+               if (i % 16 == 15)
                        printk("\n");
        }
-       outb(0x30,0x3ce);
-       outb(inb(0x3cf) & 0xbf,0x3cf);
+       outb(0x30, 0x3ce);
+       outb(inb(0x3cf) & 0xbf, 0x3cf);
 
        printk("\n");
-       for(i=0; i<=0x7f; i++) {
-               outb(i,0x3ce);
-               printk("GR%02x=%02x ",i,inb(0x3cf));
-               if (i%16==15)
+       for (i = 0; i <= 0x7f; i++) {
+               outb(i, 0x3ce);
+               printk("GR%02x=%02x ", i, inb(0x3cf));
+               if (i % 16 == 15)
                        printk("\n");
        }
 
        printk("\n");
-       for(i=0; i<=0xff; i++) {
-               outb(i,0x3c4);
-               printk("SR%02x=%02x ",i,inb(0x3c5));
-               if (i%16==15)
+       for (i = 0; i <= 0xff; i++) {
+               outb(i, 0x3c4);
+               printk("SR%02x=%02x ", i, inb(0x3c5));
+               if (i % 16 == 15)
                        printk("\n");
        }
 
        printk("\n");
-       for(i=0; i <= 0x1F; i++) {
-               inb(0x3da); // next access is index!
-               outb(i,0x3c0);
-               printk("AR%02x=%02x ",i,inb(0x3c1));
-               if (i%16==15)
+       for (i = 0; i <= 0x1F; i++) {
+               inb(0x3da);     // next access is index!
+               outb(i, 0x3c0);
+               printk("AR%02x=%02x ", i, inb(0x3c1));
+               if (i % 16 == 15)
                        printk("\n");
        }
        printk("\n");
 
-       inb(0x3DA);                     // reset internal flag to 3c0 index
-       outb(0x20,0x3C0);               // enable attr
+       inb(0x3DA);             // reset internal flag to 3c0 index
+       outb(0x20, 0x3C0);      // enable attr
+
+       return;
+}
+
+//=======================================================================
+//
+// Save State
+//
+// This function is called while a switch to KD_TEXT is in progress,
+// before any of the other functions are called.
+//
+//=======================================================================
 
+static void cyblafb_save_state(struct fb_info *info)
+{
+       struct cyblafb_par *par = info->par;
+       if (verbosity > 0)
+               output("Switching to KD_TEXT\n");
+       disabled = 0;
+       regdump(par);
+       enable_mmio();
+       return;
+}
+
+//=======================================================================
+//
+// Restore State
+//
+// This function is called while a switch to KD_GRAPHICS is in progress,
+// We have to turn on vga style panning registers again because the
+// trident driver of X does not know about GE10.
+//
+//=======================================================================
+
+static void cyblafb_restore_state(struct fb_info *info)
+{
+       if (verbosity > 0)
+               output("Switching to KD_GRAPHICS\n");
+       out32(GE10, 0);
+       disabled = 1;
        return;
 }
 
@@ -640,32 +792,34 @@ static void regdump(struct cyblafb_par *par)
 static int cyblafb_set_par(struct fb_info *info)
 {
        struct cyblafb_par *par = info->par;
-       u32
-       htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
-               vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
+       u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
+           hblankend, preendfetch, vtotal, vdispend, vsyncstart,
+           vsyncend, vblankstart, vblankend;
        struct fb_var_screeninfo *var = &info->var;
        int bpp = var->bits_per_pixel;
        int i;
 
+       KD_GRAPHICS_RETURN(0);
+
        if (verbosity > 0)
                output("Switching to new mode: "
                       "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
-                       var->xres,var->yres,var->xres_virtual,
-                       var->yres_virtual,var->bits_per_pixel,var->pixclock,
-                       var->left_margin,var->right_margin,var->upper_margin,
-                       var->lower_margin,var->hsync_len,var->vsync_len);
+                      var->xres, var->yres, var->xres_virtual,
+                      var->yres_virtual, var->bits_per_pixel, var->pixclock,
+                      var->left_margin, var->right_margin, var->upper_margin,
+                      var->lower_margin, var->hsync_len, var->vsync_len);
 
        htotal = (var->xres + var->left_margin + var->right_margin +
-                                                var->hsync_len) / 8 - 5;
-       hdispend = var->xres/8 - 1;
-       hsyncstart = (var->xres + var->right_margin)/8;
-       hsyncend = var->hsync_len/8;
+                 var->hsync_len) / 8 - 5;
+       hdispend = var->xres / 8 - 1;
+       hsyncstart = (var->xres + var->right_margin) / 8;
+       hsyncend = var->hsync_len / 8;
        hblankstart = hdispend + 1;
        hblankend = htotal + 3; // should be htotal + 5, bios does it this way
-       preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
+       preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
 
        vtotal = var->yres + var->upper_margin + var->lower_margin +
-                                                var->vsync_len - 2;
+                                                       var->vsync_len - 2;
        vdispend = var->yres - 1;
        vsyncstart = var->yres + var->lower_margin;
        vblankstart = var->yres;
@@ -674,101 +828,99 @@ static int cyblafb_set_par(struct fb_info *info)
 
        enable_mmio();          // necessary! ... check X ...
 
-       write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
+       write3X4(CR11, read3X4(CR11) & 0x7F);   // unlock cr00 .. cr07
 
-       write3CE(GR30,8);
+       write3CE(GR30, 8);
 
        if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
 
                // stretch or center ?
 
-               out8(0x3C2,0xEB);
+               out8(0x3C2, 0xEB);
 
-               write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
+               write3CE(GR30, read3CE(GR30) | 0x81);   // shadow mode on
 
                if (center) {
-                       write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
-                       write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
-               }
-               else if (stretch) {
-                       write3CE(GR5D,0);
-                       write3CE(GR52,(read3CE(GR52) & 0x7C) | 1);
-                       write3CE(GR53,(read3CE(GR53) & 0x7C) | 1);
+                       write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
+                       write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
+               } else if (stretch) {
+                       write3CE(GR5D, 0);
+                       write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
+                       write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
                }
 
        } else {
-               out8(0x3C2,0x2B);
-               write3CE(GR30,8);
+               out8(0x3C2, 0x2B);
+               write3CE(GR30, 8);
        }
 
        //
        // Setup CRxx regs
        //
 
-       write3X4(CR00,htotal & 0xFF);
-       write3X4(CR01,hdispend & 0xFF);
-       write3X4(CR02,hblankstart & 0xFF);
-       write3X4(CR03,hblankend & 0x1F);
-       write3X4(CR04,hsyncstart & 0xFF);
-       write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
-       write3X4(CR06,vtotal & 0xFF);
-       write3X4(CR07,(vtotal & 0x100) >> 8 |
-                     (vdispend & 0x100) >> 7 |
-                     (vsyncstart & 0x100) >> 6 |
-                     (vblankstart & 0x100) >> 5 |
-                     0x10 |
-                     (vtotal & 0x200) >> 4 |
-                     (vdispend & 0x200) >> 3 |
-                     (vsyncstart & 0x200) >> 2);
-       write3X4(CR08,0);
-       write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 |  // FIX !!!
-                     ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
-       write3X4(CR0A,0);  // Init to some reasonable default
-       write3X4(CR0B,0);  // Init to some reasonable default
-       write3X4(CR0C,0);  // Offset 0
-       write3X4(CR0D,0);  // Offset 0
-       write3X4(CR0E,0);  // Init to some reasonable default
-       write3X4(CR0F,0);  // Init to some reasonable default
-       write3X4(CR10,vsyncstart & 0xFF);
-       write3X4(CR11,(vsyncend & 0x0F));
-       write3X4(CR12,vdispend & 0xFF);
-       write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF);
-       write3X4(CR14,0x40);  // double word mode
-       write3X4(CR15,vblankstart & 0xFF);
-       write3X4(CR16,vblankend & 0xFF);
-       write3X4(CR17,0xC3);
-       write3X4(CR18,0xFF);
+       write3X4(CR00, htotal & 0xFF);
+       write3X4(CR01, hdispend & 0xFF);
+       write3X4(CR02, hblankstart & 0xFF);
+       write3X4(CR03, hblankend & 0x1F);
+       write3X4(CR04, hsyncstart & 0xFF);
+       write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
+       write3X4(CR06, vtotal & 0xFF);
+       write3X4(CR07, (vtotal & 0x100) >> 8 |
+                      (vdispend & 0x100) >> 7 |
+                      (vsyncstart & 0x100) >> 6 |
+                      (vblankstart & 0x100) >> 5 |
+                      0x10 |
+                      (vtotal & 0x200) >> 4 |
+                      (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
+       write3X4(CR08, 0);
+       write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 |      // FIX !!!
+                      ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
+       write3X4(CR0A, 0);      // Init to some reasonable default
+       write3X4(CR0B, 0);      // Init to some reasonable default
+       write3X4(CR0C, 0);      // Offset 0
+       write3X4(CR0D, 0);      // Offset 0
+       write3X4(CR0E, 0);      // Init to some reasonable default
+       write3X4(CR0F, 0);      // Init to some reasonable default
+       write3X4(CR10, vsyncstart & 0xFF);
+       write3X4(CR11, (vsyncend & 0x0F));
+       write3X4(CR12, vdispend & 0xFF);
+       write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
+       write3X4(CR14, 0x40);   // double word mode
+       write3X4(CR15, vblankstart & 0xFF);
+       write3X4(CR16, vblankend & 0xFF);
+       write3X4(CR17, 0xE3);
+       write3X4(CR18, 0xFF);
        //       CR19: needed for interlaced modes ... ignore it for now
-       write3X4(CR1A,0x07); // Arbitration Control Counter 1
-       write3X4(CR1B,0x07); // Arbitration Control Counter 2
-       write3X4(CR1C,0x07); // Arbitration Control Counter 3
-       write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-)
-       write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
+       write3X4(CR1A, 0x07);   // Arbitration Control Counter 1
+       write3X4(CR1B, 0x07);   // Arbitration Control Counter 2
+       write3X4(CR1C, 0x07);   // Arbitration Control Counter 3
+       write3X4(CR1D, 0x00);   // Don't know, doesn't hurt ; -)
+       write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
        //       CR1F: do not set, contains BIOS info about memsize
-       write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode
-       write3X4(CR21,0x20); // enable linear memory access
+       write3X4(CR20, 0x20);   // enabe wr buf, disable 16bit planar mode
+       write3X4(CR21, 0x20);   // enable linear memory access
        //       CR22: RO cpu latch readback
        //       CR23: ???
        //       CR24: RO AR flag state
        //       CR25: RAMDAC rw timing, pclk buffer tristate control ????
        //       CR26: ???
-       write3X4(CR27,(vdispend & 0x400) >> 6 |
-                     (vsyncstart & 0x400) >> 5 |
-                     (vblankstart & 0x400) >> 4 |
-                     (vtotal & 0x400) >> 3 |
-                     0x8);
+       write3X4(CR27, (vdispend & 0x400) >> 6 |
+                      (vsyncstart & 0x400) >> 5 |
+                      (vblankstart & 0x400) >> 4 |
+                      (vtotal & 0x400) >> 3 |
+                      0x8);
        //       CR28: ???
-       write3X4(CR29,(read3X4(CR29) & 0xCF) |
-                     ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4));
-       write3X4(CR2A,read3X4(CR2A) | 0x40);
-       write3X4(CR2B,(htotal & 0x100) >> 8 |
-                     (hdispend & 0x100) >> 7 |
-                     // (0x00 & 0x100) >> 6 |   hinterlace para bit 8 ???
-                     (hsyncstart & 0x100) >> 5 |
-                     (hblankstart & 0x100) >> 4);
+       write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
+                       bpp) / (4 * 16)) & 0x300) >> 4));
+       write3X4(CR2A, read3X4(CR2A) | 0x40);
+       write3X4(CR2B, (htotal & 0x100) >> 8 |
+                      (hdispend & 0x100) >> 7 |
+                      // (0x00 & 0x100) >> 6 |   hinterlace para bit 8 ???
+                      (hsyncstart & 0x100) >> 5 |
+                      (hblankstart & 0x100) >> 4);
        //       CR2C: ???
        //       CR2D: initialized in cyblafb_setup_GE()
-       write3X4(CR2F,0x92); // conservative, better signal quality
+       write3X4(CR2F, 0x92);   // conservative, better signal quality
        //       CR30: reserved
        //       CR31: reserved
        //       CR32: reserved
@@ -777,96 +929,116 @@ static int cyblafb_set_par(struct fb_info *info)
        //       CR35: disabled in CR36
        //       CR36: initialized in cyblafb_setup_GE
        //       CR37: i2c, ignore for now
-       write3X4(CR38,(bpp == 8) ? 0x00 :       //
-                     (bpp == 16) ? 0x05 :      // highcolor
-                     (bpp == 24) ? 0x29 :      // packed 24bit truecolor
-                     (bpp == 32) ? 0x09 : 0);  // truecolor, 16 bit pixelbus
-       write3X4(CR39,0x01 |                    // MMIO enable
-                     (pcirb ? 0x02 : 0) | // pci read burst enable
-                     (pciwb ? 0x04 : 0)); // pci write burst enable
-       write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase
-                     (pcirr ? 0x40 : 0) | // pci read retry enable
-                     (pciwr ? 0x80 : 0)); // pci write retry enable
-       write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0);
-       write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
-       write3X4(CR58,0x82);    // Bios does this .... don't know more
+       write3X4(CR38, (bpp == 8) ? 0x00 :      //
+                      (bpp == 16) ? 0x05 :     // highcolor
+                      (bpp == 24) ? 0x29 :     // packed 24bit truecolor
+                      (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
+       write3X4(CR39, 0x01 |   // MMIO enable
+                      (pcirb ? 0x02 : 0) |     // pci read burst enable
+                      (pciwb ? 0x04 : 0));     // pci write burst enable
+       write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
+                      (pcirr ? 0x40 : 0) |     // pci read retry enable
+                      (pciwr ? 0x80 : 0));     // pci write retry enable
+       write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
+                                           : 0);
+       write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
+       write3X4(CR58, 0x82);   // Bios does this .... don't know more
        //
        // Setup SRxx regs
        //
-       write3C4(SR00,3);
-       write3C4(SR01,1);       //set char clock 8 dots wide
-       write3C4(SR02,0x0F);    //enable 4 maps needed in chain4 mode
-       write3C4(SR03,0);       //no character map select
-       write3C4(SR04,0x0E);    //memory mode: ext mem, even, chain4
+       write3C4(SR00, 3);
+       write3C4(SR01, 1);      //set char clock 8 dots wide
+       write3C4(SR02, 0x0F);   //enable 4 maps needed in chain4 mode
+       write3C4(SR03, 0);      //no character map select
+       write3C4(SR04, 0x0E);   //memory mode: ext mem, even, chain4
 
-       out8(0x3C4,0x0b);
+       out8(0x3C4, 0x0b);
        in8(0x3C5);             // Set NEW mode
-       write3C4(SR0D,0x00);    // test ... check
+       write3C4(SR0D, 0x00);   // test ... check
 
-       set_vclk(par,(bpp==32 ? 200000000 : 100000000)/
-                info->var.pixclock); //SR18,SR19
+       set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
+                                       / info->var.pixclock);  //SR18, SR19
 
        //
        // Setup GRxx regs
        //
-       write3CE(GR00,0x00);    // test ... check
-       write3CE(GR01,0x00);    // test ... check
-       write3CE(GR02,0x00);    // test ... check
-       write3CE(GR03,0x00);    // test ... check
-       write3CE(GR04,0x00);    // test ... check
-       write3CE(GR05,0x40);    // no CGA compat,allow 256 col
-       write3CE(GR06,0x05);    // graphics mode
-       write3CE(GR07,0x0F);    // planes?
-       write3CE(GR08,0xFF);    // test ... check
-       write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4
-       write3CE(GR20,0xC0);    // test ... check
-       write3CE(GR2F,0xA0);    // PCLK = VCLK, no skew,
+       write3CE(GR00, 0x00);   // test ... check
+       write3CE(GR01, 0x00);   // test ... check
+       write3CE(GR02, 0x00);   // test ... check
+       write3CE(GR03, 0x00);   // test ... check
+       write3CE(GR04, 0x00);   // test ... check
+       write3CE(GR05, 0x40);   // no CGA compat, allow 256 col
+       write3CE(GR06, 0x05);   // graphics mode
+       write3CE(GR07, 0x0F);   // planes?
+       write3CE(GR08, 0xFF);   // test ... check
+       write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
+       write3CE(GR20, 0xC0);   // test ... check
+       write3CE(GR2F, 0xA0);   // PCLK = VCLK, no skew,
 
        //
        // Setup ARxx regs
        //
-       for(i = 0;i < 0x10;i++) // set AR00 .. AR0f
-               write3C0(i,i);
-       write3C0(AR10,0x41);    // graphics mode and support 256 color modes
-       write3C0(AR12,0x0F);    // planes
-       write3C0(AR13,0);       // horizontal pel panning
+       for (i = 0; i < 0x10; i++)      // set AR00 .. AR0f
+               write3C0(i, i);
+       write3C0(AR10, 0x41);   // graphics mode and support 256 color modes
+       write3C0(AR12, 0x0F);   // planes
+       write3C0(AR13, 0);      // horizontal pel panning
        in8(0x3DA);             // reset internal flag to 3c0 index
-       out8(0x3C0,0x20);       // enable attr
+       out8(0x3C0, 0x20);      // enable attr
 
        //
        // Setup hidden RAMDAC command register
        //
-       in8(0x3C8);  // these reads are
-       in8(0x3C6);  // necessary to
-       in8(0x3C6);  // unmask the RAMDAC
-       in8(0x3C6);  // command reg, otherwise
-       in8(0x3C6);  // we would write the pixelmask reg!
-       out8(0x3C6,(bpp ==  8) ? 0x00 :         // 256 colors
-                  (bpp == 15) ? 0x10 :         //
-                  (bpp == 16) ? 0x30 :         // hicolor
-                  (bpp == 24) ? 0xD0 :         // truecolor
-                  (bpp == 32) ? 0xD0 : 0);     // truecolor
+       in8(0x3C8);             // these reads are
+       in8(0x3C6);             // necessary to
+       in8(0x3C6);             // unmask the RAMDAC
+       in8(0x3C6);             // command reg, otherwise
+       in8(0x3C6);             // we would write the pixelmask reg!
+       out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
+            (bpp == 15) ? 0x10 :       //
+            (bpp == 16) ? 0x30 :       // hicolor
+            (bpp == 24) ? 0xD0 :       // truecolor
+            (bpp == 32) ? 0xD0 : 0);   // truecolor
        in8(0x3C8);
 
        //
        // GR31 is not mentioned in the datasheet
        //
        if (displaytype == DISPLAY_FP)
-               write3CE(GR31,(read3CE(GR31) & 0x8F) |
+               write3CE(GR31, (read3CE(GR31) & 0x8F) |
                         ((info->var.yres > 1024) ? 0x50 :
-                        (info->var.yres >   768) ? 0x30 :
-                        (info->var.yres >   600) ? 0x20 :
-                        (info->var.yres >   480) ? 0x10 : 0));
+                         (info->var.yres > 768) ? 0x30 :
+                         (info->var.yres > 600) ? 0x20 :
+                         (info->var.yres > 480) ? 0x10 : 0));
 
        info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
                                      : FB_VISUAL_TRUECOLOR;
-       info->fix.line_length = info->var.xres * (bpp >> 3);
-       info->cmap.len = (bpp == 8) ? 256: 16;
+       info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
+       info->cmap.len = (bpp == 8) ? 256 : 16;
 
        //
        // init acceleration engine
        //
-       cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel);
+       cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
+
+       //
+       // Set/clear flags to allow proper scroll mode selection.
+       //
+       if (var->xres == var->xres_virtual)
+               info->flags &= ~FBINFO_HWACCEL_XPAN;
+       else
+               info->flags |= FBINFO_HWACCEL_XPAN;
+
+       if (var->yres == var->yres_virtual)
+               info->flags &= ~FBINFO_HWACCEL_YPAN;
+       else
+               info->flags |= FBINFO_HWACCEL_YPAN;
+
+       if (info->fix.smem_len !=
+           var->xres_virtual * var->yres_virtual * bpp / 8)
+               info->flags &= ~FBINFO_HWACCEL_YWRAP;
+       else
+               info->flags |= FBINFO_HWACCEL_YWRAP;
 
        regdump(par);
 
@@ -885,27 +1057,27 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
 {
        int bpp = info->var.bits_per_pixel;
 
+       KD_GRAPHICS_RETURN(0);
+
        if (regno >= info->cmap.len)
                return 1;
 
        if (bpp == 8) {
-               out8(0x3C6,0xFF);
-               out8(0x3C8,regno);
-               out8(0x3C9,red>>10);
-               out8(0x3C9,green>>10);
-               out8(0x3C9,blue>>10);
-
-       } else if (bpp == 16)                           // RGB 565
-               ((u32*)info->pseudo_palette)[regno] =
-                       (red & 0xF800) |
-                       ((green & 0xFC00) >> 5) |
-                       ((blue & 0xF800) >> 11);
-       else if (bpp == 32)                             // ARGB 8888
-               ((u32*)info->pseudo_palette)[regno] =
-                       ((transp & 0xFF00) <<16) |
-                       ((red & 0xFF00) << 8) |
-                       ((green & 0xFF00)) |
-                       ((blue & 0xFF00)>>8);
+               out8(0x3C6, 0xFF);
+               out8(0x3C8, regno);
+               out8(0x3C9, red >> 10);
+               out8(0x3C9, green >> 10);
+               out8(0x3C9, blue >> 10);
+
+       } else if (bpp == 16)   // RGB 565
+               ((u32 *) info->pseudo_palette)[regno] =
+                   (red & 0xF800) |
+                   ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+       else if (bpp == 32)     // ARGB 8888
+               ((u32 *) info->pseudo_palette)[regno] =
+                   ((transp & 0xFF00) << 16) |
+                   ((red & 0xFF00) << 8) |
+                   ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
 
        return 0;
 }
@@ -918,40 +1090,41 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
 
 static int cyblafb_blank(int blank_mode, struct fb_info *info)
 {
-       unsigned char PMCont,DPMSCont;
+       unsigned char PMCont, DPMSCont;
+
+       KD_GRAPHICS_RETURN(0);
 
        if (displaytype == DISPLAY_FP)
                return 0;
 
-       out8(0x83C8,0x04);              // DPMS Control
+       out8(0x83C8, 0x04);     // DPMS Control
        PMCont = in8(0x83C6) & 0xFC;
 
        DPMSCont = read3CE(GR23) & 0xFC;
 
-       switch (blank_mode)
-       {
-       case FB_BLANK_UNBLANK:       // Screen: On, HSync: On, VSync: On
-       case FB_BLANK_NORMAL:        // Screen: Off, HSync: On, VSync: On
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:  // Screen: On, HSync: On, VSync: On
+       case FB_BLANK_NORMAL:   // Screen: Off, HSync: On, VSync: On
                PMCont |= 0x03;
                DPMSCont |= 0x00;
                break;
-       case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
+       case FB_BLANK_HSYNC_SUSPEND:    // Screen: Off, HSync: Off, VSync: On
                PMCont |= 0x02;
                DPMSCont |= 0x01;
                break;
-       case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
+       case FB_BLANK_VSYNC_SUSPEND:    // Screen: Off, HSync: On, VSync: Off
                PMCont |= 0x02;
                DPMSCont |= 0x02;
                break;
-       case FB_BLANK_POWERDOWN:     // Screen: Off, HSync: Off, VSync: Off
+       case FB_BLANK_POWERDOWN:        // Screen: Off, HSync: Off, VSync: Off
                PMCont |= 0x00;
                DPMSCont |= 0x03;
                break;
        }
 
-       write3CE(GR23,DPMSCont);
-       out8(0x83C8,4);
-       out8(0x83C6,PMCont);
+       write3CE(GR23, DPMSCont);
+       out8(0x83C8, 4);
+       out8(0x83C6, PMCont);
        //
        // let fbcon do a softblank for us
        //
@@ -959,15 +1132,18 @@ static int cyblafb_blank(int blank_mode, struct fb_info *info)
 }
 
 static struct fb_ops cyblafb_ops __devinitdata = {
-       .owner  = THIS_MODULE,
+       .owner = THIS_MODULE,
        .fb_setcolreg = cyblafb_setcolreg,
        .fb_pan_display = cyblafb_pan_display,
        .fb_blank = cyblafb_blank,
        .fb_check_var = cyblafb_check_var,
        .fb_set_par = cyblafb_set_par,
        .fb_fillrect = cyblafb_fillrect,
-       .fb_copyarea= cyblafb_copyarea,
+       .fb_copyarea = cyblafb_copyarea,
        .fb_imageblit = cyblafb_imageblit,
+       .fb_sync = cyblafb_sync,
+       .fb_restore_state = cyblafb_restore_state,
+       .fb_save_state = cyblafb_save_state,
 };
 
 //==========================================================================
@@ -986,74 +1162,89 @@ static struct fb_ops cyblafb_ops __devinitdata = {
 
 static int __devinit getstartupmode(struct fb_info *info)
 {
-       u32     htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
-               vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend,
-               cr00,cr01,cr02,cr03,cr04,cr05,cr2b,
-               cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27,
-               cr38,
-               sr0d,sr18,sr19,
-               gr0f,
-               fi,pxclkdiv,vclkdiv,tmp,i;
+       u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
+           vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
+           cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
+           cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
+           cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
 
        struct modus {
-               int xres; int yres; int vyres; int bpp; int pxclk;
-               int left_margin; int right_margin; int upper_margin;
-               int lower_margin; int hsync_len; int vsync_len;
-       }  modedb[5] = {
-               {   0,    0, 8000, 0, 0,   0,  0,  0, 0,   0,  0},
-               { 640,  480, 3756, 0, 0, -40, 24, 17, 0, 216,  3},
-               { 800,  600, 3221, 0, 0,  96, 24, 14, 0, 136, 11},
-               {1024,  768, 2815, 0, 0, 144, 24, 29, 0, 120,  3},
-               {1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160,  3}
+               int xres; int vxres; int yres; int vyres;
+               int bpp; int pxclk;
+               int left_margin; int right_margin;
+               int upper_margin; int lower_margin;
+               int hsync_len; int vsync_len;
+       } modedb[5] = {
+               {
+               0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
+               640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
+               800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
+               1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
+               1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
        };
 
-       outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5);
-       outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5);
-       outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5);
-       outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5);
-       outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5);
-       outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5);
-       outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5);
-       outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5);
-       outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5);
-       outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5);
-       outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf);
-
-       htotal      = cr00 | (cr2b & 0x01) << 8;
-       hdispend    = cr01 | (cr2b & 0x02) << 7;
+       outb(0x00, 0x3d4); cr00 = inb(0x3d5);
+       outb(0x01, 0x3d4); cr01 = inb(0x3d5);
+       outb(0x02, 0x3d4); cr02 = inb(0x3d5);
+       outb(0x03, 0x3d4); cr03 = inb(0x3d5);
+       outb(0x04, 0x3d4); cr04 = inb(0x3d5);
+       outb(0x05, 0x3d4); cr05 = inb(0x3d5);
+       outb(0x06, 0x3d4); cr06 = inb(0x3d5);
+       outb(0x07, 0x3d4); cr07 = inb(0x3d5);
+       outb(0x09, 0x3d4); cr09 = inb(0x3d5);
+       outb(0x10, 0x3d4); cr10 = inb(0x3d5);
+       outb(0x11, 0x3d4); cr11 = inb(0x3d5);
+       outb(0x12, 0x3d4); cr12 = inb(0x3d5);
+       outb(0x15, 0x3d4); cr15 = inb(0x3d5);
+       outb(0x16, 0x3d4); cr16 = inb(0x3d5);
+       outb(0x27, 0x3d4); cr27 = inb(0x3d5);
+       outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
+       outb(0x38, 0x3d4); cr38 = inb(0x3d5);
+
+       outb(0x0b, 0x3c4);
+       inb(0x3c5);
+
+       outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
+       outb(0x18, 0x3c4); sr18 = inb(0x3c5);
+       outb(0x19, 0x3c4); sr19 = inb(0x3c5);
+       outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
+
+       htotal = cr00 | (cr2b & 0x01) << 8;
+       hdispend = cr01 | (cr2b & 0x02) << 7;
        hblankstart = cr02 | (cr2b & 0x10) << 4;
-       hblankend   = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
-       hsyncstart  = cr04 | (cr2b & 0x08) << 5;
-       hsyncend    = cr05 & 0x1f;
+       hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
+       hsyncstart = cr04 | (cr2b & 0x08) << 5;
+       hsyncend = cr05 & 0x1f;
 
        modedb[0].xres = hblankstart * 8;
        modedb[0].hsync_len = hsyncend * 8;
        modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
        modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
-               modedb[0].right_margin - modedb[0].hsync_len;
-
-       vtotal      = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
-                          | (cr27 & 0x80) << 3;
-       vdispend    = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
-                          | (cr27 & 0x10) << 6;
-       vsyncstart  = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
-                          | (cr27 & 0x20) << 5;
-       vsyncend    = cr11 & 0x0f;
+           modedb[0].right_margin - modedb[0].hsync_len;
+
+       vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
+           | (cr27 & 0x80) << 3;
+       vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
+           | (cr27 & 0x10) << 6;
+       vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
+           | (cr27 & 0x20) << 5;
+       vsyncend = cr11 & 0x0f;
        vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
-                          | (cr27 & 0x40) << 4;
-       vblankend   = cr16;
+           | (cr27 & 0x40) << 4;
+       vblankend = cr16;
 
-       modedb[0].yres         = vdispend + 1;
-       modedb[0].vsync_len    = vsyncend;
+       modedb[0].yres = vdispend + 1;
+       modedb[0].vsync_len = vsyncend;
        modedb[0].lower_margin = vsyncstart - modedb[0].yres;
        modedb[0].upper_margin = vtotal - modedb[0].yres -
-               modedb[0].lower_margin - modedb[0].vsync_len + 2;
+           modedb[0].lower_margin - modedb[0].vsync_len + 2;
 
        tmp = cr38 & 0x3c;
        modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
-                       tmp == 8 ? 32 : 8;
+           tmp == 8 ? 32 : 8;
 
-       fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12;
+       fi = ((5864727 * (sr18 + 8)) /
+             (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
        pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
        tmp = sr0d & 0x06;
        vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
@@ -1062,10 +1253,10 @@ static int __devinit getstartupmode(struct fb_info *info)
        if (verbosity > 0)
                output("detected startup mode: "
                       "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
-                      modedb[0].xres,modedb[0].yres,modedb[0].xres,
-                      modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin,
-                      modedb[0].right_margin,modedb[0].upper_margin,
-                      modedb[0].lower_margin,modedb[0].hsync_len,
+                      modedb[0].xres, modedb[0].yres, modedb[0].xres,
+                      modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
+                      modedb[0].right_margin, modedb[0].upper_margin,
+                      modedb[0].lower_margin, modedb[0].hsync_len,
                       modedb[0].vsync_len);
 
        //
@@ -1073,36 +1264,39 @@ static int __devinit getstartupmode(struct fb_info *info)
        // do not want to do it in another way!
        //
 
-       tryagain:
+      tryagain:
 
        i = (mode == NULL) ? 0 :
-           !strncmp(mode,"640x480",7) ? 1 :
-           !strncmp(mode,"800x600",7) ? 2 :
-           !strncmp(mode,"1024x768",8) ? 3 :
-           !strncmp(mode,"1280x1024",9) ? 4 : 0;
+           !strncmp(mode, "640x480", 7) ? 1 :
+           !strncmp(mode, "800x600", 7) ? 2 :
+           !strncmp(mode, "1024x768", 8) ? 3 :
+           !strncmp(mode, "1280x1024", 9) ? 4 : 0;
 
        ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
 
-       if(i==0) {
+       if (i == 0) {
                info->var.pixclock = modedb[i].pxclk;
                info->var.bits_per_pixel = modedb[i].bpp;
        } else {
                info->var.pixclock = (100000000 /
-                       ((modedb[i].left_margin + modedb[i].xres +
-                         modedb[i].right_margin + modedb[i].hsync_len
-                        ) * (
-                         modedb[i].upper_margin + modedb[i].yres +
-                         modedb[i].lower_margin + modedb[i].vsync_len
-                        ) *
-                         ref / 10000
-                       ));
+                                     ((modedb[i].left_margin +
+                                       modedb[i].xres +
+                                       modedb[i].right_margin +
+                                       modedb[i].hsync_len) *
+                                      (modedb[i].upper_margin +
+                                       modedb[i].yres +
+                                       modedb[i].lower_margin +
+                                       modedb[i].vsync_len) * ref / 10000));
                info->var.bits_per_pixel = bpp;
        }
 
        info->var.left_margin = modedb[i].left_margin;
        info->var.right_margin = modedb[i].right_margin;
        info->var.xres = modedb[i].xres;
-       info->var.xres_virtual = modedb[i].xres;
+       if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
+               info->var.xres_virtual = modedb[i].vxres;
+       else
+               info->var.xres_virtual = modedb[i].xres;
        info->var.xoffset = 0;
        info->var.hsync_len = modedb[i].hsync_len;
        info->var.upper_margin = modedb[i].upper_margin;
@@ -1114,33 +1308,32 @@ static int __devinit getstartupmode(struct fb_info *info)
        info->var.sync = 0;
        info->var.vmode = FB_VMODE_NONINTERLACED;
 
-       if(cyblafb_check_var(&info->var,info)) {
-               // 640x480-8@75 should really never fail. One case would
+       if (cyblafb_check_var(&info->var, info)) {
+               // 640x480 - 8@75 should really never fail. One case would
                // be fp == 1 and nativex < 640 ... give up then
-               if(i==1 && bpp == 8 && ref == 75){
+               if (i == 1 && bpp == 8 && ref == 75) {
                        output("Can't find a valid mode :-(\n");
                        return -EINVAL;
                }
                // Our detected mode is unlikely to fail. If it does,
-               // try 640x480-8@75 ...
-               if(i==0) {
-                       mode="640x480";
-                       bpp=8;
-                       ref=75;
+               // try 640x480 - 8@75 ...
+               if (i == 0) {
+                       mode = "640x480";
+                       bpp = 8;
+                       ref = 75;
                        output("Detected mode failed check_var! "
-                              "Trying 640x480-8@75\n");
+                              "Trying 640x480 - 8@75\n");
                        goto tryagain;
                }
                // A specified video mode failed for some reason.
                // Try the startup mode first
                output("Specified mode '%s' failed check! "
-                       "Falling back to startup mode.\n",mode);
-               mode=NULL;
+                      "Falling back to startup mode.\n", mode);
+               mode = NULL;
                goto tryagain;
        }
 
        return 0;
-
 }
 
 //========================================================
@@ -1160,21 +1353,28 @@ static unsigned int __devinit get_memsize(void)
        else {
                tmp = read3X4(CR1F) & 0x0F;
                switch (tmp) {
-                       case 0x03: k = 1 * Mb; break;
-                       case 0x07: k = 2 * Mb; break;
-                       case 0x0F: k = 4 * Mb; break;
-                       case 0x04: k = 8 * Mb; break;
-                       default:
-                               k = 1 * Mb;
-                               output("Unknown memory size code %x in CR1F."
-                                      " We default to 1 Mb for now, please"
-                                      " do provide a memsize parameter!\n",
-                                      tmp);
+               case 0x03:
+                       k = 1 * 1024 * 1024;
+                       break;
+               case 0x07:
+                       k = 2 * 1024 * 1024;
+                       break;
+               case 0x0F:
+                       k = 4 * 1024 * 1024;
+                       break;
+               case 0x04:
+                       k = 8 * 1024 * 1024;
+                       break;
+               default:
+                       k = 1 * 1024 * 1024;
+                       output("Unknown memory size code %x in CR1F."
+                              " We default to 1 Mb for now, please"
+                              " do provide a memsize parameter!\n", tmp);
                }
        }
 
        if (verbosity > 0)
-               output("framebuffer size = %d Kb\n",k/Kb);
+               output("framebuffer size = %d Kb\n", k / Kb);
        return k;
 }
 
@@ -1192,7 +1392,7 @@ static unsigned int __devinit get_displaytype(void)
                return DISPLAY_FP;
        if (crt)
                return DISPLAY_CRT;
-       return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
+       return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
 }
 
 //=====================================
@@ -1203,7 +1403,7 @@ static unsigned int __devinit get_displaytype(void)
 
 static int __devinit get_nativex(void)
 {
-       int x,y,tmp;
+       int x, y, tmp;
 
        if (nativex)
                return nativex;
@@ -1211,29 +1411,45 @@ static int __devinit get_nativex(void)
        tmp = (read3CE(GR52) >> 4) & 3;
 
        switch (tmp) {
-               case 0:  x = 1280; y = 1024; break;
-               case 2:  x = 1024; y = 768;  break;
-               case 3:  x = 800;  y = 600;  break;
-               case 4:  x = 1400; y = 1050; break;
-               case 1:
-               default: x = 640;  y = 480;  break;
+       case 0: x = 1280; y = 1024;
+               break;
+       case 2: x = 1024; y = 768;
+               break;
+       case 3: x = 800;  y = 600;
+               break;
+       case 4: x = 1400; y = 1050;
+               break;
+       case 1:
+       default:
+               x = 640; y = 480;
+               break;
        }
 
        if (verbosity > 0)
-               output("%dx%d flat panel found\n",x,y);
+               output("%dx%d flat panel found\n", x, y);
        return x;
 }
 
-static int __devinit cybla_pci_probe(struct pci_dev * dev,
-                                    const struct pci_device_id * id)
+static int __devinit cybla_pci_probe(struct pci_dev *dev,
+                                    const struct pci_device_id *id)
 {
        struct fb_info *info;
        struct cyblafb_par *par;
 
-       info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev);
-
+       info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
        if (!info)
-               goto errout_alloc;
+               goto errout_alloc_info;
+
+       info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
+       if (!info->pixmap.addr) {
+               output("allocation of pixmap buffer failed!\n");
+               goto errout_alloc_pixmap;
+       }
+       info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
+       info->pixmap.buf_align = 4;
+       info->pixmap.access_align = 32;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+       info->pixmap.scan_align = 4;
 
        par = info->par;
        par->ops = cyblafb_ops;
@@ -1246,26 +1462,31 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev,
                output("could not enable device!\n");
                goto errout_enable;
        }
-
        // might already be requested by vga console or vesafb,
        // so we do care about success
-       request_region(0x3c0,32,"cyblafb");
+       if (!request_region(0x3c0, 0x20, "cyblafb")) {
+               output("region 0x3c0/0x20 already reserved\n");
+               vesafb |= 1;
 
+       }
        //
        // Graphics Engine Registers
        //
-       request_region(GEBase,0x100,"cyblafb");
+       if (!request_region(GEBase, 0x100, "cyblafb")) {
+               output("region %#x/0x100 already reserved\n", GEBase);
+               vesafb |= 2;
+       }
 
        regdump(par);
 
        enable_mmio();
 
        // setup MMIO region
-       info->fix.mmio_start = pci_resource_start(dev,1);
+       info->fix.mmio_start = pci_resource_start(dev, 1);
        info->fix.mmio_len = 0x20000;
 
        if (!request_mem_region(info->fix.mmio_start,
-                               info->fix.mmio_len,"cyblafb")) {
+                               info->fix.mmio_len, "cyblafb")) {
                output("request_mem_region failed for mmio region!\n");
                goto errout_mmio_reqmem;
        }
@@ -1276,18 +1497,17 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev,
                output("ioremap failed for mmio region\n");
                goto errout_mmio_remap;
        }
-
        // setup framebuffer memory ... might already be requested
        // by vesafb. Not to fail in case of an unsuccessful request
-       // is useful for the development cycle
-       info->fix.smem_start = pci_resource_start(dev,0);
+       // is useful if both are loaded.
+       info->fix.smem_start = pci_resource_start(dev, 0);
        info->fix.smem_len = get_memsize();
 
        if (!request_mem_region(info->fix.smem_start,
-                               info->fix.smem_len,"cyblafb")) {
-               output("request_mem_region failed for smem region!\n");
-               if (!vesafb)
-                       goto errout_smem_req;
+                               info->fix.smem_len, "cyblafb")) {
+               output("region %#lx/%#x already reserved\n",
+                      info->fix.smem_start, info->fix.smem_len);
+               vesafb |= 4;
        }
 
        info->screen_base = ioremap_nocache(info->fix.smem_start,
@@ -1300,31 +1520,30 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev,
 
        displaytype = get_displaytype();
 
-       if(displaytype == DISPLAY_FP)
+       if (displaytype == DISPLAY_FP)
                nativex = get_nativex();
 
-       //
-       // FBINFO_HWACCEL_YWRAP    .... does not work (could be made to work?)
-       // FBINFO_PARTIAL_PAN_OK   .... is not ok
-       // FBINFO_READS_FAST       .... is necessary for optimal scrolling
-       //
-       info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN
-                     | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT
-                     | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST;
+       info->flags = FBINFO_DEFAULT
+                   | FBINFO_HWACCEL_COPYAREA
+                   | FBINFO_HWACCEL_FILLRECT
+                   | FBINFO_HWACCEL_IMAGEBLIT
+                   | FBINFO_READS_FAST
+//                 | FBINFO_PARTIAL_PAN_OK
+                   | FBINFO_MISC_ALWAYS_SETPAR;
 
        info->pseudo_palette = par->pseudo_pal;
 
-       if(getstartupmode(info))
+       if (getstartupmode(info))
                goto errout_findmode;
 
-       fb_alloc_cmap(&info->cmap,256,0);
+       fb_alloc_cmap(&info->cmap, 256, 0);
 
        if (register_framebuffer(info)) {
                output("Could not register CyBla framebuffer\n");
                goto errout_register;
        }
 
-       pci_set_drvdata(dev,info);
+       pci_set_drvdata(dev, info);
 
        //
        // normal exit and error paths
@@ -1332,23 +1551,24 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev,
 
        return 0;
 
- errout_register:
- errout_findmode:
     errout_register:
     errout_findmode:
        iounmap(info->screen_base);
- errout_smem_remap:
-       release_mem_region(info->fix.smem_start,
-                          info->fix.smem_len);
- errout_smem_req:
+      errout_smem_remap:
+       if (!(vesafb & 4))
+               release_mem_region(info->fix.smem_start, info->fix.smem_len);
        iounmap(io_virt);
- errout_mmio_remap:
-       release_mem_region(info->fix.mmio_start,
-                          info->fix.mmio_len);
- errout_mmio_reqmem:
-//     release_region(0x3c0,32);
- errout_enable:
+      errout_mmio_remap:
+       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+      errout_mmio_reqmem:
+       if (!(vesafb & 1))
+               release_region(0x3c0, 32);
+      errout_enable:
+       kfree(info->pixmap.addr);
+      errout_alloc_pixmap:
        framebuffer_release(info);
errout_alloc:
-       output("CyblaFB version %s aborting init.\n",VERSION);
     errout_alloc_info:
+       output("CyblaFB version %s aborting init.\n", VERSION);
        return -ENODEV;
 }
 
@@ -1359,35 +1579,41 @@ static void __devexit cybla_pci_remove(struct pci_dev *dev)
        unregister_framebuffer(info);
        iounmap(io_virt);
        iounmap(info->screen_base);
-       release_mem_region(info->fix.smem_start,info->fix.smem_len);
-       release_mem_region(info->fix.mmio_start,info->fix.mmio_len);
+       if (!(vesafb & 4))
+               release_mem_region(info->fix.smem_start, info->fix.smem_len);
+       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
        fb_dealloc_cmap(&info->cmap);
+       if (!(vesafb & 2))
+               release_region(GEBase, 0x100);
+       if (!(vesafb & 1))
+               release_region(0x3c0, 32);
+       kfree(info->pixmap.addr);
        framebuffer_release(info);
-       output("CyblaFB version %s normal exit.\n",VERSION);
+       output("CyblaFB version %s normal exit.\n", VERSION);
 }
 
 //
 // List of boards that we are trying to support
 //
 static struct pci_device_id cybla_devices[] = {
-       {PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+       {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0,}
 };
 
-MODULE_DEVICE_TABLE(pci,cybla_devices);
+MODULE_DEVICE_TABLE(pci, cybla_devices);
 
 static struct pci_driver cyblafb_pci_driver = {
-       .name           = "cyblafb",
-       .id_table       = cybla_devices,
-       .probe          = cybla_pci_probe,
-       .remove         = __devexit_p(cybla_pci_remove)
+       .name = "cyblafb",
+       .id_table = cybla_devices,
+       .probe = cybla_pci_probe,
+       .remove = __devexit_p(cybla_pci_remove)
 };
 
 //=============================================================
 //
 // kernel command line example:
 //
-//     video=cyblafb:1280x1024,bpp=16,ref=50 ...
+//     video=cyblafb:1280x1024, bpp=16, ref=50 ...
 //
 // modprobe command line example:
 //
@@ -1401,45 +1627,44 @@ static int __devinit cyblafb_init(void)
        char *options = NULL;
        char *opt;
 
-       if (fb_get_options("cyblafb",&options))
+       if (fb_get_options("cyblafb", &options))
                return -ENODEV;
 
        if (options && *options)
-               while((opt = strsep(&options,",")) != NULL ) {
-                       if (!*opt) continue;
-                       else if (!strncmp(opt,"bpp=",4))
-                               bpp = simple_strtoul(opt+4,NULL,0);
-                       else if (!strncmp(opt,"ref=",4))
-                               ref = simple_strtoul(opt+4,NULL,0);
-                       else if (!strncmp(opt,"fp",2))
+               while ((opt = strsep(&options, ",")) != NULL) {
+                       if (!*opt)
+                               continue;
+                       else if (!strncmp(opt, "bpp=", 4))
+                               bpp = simple_strtoul(opt + 4, NULL, 0);
+                       else if (!strncmp(opt, "ref=", 4))
+                               ref = simple_strtoul(opt + 4, NULL, 0);
+                       else if (!strncmp(opt, "fp", 2))
                                displaytype = DISPLAY_FP;
-                       else if (!strncmp(opt,"crt",3))
+                       else if (!strncmp(opt, "crt", 3))
                                displaytype = DISPLAY_CRT;
-                       else if (!strncmp(opt,"nativex=",8))
-                               nativex = simple_strtoul(opt+8,NULL,0);
-                       else if (!strncmp(opt,"center",6))
+                       else if (!strncmp(opt, "nativex=", 8))
+                               nativex = simple_strtoul(opt + 8, NULL, 0);
+                       else if (!strncmp(opt, "center", 6))
                                center = 1;
-                       else if (!strncmp(opt,"stretch",7))
+                       else if (!strncmp(opt, "stretch", 7))
                                stretch = 1;
-                       else if (!strncmp(opt,"pciwb=",6))
-                               pciwb = simple_strtoul(opt+6,NULL,0);
-                       else if (!strncmp(opt,"pcirb=",6))
-                               pcirb = simple_strtoul(opt+6,NULL,0);
-                       else if (!strncmp(opt,"pciwr=",6))
-                               pciwr = simple_strtoul(opt+6,NULL,0);
-                       else if (!strncmp(opt,"pcirr=",6))
-                               pcirr = simple_strtoul(opt+6,NULL,0);
-                       else if (!strncmp(opt,"memsize=",8))
-                               memsize = simple_strtoul(opt+8,NULL,0);
-                       else if (!strncmp(opt,"verbosity=",10))
-                               verbosity = simple_strtoul(opt+10,NULL,0);
-                       else if (!strncmp(opt,"vesafb",6))
-                               vesafb = 1;
+                       else if (!strncmp(opt, "pciwb=", 6))
+                               pciwb = simple_strtoul(opt + 6, NULL, 0);
+                       else if (!strncmp(opt, "pcirb=", 6))
+                               pcirb = simple_strtoul(opt + 6, NULL, 0);
+                       else if (!strncmp(opt, "pciwr=", 6))
+                               pciwr = simple_strtoul(opt + 6, NULL, 0);
+                       else if (!strncmp(opt, "pcirr=", 6))
+                               pcirr = simple_strtoul(opt + 6, NULL, 0);
+                       else if (!strncmp(opt, "memsize=", 8))
+                               memsize = simple_strtoul(opt + 8, NULL, 0);
+                       else if (!strncmp(opt, "verbosity=", 10))
+                               verbosity = simple_strtoul(opt + 10, NULL, 0);
                        else
                                mode = opt;
                }
 #endif
-       output("CyblaFB version %s initializing\n",VERSION);
+       output("CyblaFB version %s initializing\n", VERSION);
        return pci_module_init(&cyblafb_pci_driver);
 }
 
index 00d87f5bb7be0ed8f854d34b742f75e6e97807e2..ad1434e3f2277ff33bbc5dad7224ceff8e7da4a5 100644 (file)
@@ -223,6 +223,7 @@ static int offb_blank(int blank, struct fb_info *info)
 int __init offb_init(void)
 {
        struct device_node *dp = NULL, *boot_disp = NULL;
+
 #if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
        struct device_node *macos_display = NULL;
 #endif
@@ -234,60 +235,54 @@ int __init offb_init(void)
        if (boot_infos != 0) {
                unsigned long addr =
                    (unsigned long) boot_infos->dispDeviceBase;
+               u32 *addrp;
+               u64 daddr, dsize;
+               unsigned int flags;
+
                /* find the device node corresponding to the macos display */
                while ((dp = of_find_node_by_type(dp, "display"))) {
                        int i;
-                       /*
-                        * Grrr...  It looks like the MacOS ATI driver
-                        * munges the assigned-addresses property (but
-                        * the AAPL,address value is OK).
-                        */
-                       if (strncmp(dp->name, "ATY,", 4) == 0
-                           && dp->n_addrs == 1) {
-                               unsigned int *ap =
-                                   (unsigned int *) get_property(dp,
-                                                                 "AAPL,address",
-                                                                 NULL);
-                               if (ap != NULL) {
-                                       dp->addrs[0].address = *ap;
-                                       dp->addrs[0].size = 0x01000000;
-                               }
-                       }
 
                        /*
-                        * The LTPro on the Lombard powerbook has no addresses
-                        * on the display nodes, they are on their parent.
+                        * Look for an AAPL,address property first.
                         */
-                       if (dp->n_addrs == 0
-                           && device_is_compatible(dp, "ATY,264LTPro")) {
-                               int na;
-                               unsigned int *ap = (unsigned int *)
-                                   get_property(dp, "AAPL,address", &na);
-                               if (ap != 0)
-                                       for (na /= sizeof(unsigned int);
-                                            na > 0; --na, ++ap)
-                                               if (*ap <= addr
-                                                   && addr <
-                                                   *ap + 0x1000000)
-                                                       goto foundit;
+                       unsigned int na;
+                       unsigned int *ap =
+                               (unsigned int *)get_property(dp, "AAPL,address",
+                                                            &na);
+                       if (ap != 0) {
+                               for (na /= sizeof(unsigned int); na > 0;
+                                    --na, ++ap)
+                                       if (*ap <= addr &&
+                                           addr < *ap + 0x1000000) {
+                                               macos_display = dp;
+                                               goto foundit;
+                                       }
                        }
 
                        /*
                         * See if the display address is in one of the address
                         * ranges for this display.
                         */
-                       for (i = 0; i < dp->n_addrs; ++i) {
-                               if (dp->addrs[i].address <= addr
-                                   && addr <
-                                   dp->addrs[i].address +
-                                   dp->addrs[i].size)
+                       i = 0;
+                       for (;;) {
+                               addrp = of_get_address(dp, i++, &dsize, &flags);
+                               if (addrp == NULL)
                                        break;
+                               if (!(flags & IORESOURCE_MEM))
+                                       continue;
+                               daddr = of_translate_address(dp, addrp);
+                               if (daddr == OF_BAD_ADDR)
+                                       continue;
+                               if (daddr <= addr && addr < (daddr + dsize)) {
+                                       macos_display = dp;
+                                       goto foundit;
+                               }
                        }
-                       if (i < dp->n_addrs) {
-                             foundit:
+               foundit:
+                       if (macos_display) {
                                printk(KERN_INFO "MacOS display is %s\n",
                                       dp->full_name);
-                               macos_display = dp;
                                break;
                        }
                }
@@ -326,8 +321,10 @@ static void __init offb_init_nodriver(struct device_node *dp)
        int *pp, i;
        unsigned int len;
        int width = 640, height = 480, depth = 8, pitch;
-       unsigned int rsize, *up;
-       unsigned long address = 0;
+       unsigned int flags, rsize, *up;
+       u64 address = OF_BAD_ADDR;
+       u32 *addrp;
+       u64 asize;
 
        if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
            && len == sizeof(int))
@@ -363,7 +360,7 @@ static void __init offb_init_nodriver(struct device_node *dp)
                                break;
               }
                if (pdev) {
-                       for (i = 0; i < 6 && address == 0; i++) {
+                       for (i = 0; i < 6 && address == OF_BAD_ADDR; i++) {
                                if ((pci_resource_flags(pdev, i) &
                                    IORESOURCE_MEM) &&
                                   (pci_resource_len(pdev, i) >= rsize))
@@ -374,27 +371,33 @@ static void __init offb_init_nodriver(struct device_node *dp)
         }
 #endif /* CONFIG_PCI */
 
-       if (address == 0 &&
-           (up = (unsigned *) get_property(dp, "address", &len)) != NULL &&
-           len == sizeof(unsigned))
-               address = (u_long) * up;
-       if (address == 0) {
-               for (i = 0; i < dp->n_addrs; ++i)
-                       if (dp->addrs[i].size >=
-                           pitch * height * depth / 8)
-                               break;
-               if (i >= dp->n_addrs) {
+       /* This one is dodgy, we may drop it ... */
+       if (address == OF_BAD_ADDR &&
+          (up = (unsigned *) get_property(dp, "address", &len)) != NULL &&
+          len == sizeof(unsigned int))
+              address = (u64) * up;
+
+       if (address == OF_BAD_ADDR) {
+              for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
+                           != NULL; i++) {
+                      if (!(flags & IORESOURCE_MEM))
+                              continue;
+                      if (asize >= pitch * height * depth / 8)
+                              break;
+              }
+               if (addrp == NULL) {
                        printk(KERN_ERR
                               "no framebuffer address found for %s\n",
                               dp->full_name);
                        return;
                }
-
-               address = (u_long) dp->addrs[i].address;
-
-#ifdef CONFIG_PPC64
-               address += ((struct pci_dn *)dp->data)->phb->pci_mem_offset;
-#endif
+               address = of_translate_address(dp, addrp);
+               if (address == OF_BAD_ADDR) {
+                       printk(KERN_ERR
+                              "can't translate framebuffer address for %s\n",
+                              dp->full_name);
+                       return;
+               }
 
                /* kludge for valkyrie */
                if (strcmp(dp->name, "valkyrie") == 0)
@@ -459,7 +462,9 @@ static void __init offb_init_fb(const char *name, const char *full_name,
 
        par->cmap_type = cmap_unknown;
        if (depth == 8) {
-               /* XXX kludge for ati */
+
+               /* Palette hacks disabled for now */
+#if 0
                if (dp && !strncmp(name, "ATY,Rage128", 11)) {
                        unsigned long regbase = dp->addrs[2].address;
                        par->cmap_adr = ioremap(regbase, 0x1FFF);
@@ -490,6 +495,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
                        par->cmap_adr = ioremap(regbase + 0x6000, 0x1000);
                        par->cmap_type = cmap_gxt2000;
                }
+#endif
                fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
                    : FB_VISUAL_STATIC_PSEUDOCOLOR;
        } else
index ca4082ae5a18d34313a3a71c7ef2b34b977a484e..335e3746555983bb4678c325fef450aab47f75ef 100644 (file)
@@ -69,6 +69,8 @@ struct fb_info_platinum {
        unsigned long                   total_vram;
        int                             clktype;
        int                             dactype;
+
+       struct resource                 rsrc_fb, rsrc_reg;
 };
 
 /*
@@ -97,9 +99,6 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var,
  * Interface used by the world
  */
 
-int platinumfb_init(void);
-int platinumfb_setup(char*);
-
 static struct fb_ops platinumfb_ops = {
        .owner =        THIS_MODULE,
        .fb_check_var   = platinumfb_check_var,
@@ -138,13 +137,15 @@ static int platinumfb_set_par (struct fb_info *info)
 
        init = platinum_reg_init[pinfo->vmode-1];
        
-       if (pinfo->vmode == 13 && pinfo->cmode > 0)
-               offset = 0x10;
+       if ((pinfo->vmode == VMODE_832_624_75) && (pinfo->cmode > CMODE_8))
+               offset = 0x10;
+
        info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
        info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
        info->fix.visual = (pinfo->cmode == CMODE_8) ?
                FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
-       info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) + offset;
+       info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode)
+               + offset;
        printk("line_length: %x\n", info->fix.line_length);
        return 0;
 }
@@ -221,7 +222,9 @@ static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 static inline int platinum_vram_reqd(int video_mode, int color_mode)
 {
        return vmode_attrs[video_mode-1].vres *
-              (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20) +0x1000;
+              (vmode_attrs[video_mode-1].hres * (1<<color_mode) +
+               ((video_mode == VMODE_832_624_75) &&
+                (color_mode > CMODE_8)) ? 0x10 : 0x20) + 0x1000;
 }
 
 #define STORE_D2(a, d) { \
@@ -481,7 +484,7 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var,
 /* 
  * Parse user speficied options (`video=platinumfb:')
  */
-int __init platinumfb_setup(char *options)
+static int __init platinumfb_setup(char *options)
 {
        char *this_opt;
 
@@ -522,19 +525,15 @@ int __init platinumfb_setup(char *options)
 #define invalidate_cache(addr)
 #endif
 
-static int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match)
+static int __devinit platinumfb_probe(struct of_device* odev,
+                                     const struct of_device_id *match)
 {
        struct device_node      *dp = odev->node;
        struct fb_info          *info;
        struct fb_info_platinum *pinfo;
-       unsigned long           addr, size;
        volatile __u8           *fbuffer;
-       int                     i, bank0, bank1, bank2, bank3, rc;
+       int                     bank0, bank1, bank2, bank3, rc;
 
-       if (dp->n_addrs != 2) {
-               printk(KERN_ERR "expecting 2 address for platinum (got %d)", dp->n_addrs);
-               return -ENXIO;
-       }
        printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n");
 
        info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
@@ -542,26 +541,39 @@ static int __devinit platinumfb_probe(struct of_device* odev, const struct of_de
                return -ENOMEM;
        pinfo = info->par;
 
-       /* Map in frame buffer and registers */
-       for (i = 0; i < dp->n_addrs; ++i) {
-               addr = dp->addrs[i].address;
-               size = dp->addrs[i].size;
-               /* Let's assume we can request either all or nothing */
-               if (!request_mem_region(addr, size, "platinumfb")) {
-                       framebuffer_release(info);
-                       return -ENXIO;
-               }
-               if (size >= 0x400000) {
-                       /* frame buffer - map only 4MB */
-                       pinfo->frame_buffer_phys = addr;
-                       pinfo->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
-                       pinfo->base_frame_buffer = pinfo->frame_buffer;
-               } else {
-                       /* registers */
-                       pinfo->platinum_regs_phys = addr;
-                       pinfo->platinum_regs = ioremap(addr, size);
-               }
+       if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
+           of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) {
+               printk(KERN_ERR "platinumfb: Can't get resources\n");
+               framebuffer_release(info);
+               return -ENXIO;
        }
+       if (!request_mem_region(pinfo->rsrc_reg.start,
+                               pinfo->rsrc_reg.start -
+                               pinfo->rsrc_reg.end + 1,
+                               "platinumfb registers")) {
+               framebuffer_release(info);
+               return -ENXIO;
+       }
+       if (!request_mem_region(pinfo->rsrc_fb.start,
+                               pinfo->rsrc_fb.start
+                               - pinfo->rsrc_fb.end + 1,
+                               "platinumfb framebuffer")) {
+               release_mem_region(pinfo->rsrc_reg.start,
+                                  pinfo->rsrc_reg.end -
+                                  pinfo->rsrc_reg.start + 1);
+               framebuffer_release(info);
+               return -ENXIO;
+       }
+
+       /* frame buffer - map only 4MB */
+       pinfo->frame_buffer_phys = pinfo->rsrc_fb.start;
+       pinfo->frame_buffer = __ioremap(pinfo->rsrc_fb.start, 0x400000,
+                                       _PAGE_WRITETHRU);
+       pinfo->base_frame_buffer = pinfo->frame_buffer;
+
+       /* registers */
+       pinfo->platinum_regs_phys = pinfo->rsrc_reg.start;
+       pinfo->platinum_regs = ioremap(pinfo->rsrc_reg.start, 0x1000);
 
        pinfo->cmap_regs_phys = 0xf301b000;     /* XXX not in prom? */
        request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap");
@@ -624,18 +636,16 @@ static int __devexit platinumfb_remove(struct of_device* odev)
 {
        struct fb_info          *info = dev_get_drvdata(&odev->dev);
        struct fb_info_platinum *pinfo = info->par;
-       struct device_node *dp = odev->node;
-       unsigned long addr, size;
-       int i;
        
         unregister_framebuffer (info);
        
        /* Unmap frame buffer and registers */
-       for (i = 0; i < dp->n_addrs; ++i) {
-               addr = dp->addrs[i].address;
-               size = dp->addrs[i].size;
-               release_mem_region(addr, size);
-       }
+       release_mem_region(pinfo->rsrc_fb.start,
+                          pinfo->rsrc_fb.end -
+                          pinfo->rsrc_fb.start + 1);
+       release_mem_region(pinfo->rsrc_reg.start,
+                          pinfo->rsrc_reg.end -
+                          pinfo->rsrc_reg.start + 1);
        iounmap(pinfo->frame_buffer);
        iounmap(pinfo->platinum_regs);
        release_mem_region(pinfo->cmap_regs_phys, 0x1000);
@@ -662,7 +672,7 @@ static struct of_platform_driver platinum_driver =
        .remove         = platinumfb_remove,
 };
 
-int __init platinumfb_init(void)
+static int __init platinumfb_init(void)
 {
 #ifndef MODULE
        char *option = NULL;
@@ -676,7 +686,7 @@ int __init platinumfb_init(void)
        return 0;
 }
 
-void __exit platinumfb_exit(void)
+static void __exit platinumfb_exit(void)
 {
        of_unregister_driver(&platinum_driver); 
 }
index 2834fc1c344b3400bbef8a90b3576c190e8e6d45..f6bd77cafd174b3224a99ab6fba5c67687ac505f 100644 (file)
@@ -158,7 +158,9 @@ static struct platinum_regvals platinum_reg_init_14 = {
 /* 832x624, 75Hz (13) */
 static struct platinum_regvals platinum_reg_init_13 = {
        0x70,
-       { 864, 1680, 3360 },    /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+       { 864, 1680, 3344 },    /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB,
+                                * and we use 3344 instead of 3360 to fit in 2Mb
+                                */
        { 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
          0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
          0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
index ce97ec8eae9756792d150ed33e7391dfe7583c7d..2bdeb4baa9529c53426a76dfd27a9b3afbee9c2d 100644 (file)
@@ -342,19 +342,19 @@ int __init valkyriefb_init(void)
 #else /* ppc (!CONFIG_MAC) */
        {
                struct device_node *dp;
+               struct resource r;
 
-               dp = find_devices("valkyrie");
+               dp = of_find_node_by_name(NULL, "valkyrie");
                if (dp == 0)
                        return 0;
 
-               if (dp->n_addrs != 1) {
-                       printk(KERN_ERR "expecting 1 address for valkyrie (got %d)\n",
-                              dp->n_addrs);
+               if (of_address_to_resource(dp, 0, &r)) {
+                       printk(KERN_ERR "can't find address for valkyrie\n");
                        return 0;
                }
 
-               frame_buffer_phys = dp->addrs[0].address;
-               cmap_regs_phys = dp->addrs[0].address+0x304000;
+               frame_buffer_phys = r.start;
+               cmap_regs_phys = r.start + 0x304000;
                flags = _PAGE_WRITETHRU;
        }
 #endif /* ppc (!CONFIG_MAC) */
index e847f504a47c7e807f0fe97ad191b9164eb54320..1a6d08761f3942da8e56c3f79518bbfc32bf09ac 100644 (file)
@@ -1,8 +1,9 @@
 /*
  *  linux/fs/9p/9p.c
  *
- *  This file contains functions 9P2000 functions
+ *  This file contains functions to perform synchronous 9P calls
  *
+ *  Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
@@ -33,6 +34,7 @@
 #include "debug.h"
 #include "v9fs.h"
 #include "9p.h"
+#include "conv.h"
 #include "mux.h"
 
 /**
 
 int
 v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
-              char *version, struct v9fs_fcall **fcall)
+              char *version, struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall *tc;
 
        dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
-       msg.id = TVERSION;
-       msg.params.tversion.msize = msize;
-       msg.params.tversion.version = version;
+       tc = v9fs_create_tversion(msize, version);
 
-       return v9fs_mux_rpc(v9ses, &msg, fcall);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
 }
 
 /**
@@ -71,19 +78,45 @@ v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
 
 int
 v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
-             u32 fid, u32 afid, struct v9fs_fcall **fcall)
+             u32 fid, u32 afid, struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall* tc;
 
        dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
                aname, fid, afid);
-       msg.id = TATTACH;
-       msg.params.tattach.fid = fid;
-       msg.params.tattach.afid = afid;
-       msg.params.tattach.uname = uname;
-       msg.params.tattach.aname = aname;
 
-       return v9fs_mux_rpc(v9ses, &msg, fcall);
+       tc = v9fs_create_tattach(fid, afid, uname, aname);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
+       struct v9fs_fcall *rc, int err)
+{
+       int fid;
+       struct v9fs_session_info *v9ses;
+
+       if (err)
+               return;
+
+       fid = tc->params.tclunk.fid;
+       kfree(tc);
+
+       if (!rc)
+               return;
+
+       dprintk(DEBUG_9P, "tcall id %d rcall id %d\n", tc->id, rc->id);
+       v9ses = a;
+       if (rc->id == RCLUNK)
+               v9fs_put_idpool(fid, &v9ses->fidpool);
+
+       kfree(rc);
 }
 
 /**
@@ -95,16 +128,25 @@ v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
  */
 
 int
-v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid,
-            struct v9fs_fcall **fcall)
+v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall *tc, *rc;
 
        dprintk(DEBUG_9P, "fid %d\n", fid);
-       msg.id = TCLUNK;
-       msg.params.tclunk.fid = fid;
 
-       return v9fs_mux_rpc(v9ses, &msg, fcall);
+       rc = NULL;
+       tc = v9fs_create_tclunk(fid);
+       if (!IS_ERR(tc))
+               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
+       else
+               ret = PTR_ERR(tc);
+
+       if (ret)
+               dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);
+
+       v9fs_t_clunk_cb(v9ses, tc, rc, ret);
+       return ret;
 }
 
 /**
@@ -114,14 +156,21 @@ v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid,
  *
  */
 
-int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag)
+int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
+
+       tc = v9fs_create_tflush(oldtag);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
 
-       dprintk(DEBUG_9P, "oldtag %d\n", tag);
-       msg.id = TFLUSH;
-       msg.params.tflush.oldtag = tag;
-       return v9fs_mux_rpc(v9ses, &msg, NULL);
+       return ret;
 }
 
 /**
@@ -133,17 +182,22 @@ int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag)
  */
 
 int
-v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall)
+v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall *tc;
 
        dprintk(DEBUG_9P, "fid %d\n", fid);
-       if (fcall)
-               *fcall = NULL;
 
-       msg.id = TSTAT;
-       msg.params.tstat.fid = fid;
-       return v9fs_mux_rpc(v9ses, &msg, fcall);
+       ret = -ENOMEM;
+       tc = v9fs_create_tstat(fid);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
 }
 
 /**
@@ -157,16 +211,21 @@ v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall)
 
 int
 v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
-            struct v9fs_stat *stat, struct v9fs_fcall **fcall)
+            struct v9fs_wstat *wstat, struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "fid %d\n", fid);
 
-       dprintk(DEBUG_9P, "fid %d length %d\n", fid, (int)stat->length);
-       msg.id = TWSTAT;
-       msg.params.twstat.fid = fid;
-       msg.params.twstat.stat = stat;
+       tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
 
-       return v9fs_mux_rpc(v9ses, &msg, fcall);
+       return ret;
 }
 
 /**
@@ -183,23 +242,27 @@ v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
 
 int
 v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
-           char *name, struct v9fs_fcall **fcall)
+           char *name, struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall *tc;
+       int nwname;
 
        dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
-       msg.id = TWALK;
-       msg.params.twalk.fid = fid;
-       msg.params.twalk.newfid = newfid;
-
-       if (name) {
-               msg.params.twalk.nwname = 1;
-               msg.params.twalk.wnames = &name;
-       } else {
-               msg.params.twalk.nwname = 0;
-       }
-
-       return v9fs_mux_rpc(v9ses, &msg, fcall);
+
+       if (name)
+               nwname = 1;
+       else
+               nwname = 0;
+
+       tc = v9fs_create_twalk(fid, newfid, nwname, &name);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
 }
 
 /**
@@ -214,19 +277,21 @@ v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
 
 int
 v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
-           struct v9fs_fcall **fcall)
+           struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
-       long errorno = -1;
+       int ret;
+       struct v9fs_fcall *tc;
 
        dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
-       msg.id = TOPEN;
-       msg.params.topen.fid = fid;
-       msg.params.topen.mode = mode;
 
-       errorno = v9fs_mux_rpc(v9ses, &msg, fcall);
+       tc = v9fs_create_topen(fid, mode);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
 
-       return errorno;
+       return ret;
 }
 
 /**
@@ -239,14 +304,21 @@ v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
 
 int
 v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
-             struct v9fs_fcall **fcall)
+             struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall *tc;
 
        dprintk(DEBUG_9P, "fid %d\n", fid);
-       msg.id = TREMOVE;
-       msg.params.tremove.fid = fid;
-       return v9fs_mux_rpc(v9ses, &msg, fcall);
+
+       tc = v9fs_create_tremove(fid);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
 }
 
 /**
@@ -262,20 +334,22 @@ v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
 
 int
 v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
-             u32 perm, u8 mode, struct v9fs_fcall **fcall)
+             u32 perm, u8 mode, struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
+       int ret;
+       struct v9fs_fcall *tc;
 
        dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
                fid, name, perm, mode);
 
-       msg.id = TCREATE;
-       msg.params.tcreate.fid = fid;
-       msg.params.tcreate.name = name;
-       msg.params.tcreate.perm = perm;
-       msg.params.tcreate.mode = mode;
+       tc = v9fs_create_tcreate(fid, name, perm, mode);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
 
-       return v9fs_mux_rpc(v9ses, &msg, fcall);
+       return ret;
 }
 
 /**
@@ -290,31 +364,29 @@ v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
 
 int
 v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
-           u32 count, struct v9fs_fcall **fcall)
+           u32 count, struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
-       struct v9fs_fcall *rc = NULL;
-       long errorno = -1;
-
-       dprintk(DEBUG_9P, "fid %d offset 0x%lx count 0x%x\n", fid,
-               (long unsigned int)offset, count);
-       msg.id = TREAD;
-       msg.params.tread.fid = fid;
-       msg.params.tread.offset = offset;
-       msg.params.tread.count = count;
-       errorno = v9fs_mux_rpc(v9ses, &msg, &rc);
-
-       if (!errorno) {
-               errorno = rc->params.rread.count;
-               dump_data(rc->params.rread.data, rc->params.rread.count);
-       }
-
-       if (fcall)
-               *fcall = rc;
-       else
-               kfree(rc);
-
-       return errorno;
+       int ret;
+       struct v9fs_fcall *tc, *rc;
+
+       dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
+               (long long unsigned) offset, count);
+
+       tc = v9fs_create_tread(fid, offset, count);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
+               if (!ret)
+                       ret = rc->params.rread.count;
+               if (rcp)
+                       *rcp = rc;
+               else
+                       kfree(rc);
+
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
 }
 
 /**
@@ -328,32 +400,30 @@ v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
  */
 
 int
-v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid,
-            u64 offset, u32 count, void *data, struct v9fs_fcall **fcall)
+v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count,
+       const char __user *data, struct v9fs_fcall **rcp)
 {
-       struct v9fs_fcall msg;
-       struct v9fs_fcall *rc = NULL;
-       long errorno = -1;
+       int ret;
+       struct v9fs_fcall *tc, *rc;
 
-       dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid,
-               (unsigned long long)offset, count);
-       dump_data(data, count);
+       dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
+               (long long unsigned) offset, count);
 
-       msg.id = TWRITE;
-       msg.params.twrite.fid = fid;
-       msg.params.twrite.offset = offset;
-       msg.params.twrite.count = count;
-       msg.params.twrite.data = data;
+       tc = v9fs_create_twrite(fid, offset, count, data);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
 
-       errorno = v9fs_mux_rpc(v9ses, &msg, &rc);
+               if (!ret)
+                       ret = rc->params.rwrite.count;
+               if (rcp)
+                       *rcp = rc;
+               else
+                       kfree(rc);
 
-       if (!errorno)
-               errorno = rc->params.rwrite.count;
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
 
-       if (fcall)
-               *fcall = rc;
-       else
-               kfree(rc);
-
-       return errorno;
+       return ret;
 }
+
index f55424216be236e07bde9b5bb831b36b2816bc70..0cd374d94717f073646373d5f9e73ebf3eb05938 100644 (file)
@@ -3,6 +3,7 @@
  *
  * 9P protocol definitions.
  *
+ *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
@@ -100,9 +101,18 @@ enum {
        V9FS_QTFILE = 0x00,
 };
 
+#define V9FS_NOTAG     (u16)(~0)
+#define V9FS_NOFID     (u32)(~0)
+#define V9FS_MAXWELEM  16
+
 /* ample room for Twrite/Rread header (iounit) */
 #define V9FS_IOHDRSZ   24
 
+struct v9fs_str {
+       u16 len;
+       char *str;
+};
+
 /* qids are the unique ID for a file (like an inode */
 struct v9fs_qid {
        u8 type;
@@ -112,6 +122,29 @@ struct v9fs_qid {
 
 /* Plan 9 file metadata (stat) structure */
 struct v9fs_stat {
+       u16 size;
+       u16 type;
+       u32 dev;
+       struct v9fs_qid qid;
+       u32 mode;
+       u32 atime;
+       u32 mtime;
+       u64 length;
+       struct v9fs_str name;
+       struct v9fs_str uid;
+       struct v9fs_str gid;
+       struct v9fs_str muid;
+       struct v9fs_str extension;      /* 9p2000.u extensions */
+       u32 n_uid;              /* 9p2000.u extensions */
+       u32 n_gid;              /* 9p2000.u extensions */
+       u32 n_muid;             /* 9p2000.u extensions */
+};
+
+/* file metadata (stat) structure used to create Twstat message
+   The is similar to v9fs_stat, but the strings don't point to
+   the same memory block and should be freed separately
+*/
+struct v9fs_wstat {
        u16 size;
        u16 type;
        u32 dev;
@@ -128,25 +161,24 @@ struct v9fs_stat {
        u32 n_uid;              /* 9p2000.u extensions */
        u32 n_gid;              /* 9p2000.u extensions */
        u32 n_muid;             /* 9p2000.u extensions */
-       char data[0];
 };
 
 /* Structures for Protocol Operations */
 
 struct Tversion {
        u32 msize;
-       char *version;
+       struct v9fs_str version;
 };
 
 struct Rversion {
        u32 msize;
-       char *version;
+       struct v9fs_str version;
 };
 
 struct Tauth {
        u32 afid;
-       char *uname;
-       char *aname;
+       struct v9fs_str uname;
+       struct v9fs_str aname;
 };
 
 struct Rauth {
@@ -154,12 +186,12 @@ struct Rauth {
 };
 
 struct Rerror {
-       char *error;
+       struct v9fs_str error;
        u32 errno;              /* 9p2000.u extension */
 };
 
 struct Tflush {
-       u32 oldtag;
+       u16 oldtag;
 };
 
 struct Rflush {
@@ -168,8 +200,8 @@ struct Rflush {
 struct Tattach {
        u32 fid;
        u32 afid;
-       char *uname;
-       char *aname;
+       struct v9fs_str uname;
+       struct v9fs_str aname;
 };
 
 struct Rattach {
@@ -179,13 +211,13 @@ struct Rattach {
 struct Twalk {
        u32 fid;
        u32 newfid;
-       u32 nwname;
-       char **wnames;
+       u16 nwname;
+       struct v9fs_str wnames[16];
 };
 
 struct Rwalk {
-       u32 nwqid;
-       struct v9fs_qid *wqids;
+       u16 nwqid;
+       struct v9fs_qid wqids[16];
 };
 
 struct Topen {
@@ -200,7 +232,7 @@ struct Ropen {
 
 struct Tcreate {
        u32 fid;
-       char *name;
+       struct v9fs_str name;
        u32 perm;
        u8 mode;
 };
@@ -251,12 +283,12 @@ struct Tstat {
 };
 
 struct Rstat {
-       struct v9fs_stat *stat;
+       struct v9fs_stat stat;
 };
 
 struct Twstat {
        u32 fid;
-       struct v9fs_stat *stat;
+       struct v9fs_stat stat;
 };
 
 struct Rwstat {
@@ -271,6 +303,7 @@ struct v9fs_fcall {
        u32 size;
        u8 id;
        u16 tag;
+       void *sdata;
 
        union {
                struct Tversion tversion;
@@ -303,7 +336,9 @@ struct v9fs_fcall {
        } params;
 };
 
-#define FCALL_ERROR(fcall) (fcall ? fcall->params.rerror.error : "")
+#define PRINT_FCALL_ERROR(s, fcall) dprintk(DEBUG_ERROR, "%s: %.*s\n", s, \
+       fcall?fcall->params.rerror.error.len:0, \
+       fcall?fcall->params.rerror.error.str:"");
 
 int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
                   char *version, struct v9fs_fcall **rcall);
@@ -311,8 +346,7 @@ int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
 int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
                  u32 fid, u32 afid, struct v9fs_fcall **rcall);
 
-int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid,
-                struct v9fs_fcall **rcall);
+int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid);
 
 int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag);
 
@@ -320,7 +354,7 @@ int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid,
                struct v9fs_fcall **rcall);
 
 int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
-                struct v9fs_stat *stat, struct v9fs_fcall **rcall);
+                struct v9fs_wstat *wstat, struct v9fs_fcall **rcall);
 
 int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
                char *name, struct v9fs_fcall **rcall);
@@ -338,4 +372,5 @@ int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
                u64 offset, u32 count, struct v9fs_fcall **rcall);
 
 int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
-                u32 count, void *data, struct v9fs_fcall **rcall);
+                u32 count, const char __user * data,
+                struct v9fs_fcall **rcall);
index e4e4ffe5a7dc5068a8461022d5f1282fef37bc3b..3d023089707efe87df1d17e276ae8598971db1ee 100644 (file)
@@ -1,17 +1,17 @@
 obj-$(CONFIG_9P_FS) := 9p2000.o
 
 9p2000-objs := \
+       trans_fd.o \
+       trans_sock.o \
+       mux.o \
+       9p.o \
+       conv.o \
        vfs_super.o \
        vfs_inode.o \
        vfs_file.o \
        vfs_dir.o \
        vfs_dentry.o \
        error.o \
-       mux.o \
-       trans_fd.o \
-       trans_sock.o \
-       9p.o \
-       conv.o \
        v9fs.o \
        fid.o
 
index 18121af99d3ef141cb5b641538defb6f1301c008..55ccfa10ee9eeed3cf65f3efd855468b9125b88e 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
-
+#include <asm/uaccess.h>
 #include "debug.h"
 #include "v9fs.h"
 #include "9p.h"
@@ -58,12 +58,15 @@ static inline int buf_check_overflow(struct cbuf *buf)
 
 static inline int buf_check_size(struct cbuf *buf, int len)
 {
-       if (buf->p+len > buf->ep) {
+       if (buf->p + len > buf->ep) {
                if (buf->p < buf->ep) {
-                       eprintk(KERN_ERR, "buffer overflow\n");
+                       eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
+                               len, (int)(buf->ep - buf->p));
+                       dump_stack();
                        buf->p = buf->ep + 1;
-                       return 0;
                }
+
+               return 0;
        }
 
        return 1;
@@ -127,14 +130,6 @@ static inline void buf_put_string(struct cbuf *buf, const char *s)
        buf_put_stringn(buf, s, strlen(s));
 }
 
-static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen)
-{
-       if (buf_check_size(buf, datalen)) {
-               memcpy(buf->p, data, datalen);
-               buf->p += datalen;
-       }
-}
-
 static inline u8 buf_get_int8(struct cbuf *buf)
 {
        u8 ret = 0;
@@ -183,86 +178,37 @@ static inline u64 buf_get_int64(struct cbuf *buf)
        return ret;
 }
 
-static inline int
-buf_get_string(struct cbuf *buf, char *data, unsigned int datalen)
-{
-       u16 len = 0;
-
-       len = buf_get_int16(buf);
-       if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) {
-               memcpy(data, buf->p, len);
-               data[len] = 0;
-               buf->p += len;
-               len++;
-       }
-
-       return len;
-}
-
-static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf)
-{
-       char *ret;
-       u16 len;
-
-       ret = NULL;
-       len = buf_get_int16(buf);
-
-       if (!buf_check_overflow(buf) && buf_check_size(buf, len) &&
-               buf_check_size(sbuf, len+1)) {
-
-               memcpy(sbuf->p, buf->p, len);
-               sbuf->p[len] = 0;
-               ret = sbuf->p;
-               buf->p += len;
-               sbuf->p += len + 1;
-       }
-
-       return ret;
-}
-
-static inline int buf_get_data(struct cbuf *buf, void *data, int datalen)
+static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
 {
-       int ret = 0;
-
-       if (buf_check_size(buf, datalen)) {
-               memcpy(data, buf->p, datalen);
-               buf->p += datalen;
-               ret = datalen;
+       vstr->len = buf_get_int16(buf);
+       if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
+               vstr->str = buf->p;
+               buf->p += vstr->len;
+       } else {
+               vstr->len = 0;
+               vstr->str = NULL;
        }
-
-       return ret;
 }
 
-static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf,
-                                 int datalen)
+static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
 {
-       char *ret = NULL;
-       int n = 0;
-
-       if (buf_check_size(dbuf, datalen)) {
-               n = buf_get_data(buf, dbuf->p, datalen);
-               if (n > 0) {
-                       ret = dbuf->p;
-                       dbuf->p += n;
-               }
-       }
-
-       return ret;
+       qid->type = buf_get_int8(bufp);
+       qid->version = buf_get_int32(bufp);
+       qid->path = buf_get_int64(bufp);
 }
 
 /**
- * v9fs_size_stat - calculate the size of a variable length stat struct
- * @v9ses: session information
+ * v9fs_size_wstat - calculate the size of a variable length stat struct
  * @stat: metadata (stat) structure
+ * @extended: non-zero if 9P2000.u
  *
  */
 
-static int v9fs_size_stat(struct v9fs_session_info *v9ses,
-                         struct v9fs_stat *stat)
+static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
 {
        int size = 0;
 
-       if (stat == NULL) {
+       if (wstat == NULL) {
                eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
                return 0;
        }
@@ -279,82 +225,38 @@ static int v9fs_size_stat(struct v9fs_session_info *v9ses,
            8 +                 /* length[8] */
            8;                  /* minimum sum of string lengths */
 
-       if (stat->name)
-               size += strlen(stat->name);
-       if (stat->uid)
-               size += strlen(stat->uid);
-       if (stat->gid)
-               size += strlen(stat->gid);
-       if (stat->muid)
-               size += strlen(stat->muid);
+       if (wstat->name)
+               size += strlen(wstat->name);
+       if (wstat->uid)
+               size += strlen(wstat->uid);
+       if (wstat->gid)
+               size += strlen(wstat->gid);
+       if (wstat->muid)
+               size += strlen(wstat->muid);
 
-       if (v9ses->extended) {
+       if (extended) {
                size += 4 +     /* n_uid[4] */
                    4 +         /* n_gid[4] */
                    4 +         /* n_muid[4] */
                    2;          /* string length of extension[4] */
-               if (stat->extension)
-                       size += strlen(stat->extension);
+               if (wstat->extension)
+                       size += strlen(wstat->extension);
        }
 
        return size;
 }
 
 /**
- * serialize_stat - safely format a stat structure for transmission
- * @v9ses: session info
- * @stat: metadata (stat) structure
- * @bufp: buffer to serialize structure into
- *
- */
-
-static int
-serialize_stat(struct v9fs_session_info *v9ses, struct v9fs_stat *stat,
-              struct cbuf *bufp)
-{
-       buf_put_int16(bufp, stat->size);
-       buf_put_int16(bufp, stat->type);
-       buf_put_int32(bufp, stat->dev);
-       buf_put_int8(bufp, stat->qid.type);
-       buf_put_int32(bufp, stat->qid.version);
-       buf_put_int64(bufp, stat->qid.path);
-       buf_put_int32(bufp, stat->mode);
-       buf_put_int32(bufp, stat->atime);
-       buf_put_int32(bufp, stat->mtime);
-       buf_put_int64(bufp, stat->length);
-
-       buf_put_string(bufp, stat->name);
-       buf_put_string(bufp, stat->uid);
-       buf_put_string(bufp, stat->gid);
-       buf_put_string(bufp, stat->muid);
-
-       if (v9ses->extended) {
-               buf_put_string(bufp, stat->extension);
-               buf_put_int32(bufp, stat->n_uid);
-               buf_put_int32(bufp, stat->n_gid);
-               buf_put_int32(bufp, stat->n_muid);
-       }
-
-       if (buf_check_overflow(bufp))
-               return 0;
-
-       return stat->size;
-}
-
-/**
- * deserialize_stat - safely decode a recieved metadata (stat) structure
- * @v9ses: session info
+ * buf_get_stat - safely decode a recieved metadata (stat) structure
  * @bufp: buffer to deserialize
  * @stat: metadata (stat) structure
- * @dbufp: buffer to deserialize variable strings into
+ * @extended: non-zero if 9P2000.u
  *
  */
 
-static inline int
-deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp,
-                struct v9fs_stat *stat, struct cbuf *dbufp)
+static inline void
+buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
 {
-
        stat->size = buf_get_int16(bufp);
        stat->type = buf_get_int16(bufp);
        stat->dev = buf_get_int32(bufp);
@@ -365,282 +267,82 @@ deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp,
        stat->atime = buf_get_int32(bufp);
        stat->mtime = buf_get_int32(bufp);
        stat->length = buf_get_int64(bufp);
-       stat->name = buf_get_stringb(bufp, dbufp);
-       stat->uid = buf_get_stringb(bufp, dbufp);
-       stat->gid = buf_get_stringb(bufp, dbufp);
-       stat->muid = buf_get_stringb(bufp, dbufp);
+       buf_get_str(bufp, &stat->name);
+       buf_get_str(bufp, &stat->uid);
+       buf_get_str(bufp, &stat->gid);
+       buf_get_str(bufp, &stat->muid);
 
-       if (v9ses->extended) {
-               stat->extension = buf_get_stringb(bufp, dbufp);
+       if (extended) {
+               buf_get_str(bufp, &stat->extension);
                stat->n_uid = buf_get_int32(bufp);
                stat->n_gid = buf_get_int32(bufp);
                stat->n_muid = buf_get_int32(bufp);
        }
-
-       if (buf_check_overflow(bufp) || buf_check_overflow(dbufp))
-               return 0;
-
-       return stat->size + 2;
-}
-
-/**
- * deserialize_statb - wrapper for decoding a received metadata structure
- * @v9ses: session info
- * @bufp: buffer to deserialize
- * @dbufp: buffer to deserialize variable strings into
- *
- */
-
-static inline struct v9fs_stat *deserialize_statb(struct v9fs_session_info
-                                                 *v9ses, struct cbuf *bufp,
-                                                 struct cbuf *dbufp)
-{
-       struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat));
-
-       if (ret) {
-               int n = deserialize_stat(v9ses, bufp, ret, dbufp);
-               if (n <= 0)
-                       return NULL;
-       }
-
-       return ret;
 }
 
 /**
  * v9fs_deserialize_stat - decode a received metadata structure
- * @v9ses: session info
  * @buf: buffer to deserialize
  * @buflen: length of received buffer
  * @stat: metadata structure to decode into
- * @statlen: length of destination metadata structure
+ * @extended: non-zero if 9P2000.u
  *
+ * Note: stat will point to the buf region.
  */
 
 int
-v9fs_deserialize_stat(struct v9fs_session_info *v9ses, void *buf,
-                     u32 buflen, struct v9fs_stat *stat, u32 statlen)
+v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
+               int extended)
 {
        struct cbuf buffer;
        struct cbuf *bufp = &buffer;
-       struct cbuf dbuffer;
-       struct cbuf *dbufp = &dbuffer;
+       unsigned char *p;
 
        buf_init(bufp, buf, buflen);
-       buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat),
-                statlen - sizeof(struct v9fs_stat));
-
-       return deserialize_stat(v9ses, bufp, stat, dbufp);
-}
-
-static inline int
-v9fs_size_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall)
-{
-       int size = 4 + 1 + 2;   /* size[4] msg[1] tag[2] */
-       int i = 0;
-
-       switch (fcall->id) {
-       default:
-               eprintk(KERN_ERR, "bad msg type %d\n", fcall->id);
-               return 0;
-       case TVERSION:          /* msize[4] version[s] */
-               size += 4 + 2 + strlen(fcall->params.tversion.version);
-               break;
-       case TAUTH:             /* afid[4] uname[s] aname[s] */
-               size += 4 + 2 + strlen(fcall->params.tauth.uname) +
-                   2 + strlen(fcall->params.tauth.aname);
-               break;
-       case TFLUSH:            /* oldtag[2] */
-               size += 2;
-               break;
-       case TATTACH:           /* fid[4] afid[4] uname[s] aname[s] */
-               size += 4 + 4 + 2 + strlen(fcall->params.tattach.uname) +
-                   2 + strlen(fcall->params.tattach.aname);
-               break;
-       case TWALK:             /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
-               size += 4 + 4 + 2;
-               /* now compute total for the array of names */
-               for (i = 0; i < fcall->params.twalk.nwname; i++)
-                       size += 2 + strlen(fcall->params.twalk.wnames[i]);
-               break;
-       case TOPEN:             /* fid[4] mode[1] */
-               size += 4 + 1;
-               break;
-       case TCREATE:           /* fid[4] name[s] perm[4] mode[1] */
-               size += 4 + 2 + strlen(fcall->params.tcreate.name) + 4 + 1;
-               break;
-       case TREAD:             /* fid[4] offset[8] count[4] */
-               size += 4 + 8 + 4;
-               break;
-       case TWRITE:            /* fid[4] offset[8] count[4] data[count] */
-               size += 4 + 8 + 4 + fcall->params.twrite.count;
-               break;
-       case TCLUNK:            /* fid[4] */
-               size += 4;
-               break;
-       case TREMOVE:           /* fid[4] */
-               size += 4;
-               break;
-       case TSTAT:             /* fid[4] */
-               size += 4;
-               break;
-       case TWSTAT:            /* fid[4] stat[n] */
-               fcall->params.twstat.stat->size =
-                   v9fs_size_stat(v9ses, fcall->params.twstat.stat);
-               size += 4 + 2 + 2 + fcall->params.twstat.stat->size;
-       }
-       return size;
-}
-
-/*
- * v9fs_serialize_fcall - marshall fcall struct into a packet
- * @v9ses: session information
- * @fcall: structure to convert
- * @data: buffer to serialize fcall into
- * @datalen: length of buffer to serialize fcall into
- *
- */
-
-int
-v9fs_serialize_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall,
-                    void *data, u32 datalen)
-{
-       int i = 0;
-       struct v9fs_stat *stat = NULL;
-       struct cbuf buffer;
-       struct cbuf *bufp = &buffer;
-
-       buf_init(bufp, data, datalen);
-
-       if (!fcall) {
-               eprintk(KERN_ERR, "no fcall\n");
-               return -EINVAL;
-       }
-
-       fcall->size = v9fs_size_fcall(v9ses, fcall);
-
-       buf_put_int32(bufp, fcall->size);
-       buf_put_int8(bufp, fcall->id);
-       buf_put_int16(bufp, fcall->tag);
-
-       dprintk(DEBUG_CONV, "size %d id %d tag %d\n", fcall->size, fcall->id,
-               fcall->tag);
-
-       /* now encode it */
-       switch (fcall->id) {
-       default:
-               eprintk(KERN_ERR, "bad msg type: %d\n", fcall->id);
-               return -EPROTO;
-       case TVERSION:
-               buf_put_int32(bufp, fcall->params.tversion.msize);
-               buf_put_string(bufp, fcall->params.tversion.version);
-               break;
-       case TAUTH:
-               buf_put_int32(bufp, fcall->params.tauth.afid);
-               buf_put_string(bufp, fcall->params.tauth.uname);
-               buf_put_string(bufp, fcall->params.tauth.aname);
-               break;
-       case TFLUSH:
-               buf_put_int16(bufp, fcall->params.tflush.oldtag);
-               break;
-       case TATTACH:
-               buf_put_int32(bufp, fcall->params.tattach.fid);
-               buf_put_int32(bufp, fcall->params.tattach.afid);
-               buf_put_string(bufp, fcall->params.tattach.uname);
-               buf_put_string(bufp, fcall->params.tattach.aname);
-               break;
-       case TWALK:
-               buf_put_int32(bufp, fcall->params.twalk.fid);
-               buf_put_int32(bufp, fcall->params.twalk.newfid);
-               buf_put_int16(bufp, fcall->params.twalk.nwname);
-               for (i = 0; i < fcall->params.twalk.nwname; i++)
-                       buf_put_string(bufp, fcall->params.twalk.wnames[i]);
-               break;
-       case TOPEN:
-               buf_put_int32(bufp, fcall->params.topen.fid);
-               buf_put_int8(bufp, fcall->params.topen.mode);
-               break;
-       case TCREATE:
-               buf_put_int32(bufp, fcall->params.tcreate.fid);
-               buf_put_string(bufp, fcall->params.tcreate.name);
-               buf_put_int32(bufp, fcall->params.tcreate.perm);
-               buf_put_int8(bufp, fcall->params.tcreate.mode);
-               break;
-       case TREAD:
-               buf_put_int32(bufp, fcall->params.tread.fid);
-               buf_put_int64(bufp, fcall->params.tread.offset);
-               buf_put_int32(bufp, fcall->params.tread.count);
-               break;
-       case TWRITE:
-               buf_put_int32(bufp, fcall->params.twrite.fid);
-               buf_put_int64(bufp, fcall->params.twrite.offset);
-               buf_put_int32(bufp, fcall->params.twrite.count);
-               buf_put_data(bufp, fcall->params.twrite.data,
-                            fcall->params.twrite.count);
-               break;
-       case TCLUNK:
-               buf_put_int32(bufp, fcall->params.tclunk.fid);
-               break;
-       case TREMOVE:
-               buf_put_int32(bufp, fcall->params.tremove.fid);
-               break;
-       case TSTAT:
-               buf_put_int32(bufp, fcall->params.tstat.fid);
-               break;
-       case TWSTAT:
-               buf_put_int32(bufp, fcall->params.twstat.fid);
-               stat = fcall->params.twstat.stat;
-
-               buf_put_int16(bufp, stat->size + 2);
-               serialize_stat(v9ses, stat, bufp);
-               break;
-       }
+       p = bufp->p;
+       buf_get_stat(bufp, stat, extended);
 
        if (buf_check_overflow(bufp))
-               return -EIO;
-
-       return fcall->size;
+               return 0;
+       else
+               return bufp->p - p;
 }
 
 /**
  * deserialize_fcall - unmarshal a response
- * @v9ses: session information
- * @msgsize: size of rcall message
  * @buf: recieved buffer
  * @buflen: length of received buffer
  * @rcall: fcall structure to populate
  * @rcalllen: length of fcall structure to populate
+ * @extended: non-zero if 9P2000.u
  *
  */
 
 int
-v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize,
-                      void *buf, u32 buflen, struct v9fs_fcall *rcall,
-                      int rcalllen)
+v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
+                      int extended)
 {
 
        struct cbuf buffer;
        struct cbuf *bufp = &buffer;
-       struct cbuf dbuffer;
-       struct cbuf *dbufp = &dbuffer;
        int i = 0;
 
        buf_init(bufp, buf, buflen);
-       buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall),
-                rcalllen - sizeof(struct v9fs_fcall));
 
-       rcall->size = msgsize;
+       rcall->size = buf_get_int32(bufp);
        rcall->id = buf_get_int8(bufp);
        rcall->tag = buf_get_int16(bufp);
 
        dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
                rcall->tag);
+
        switch (rcall->id) {
        default:
                eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
                return -EPROTO;
        case RVERSION:
                rcall->params.rversion.msize = buf_get_int32(bufp);
-               rcall->params.rversion.version = buf_get_stringb(bufp, dbufp);
+               buf_get_str(bufp, &rcall->params.rversion.version);
                break;
        case RFLUSH:
                break;
@@ -651,34 +353,27 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize,
                break;
        case RWALK:
                rcall->params.rwalk.nwqid = buf_get_int16(bufp);
-               rcall->params.rwalk.wqids = buf_alloc(dbufp,
-                     rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid));
-               if (rcall->params.rwalk.wqids)
-                       for (i = 0; i < rcall->params.rwalk.nwqid; i++) {
-                               rcall->params.rwalk.wqids[i].type =
-                                   buf_get_int8(bufp);
-                               rcall->params.rwalk.wqids[i].version =
-                                   buf_get_int16(bufp);
-                               rcall->params.rwalk.wqids[i].path =
-                                   buf_get_int64(bufp);
-                       }
+               if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
+                       eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
+                               V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
+                       return -EPROTO;
+               }
+
+               for (i = 0; i < rcall->params.rwalk.nwqid; i++)
+                       buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
                break;
        case ROPEN:
-               rcall->params.ropen.qid.type = buf_get_int8(bufp);
-               rcall->params.ropen.qid.version = buf_get_int32(bufp);
-               rcall->params.ropen.qid.path = buf_get_int64(bufp);
+               buf_get_qid(bufp, &rcall->params.ropen.qid);
                rcall->params.ropen.iounit = buf_get_int32(bufp);
                break;
        case RCREATE:
-               rcall->params.rcreate.qid.type = buf_get_int8(bufp);
-               rcall->params.rcreate.qid.version = buf_get_int32(bufp);
-               rcall->params.rcreate.qid.path = buf_get_int64(bufp);
+               buf_get_qid(bufp, &rcall->params.rcreate.qid);
                rcall->params.rcreate.iounit = buf_get_int32(bufp);
                break;
        case RREAD:
                rcall->params.rread.count = buf_get_int32(bufp);
-               rcall->params.rread.data = buf_get_datab(bufp, dbufp,
-                       rcall->params.rread.count);
+               rcall->params.rread.data = bufp->p;
+               buf_check_size(bufp, rcall->params.rread.count);
                break;
        case RWRITE:
                rcall->params.rwrite.count = buf_get_int32(bufp);
@@ -689,20 +384,443 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize,
                break;
        case RSTAT:
                buf_get_int16(bufp);
-               rcall->params.rstat.stat =
-                   deserialize_statb(v9ses, bufp, dbufp);
+               buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
                break;
        case RWSTAT:
                break;
        case RERROR:
-               rcall->params.rerror.error = buf_get_stringb(bufp, dbufp);
-               if (v9ses->extended)
+               buf_get_str(bufp, &rcall->params.rerror.error);
+               if (extended)
                        rcall->params.rerror.errno = buf_get_int16(bufp);
                break;
        }
 
-       if (buf_check_overflow(bufp) || buf_check_overflow(dbufp))
+       if (buf_check_overflow(bufp)) {
+               dprintk(DEBUG_ERROR, "buffer overflow\n");
                return -EIO;
+       }
+
+       return bufp->p - bufp->sp;
+}
+
+static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
+{
+       *p = val;
+       buf_put_int8(bufp, val);
+}
+
+static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
+{
+       *p = val;
+       buf_put_int16(bufp, val);
+}
+
+static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
+{
+       *p = val;
+       buf_put_int32(bufp, val);
+}
+
+static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
+{
+       *p = val;
+       buf_put_int64(bufp, val);
+}
 
-       return rcall->size;
+static inline void
+v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
+{
+       if (data) {
+               str->len = strlen(data);
+               str->str = bufp->p;
+       } else {
+               str->len = 0;
+               str->str = NULL;
+       }
+
+       buf_put_stringn(bufp, data, str->len);
+}
+
+static inline int
+v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
+                  unsigned char **pdata)
+{
+       *pdata = buf_alloc(bufp, count);
+       return copy_from_user(*pdata, data, count);
+}
+
+static void
+v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
+              struct v9fs_stat *stat, int statsz, int extended)
+{
+       v9fs_put_int16(bufp, statsz, &stat->size);
+       v9fs_put_int16(bufp, wstat->type, &stat->type);
+       v9fs_put_int32(bufp, wstat->dev, &stat->dev);
+       v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
+       v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
+       v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
+       v9fs_put_int32(bufp, wstat->mode, &stat->mode);
+       v9fs_put_int32(bufp, wstat->atime, &stat->atime);
+       v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
+       v9fs_put_int64(bufp, wstat->length, &stat->length);
+
+       v9fs_put_str(bufp, wstat->name, &stat->name);
+       v9fs_put_str(bufp, wstat->uid, &stat->uid);
+       v9fs_put_str(bufp, wstat->gid, &stat->gid);
+       v9fs_put_str(bufp, wstat->muid, &stat->muid);
+
+       if (extended) {
+               v9fs_put_str(bufp, wstat->extension, &stat->extension);
+               v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
+               v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
+               v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
+       }
+}
+
+static struct v9fs_fcall *
+v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
+{
+       struct v9fs_fcall *fc;
+
+       size += 4 + 1 + 2;      /* size[4] id[1] tag[2] */
+       fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
+       if (!fc)
+               return ERR_PTR(-ENOMEM);
+
+       fc->sdata = (char *)fc + sizeof(*fc);
+
+       buf_init(bufp, (char *)fc->sdata, size);
+       v9fs_put_int32(bufp, size, &fc->size);
+       v9fs_put_int8(bufp, id, &fc->id);
+       v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
+
+       return fc;
+}
+
+void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
+{
+       fc->tag = tag;
+       *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
+}
+
+struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4 + 2 + strlen(version); /* msize[4] version[s] */
+       fc = v9fs_create_common(bufp, size, TVERSION);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
+       v9fs_put_str(bufp, version, &fc->params.tversion.version);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4 + 2 + strlen(uname) + 2 + strlen(aname);       /* afid[4] uname[s] aname[s] */
+       fc = v9fs_create_common(bufp, size, TAUTH);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
+       v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
+       v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *
+v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname);   /* fid[4] afid[4] uname[s] aname[s] */
+       fc = v9fs_create_common(bufp, size, TATTACH);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
+       v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
+       v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
+       v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
+
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 2;               /* oldtag[2] */
+       fc = v9fs_create_common(bufp, size, TFLUSH);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
+                                    char **wnames)
+{
+       int i, size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       if (nwname > V9FS_MAXWELEM) {
+               dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
+               return NULL;
+       }
+
+       size = 4 + 4 + 2;       /* fid[4] newfid[4] nwname[2] ... */
+       for (i = 0; i < nwname; i++) {
+               size += 2 + strlen(wnames[i]);  /* wname[s] */
+       }
+
+       fc = v9fs_create_common(bufp, size, TWALK);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
+       v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
+       v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
+       for (i = 0; i < nwname; i++) {
+               v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
+       }
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4 + 1;           /* fid[4] mode[1] */
+       fc = v9fs_create_common(bufp, size, TOPEN);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
+       v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4 + 2 + strlen(name) + 4 + 1;    /* fid[4] name[s] perm[4] mode[1] */
+       fc = v9fs_create_common(bufp, size, TCREATE);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
+       v9fs_put_str(bufp, name, &fc->params.tcreate.name);
+       v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
+       v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4 + 8 + 4;       /* fid[4] offset[8] count[4] */
+       fc = v9fs_create_common(bufp, size, TREAD);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
+       v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
+       v9fs_put_int32(bufp, count, &fc->params.tread.count);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
+                                     const char __user * data)
+{
+       int size, err;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4 + 8 + 4 + count;       /* fid[4] offset[8] count[4] data[count] */
+       fc = v9fs_create_common(bufp, size, TWRITE);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
+       v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
+       v9fs_put_int32(bufp, count, &fc->params.twrite.count);
+       err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
+       if (err) {
+               kfree(fc);
+               fc = ERR_PTR(err);
+       }
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4;               /* fid[4] */
+       fc = v9fs_create_common(bufp, size, TCLUNK);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tremove(u32 fid)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4;               /* fid[4] */
+       fc = v9fs_create_common(bufp, size, TREMOVE);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tstat(u32 fid)
+{
+       int size;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       size = 4;               /* fid[4] */
+       fc = v9fs_create_common(bufp, size, TSTAT);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
+}
+
+struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
+                                     int extended)
+{
+       int size, statsz;
+       struct v9fs_fcall *fc;
+       struct cbuf buffer;
+       struct cbuf *bufp = &buffer;
+
+       statsz = v9fs_size_wstat(wstat, extended);
+       size = 4 + 2 + 2 + statsz;      /* fid[4] stat[n] */
+       fc = v9fs_create_common(bufp, size, TWSTAT);
+       if (IS_ERR(fc))
+               goto error;
+
+       v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
+       buf_put_int16(bufp, statsz + 2);
+       v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
+
+       if (buf_check_overflow(bufp)) {
+               kfree(fc);
+               fc = ERR_PTR(-ENOMEM);
+       }
+      error:
+       return fc;
 }
index ee849613c61a52b1ff0ddbe19dd641fc591b13ae..26a736e4a2e7466e10ca57c5dc2de823fb597415 100644 (file)
@@ -1,8 +1,9 @@
 /*
  * linux/fs/9p/conv.h
  *
- * 9P protocol conversion definitions
+ * 9P protocol conversion definitions.
  *
+ *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *
  */
 
-int v9fs_deserialize_stat(struct v9fs_session_info *, void *buf,
-                         u32 buflen, struct v9fs_stat *stat, u32 statlen);
-int v9fs_serialize_fcall(struct v9fs_session_info *, struct v9fs_fcall *tcall,
-                        void *buf, u32 buflen);
-int v9fs_deserialize_fcall(struct v9fs_session_info *, u32 msglen,
-                          void *buf, u32 buflen, struct v9fs_fcall *rcall,
-                          int rcalllen);
+int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
+       int extended);
+int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
+       int extended);
 
-/* this one is actually in error.c right now */
-int v9fs_errstr2errno(char *errstr);
+void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag);
+
+struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version);
+struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname);
+struct v9fs_fcall *v9fs_create_tattach(u32 fid, u32 afid, char *uname,
+       char *aname);
+struct v9fs_fcall *v9fs_create_tflush(u16 oldtag);
+struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
+       char **wnames);
+struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode);
+struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode);
+struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count);
+struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
+       const char __user *data);
+struct v9fs_fcall *v9fs_create_tclunk(u32 fid);
+struct v9fs_fcall *v9fs_create_tremove(u32 fid);
+struct v9fs_fcall *v9fs_create_tstat(u32 fid);
+struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
+       int extended);
index 4445f06919d9bdf47040802abd2c825ffb0499c7..fe551032788b68b17f146174d36c6479733a0836 100644 (file)
@@ -51,16 +51,23 @@ do { \
 #if DEBUG_DUMP_PKT
 static inline void dump_data(const unsigned char *data, unsigned int datalen)
 {
-       int i, j;
-       int len = datalen;
+       int i, n;
+       char buf[5*8];
 
-       printk(KERN_DEBUG "data ");
-       for (i = 0; i < len; i += 4) {
-               for (j = 0; (j < 4) && (i + j < len); j++)
-                       printk(KERN_DEBUG "%02x", data[i + j]);
-               printk(KERN_DEBUG " ");
+       n = 0;
+       i = 0;
+       while (i < datalen) {
+               n += snprintf(buf+n, sizeof(buf)-n, "%02x", data[i++]);
+               if (i%4 == 0)
+                       n += snprintf(buf+n, sizeof(buf)-n, " ");
+
+               if (i%16 == 0) {
+                       dprintk(DEBUG_ERROR, "%s\n", buf);
+                       n = 0;
+               }
        }
-       printk(KERN_DEBUG "\n");
+
+       dprintk(DEBUG_ERROR, "%s\n", buf);
 }
 #else                          /* DEBUG_DUMP_PKT */
 static inline void dump_data(const unsigned char *data, unsigned int datalen)
index 834cb179e3888c963ae651fc34a5bf26f915b41b..e4b6f8f38b6fbcbe3fd59fcdce526d1e5a8eeabe 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <linux/list.h>
 #include <linux/jhash.h>
-#include <linux/string.h>
 
 #include "debug.h"
 #include "error.h"
@@ -55,7 +54,8 @@ int v9fs_error_init(void)
 
        /* load initial error map into hash table */
        for (c = errmap; c->name != NULL; c++) {
-               bucket = jhash(c->name, strlen(c->name), 0) % ERRHASHSZ;
+               c->namelen = strlen(c->name);
+               bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ;
                INIT_HLIST_NODE(&c->list);
                hlist_add_head(&c->list, &hash_errmap[bucket]);
        }
@@ -69,15 +69,15 @@ int v9fs_error_init(void)
  *
  */
 
-int v9fs_errstr2errno(char *errstr)
+int v9fs_errstr2errno(char *errstr, int len)
 {
        int errno = 0;
        struct hlist_node *p = NULL;
        struct errormap *c = NULL;
-       int bucket = jhash(errstr, strlen(errstr), 0) % ERRHASHSZ;
+       int bucket = jhash(errstr, len, 0) % ERRHASHSZ;
 
        hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
-               if (!strcmp(c->name, errstr)) {
+               if (c->namelen==len && !memcmp(c->name, errstr, len)) {
                        errno = c->val;
                        break;
                }
index 78f89acf7c9affa0552ea442b75e8be06787bfc3..a9794e85fe51015383736e290ad4b57e44658c89 100644 (file)
@@ -36,6 +36,7 @@ struct errormap {
        char *name;
        int val;
 
+       int namelen;
        struct hlist_node list;
 };
 
@@ -175,4 +176,3 @@ static struct errormap errmap[] = {
 };
 
 extern int v9fs_error_init(void);
-extern int v9fs_errstr2errno(char *errstr);
index d95f8626d1702e918e4d8b415e0de3afbed6afb9..eda449778fa55d5e96e7342acdc6920f73d4c3f3 100644 (file)
@@ -31,9 +31,6 @@
 #include "v9fs.h"
 #include "9p.h"
 #include "v9fs_vfs.h"
-#include "transport.h"
-#include "mux.h"
-#include "conv.h"
 #include "fid.h"
 
 /**
@@ -164,7 +161,7 @@ static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry)
        return v9fs_fid_create(dentry, v9ses, fidnum, 0);
 
 clunk_fid:
-       v9fs_t_clunk(v9ses, fidnum, NULL);
+       v9fs_t_clunk(v9ses, fidnum);
        return ERR_PTR(err);
 }
 
index 8835b576f7445c98eae41c69c9afde4f21d91b3a..945cb368d451948156bf518ee7e40616ac09e675 100644 (file)
@@ -4,7 +4,7 @@
  * Protocol Multiplexer
  *
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- *  Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
+ *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
  *
  *  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
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/poll.h>
 #include <linux/kthread.h>
 #include <linux/idr.h>
 
 #include "debug.h"
 #include "v9fs.h"
 #include "9p.h"
-#include "transport.h"
 #include "conv.h"
+#include "transport.h"
 #include "mux.h"
 
+#define ERREQFLUSH     1
+#define SCHED_TIMEOUT  10
+#define MAXPOLLWADDR   2
+
+enum {
+       Rworksched = 1,         /* read work scheduled or running */
+       Rpending = 2,           /* can read */
+       Wworksched = 4,         /* write work scheduled or running */
+       Wpending = 8,           /* can write */
+};
+
+struct v9fs_mux_poll_task;
+
+struct v9fs_req {
+       int tag;
+       struct v9fs_fcall *tcall;
+       struct v9fs_fcall *rcall;
+       int err;
+       v9fs_mux_req_callback cb;
+       void *cba;
+       struct list_head req_list;
+};
+
+struct v9fs_mux_data {
+       spinlock_t lock;
+       struct list_head mux_list;
+       struct v9fs_mux_poll_task *poll_task;
+       int msize;
+       unsigned char *extended;
+       struct v9fs_transport *trans;
+       struct v9fs_idpool tidpool;
+       int err;
+       wait_queue_head_t equeue;
+       struct list_head req_list;
+       struct list_head unsent_req_list;
+       struct v9fs_fcall *rcall;
+       int rpos;
+       char *rbuf;
+       int wpos;
+       int wsize;
+       char *wbuf;
+       wait_queue_t poll_wait[MAXPOLLWADDR];
+       wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
+       poll_table pt;
+       struct work_struct rq;
+       struct work_struct wq;
+       unsigned long wsched;
+};
+
+struct v9fs_mux_poll_task {
+       struct task_struct *task;
+       struct list_head mux_list;
+       int muxnum;
+};
+
+struct v9fs_mux_rpc {
+       struct v9fs_mux_data *m;
+       struct v9fs_req *req;
+       int err;
+       struct v9fs_fcall *rcall;
+       wait_queue_head_t wqueue;
+};
+
+static int v9fs_poll_proc(void *);
+static void v9fs_read_work(void *);
+static void v9fs_write_work(void *);
+static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
+                         poll_table * p);
+static u16 v9fs_mux_get_tag(struct v9fs_mux_data *);
+static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16);
+
+static DECLARE_MUTEX(v9fs_mux_task_lock);
+static struct workqueue_struct *v9fs_mux_wq;
+
+static int v9fs_mux_num;
+static int v9fs_mux_poll_task_num;
+static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100];
+
+int v9fs_mux_global_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++)
+               v9fs_mux_poll_tasks[i].task = NULL;
+
+       v9fs_mux_wq = create_workqueue("v9fs");
+       if (!v9fs_mux_wq)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void v9fs_mux_global_exit(void)
+{
+       destroy_workqueue(v9fs_mux_wq);
+}
+
 /**
- * dprintcond - print condition of session info
- * @v9ses: session info structure
- * @req: RPC request structure
+ * v9fs_mux_calc_poll_procs - calculates the number of polling procs
+ * based on the number of mounted v9fs filesystems.
  *
+ * The current implementation returns sqrt of the number of mounts.
  */
+inline int v9fs_mux_calc_poll_procs(int muxnum)
+{
+       int n;
+
+       if (v9fs_mux_poll_task_num)
+               n = muxnum / v9fs_mux_poll_task_num +
+                   (muxnum % v9fs_mux_poll_task_num ? 1 : 0);
+       else
+               n = 1;
+
+       if (n > ARRAY_SIZE(v9fs_mux_poll_tasks))
+               n = ARRAY_SIZE(v9fs_mux_poll_tasks);
+
+       return n;
+}
 
-static inline int
-dprintcond(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
+static int v9fs_mux_poll_start(struct v9fs_mux_data *m)
 {
-       dprintk(DEBUG_MUX, "condition: %d, %p\n", v9ses->transport->status,
-               req->rcall);
+       int i, n;
+       struct v9fs_mux_poll_task *vpt, *vptlast;
+       struct task_struct *pproc;
+
+       dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num,
+               v9fs_mux_poll_task_num);
+       up(&v9fs_mux_task_lock);
+
+       n = v9fs_mux_calc_poll_procs(v9fs_mux_num + 1);
+       if (n > v9fs_mux_poll_task_num) {
+               for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) {
+                       if (v9fs_mux_poll_tasks[i].task == NULL) {
+                               vpt = &v9fs_mux_poll_tasks[i];
+                               dprintk(DEBUG_MUX, "create proc %p\n", vpt);
+                               pproc = kthread_create(v9fs_poll_proc, vpt,
+                                                  "v9fs-poll");
+
+                               if (!IS_ERR(pproc)) {
+                                       vpt->task = pproc;
+                                       INIT_LIST_HEAD(&vpt->mux_list);
+                                       vpt->muxnum = 0;
+                                       v9fs_mux_poll_task_num++;
+                                       wake_up_process(vpt->task);
+                               }
+                               break;
+                       }
+               }
+
+               if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks))
+                       dprintk(DEBUG_ERROR, "warning: no free poll slots\n");
+       }
+
+       n = (v9fs_mux_num + 1) / v9fs_mux_poll_task_num +
+           ((v9fs_mux_num + 1) % v9fs_mux_poll_task_num ? 1 : 0);
+
+       vptlast = NULL;
+       for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) {
+               vpt = &v9fs_mux_poll_tasks[i];
+               if (vpt->task != NULL) {
+                       vptlast = vpt;
+                       if (vpt->muxnum < n) {
+                               dprintk(DEBUG_MUX, "put in proc %d\n", i);
+                               list_add(&m->mux_list, &vpt->mux_list);
+                               vpt->muxnum++;
+                               m->poll_task = vpt;
+                               memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+                               init_poll_funcptr(&m->pt, v9fs_pollwait);
+                               break;
+                       }
+               }
+       }
+
+       if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) {
+               if (vptlast == NULL)
+                       return -ENOMEM;
+
+               dprintk(DEBUG_MUX, "put in proc %d\n", i);
+               list_add(&m->mux_list, &vptlast->mux_list);
+               vptlast->muxnum++;
+               m->poll_task = vptlast;
+               memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+               init_poll_funcptr(&m->pt, v9fs_pollwait);
+       }
+
+       v9fs_mux_num++;
+       down(&v9fs_mux_task_lock);
+
        return 0;
 }
 
+static void v9fs_mux_poll_stop(struct v9fs_mux_data *m)
+{
+       int i;
+       struct v9fs_mux_poll_task *vpt;
+
+       up(&v9fs_mux_task_lock);
+       vpt = m->poll_task;
+       list_del(&m->mux_list);
+       for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+               if (m->poll_waddr[i] != NULL) {
+                       remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
+                       m->poll_waddr[i] = NULL;
+               }
+       }
+       vpt->muxnum--;
+       if (!vpt->muxnum) {
+               dprintk(DEBUG_MUX, "destroy proc %p\n", vpt);
+               send_sig(SIGKILL, vpt->task, 1);
+               vpt->task = NULL;
+               v9fs_mux_poll_task_num--;
+       }
+       v9fs_mux_num--;
+       down(&v9fs_mux_task_lock);
+}
+
 /**
- * xread - force read of a certain number of bytes
- * @v9ses: session info structure
- * @ptr: pointer to buffer
- * @sz: number of bytes to read
+ * v9fs_mux_init - allocate and initialize the per-session mux data
+ * Creates the polling task if this is the first session.
  *
- * Chuck Cranor CS-533 project1
+ * @trans - transport structure
+ * @msize - maximum message size
+ * @extended - pointer to the extended flag
  */
-
-static int xread(struct v9fs_session_info *v9ses, void *ptr, unsigned long sz)
+struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
+                                   unsigned char *extended)
 {
-       int rd = 0;
-       int ret = 0;
-       while (rd < sz) {
-               ret = v9ses->transport->read(v9ses->transport, ptr, sz - rd);
-               if (ret <= 0) {
-                       dprintk(DEBUG_ERROR, "xread errno %d\n", ret);
-                       return ret;
+       int i, n;
+       struct v9fs_mux_data *m, *mtmp;
+
+       dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize);
+       m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL);
+       if (!m)
+               return ERR_PTR(-ENOMEM);
+
+       spin_lock_init(&m->lock);
+       INIT_LIST_HEAD(&m->mux_list);
+       m->msize = msize;
+       m->extended = extended;
+       m->trans = trans;
+       idr_init(&m->tidpool.pool);
+       init_MUTEX(&m->tidpool.lock);
+       m->err = 0;
+       init_waitqueue_head(&m->equeue);
+       INIT_LIST_HEAD(&m->req_list);
+       INIT_LIST_HEAD(&m->unsent_req_list);
+       m->rcall = NULL;
+       m->rpos = 0;
+       m->rbuf = NULL;
+       m->wpos = m->wsize = 0;
+       m->wbuf = NULL;
+       INIT_WORK(&m->rq, v9fs_read_work, m);
+       INIT_WORK(&m->wq, v9fs_write_work, m);
+       m->wsched = 0;
+       memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+       m->poll_task = NULL;
+       n = v9fs_mux_poll_start(m);
+       if (n)
+               return ERR_PTR(n);
+
+       n = trans->poll(trans, &m->pt);
+       if (n & POLLIN) {
+               dprintk(DEBUG_MUX, "mux %p can read\n", m);
+               set_bit(Rpending, &m->wsched);
+       }
+
+       if (n & POLLOUT) {
+               dprintk(DEBUG_MUX, "mux %p can write\n", m);
+               set_bit(Wpending, &m->wsched);
+       }
+
+       for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+               if (IS_ERR(m->poll_waddr[i])) {
+                       v9fs_mux_poll_stop(m);
+                       mtmp = (void *)m->poll_waddr;   /* the error code */
+                       kfree(m);
+                       m = mtmp;
+                       break;
                }
-               rd += ret;
-               ptr += ret;
        }
-       return (rd);
+
+       return m;
 }
 
 /**
- * read_message - read a full 9P2000 fcall packet
- * @v9ses: session info structure
- * @rcall: fcall structure to read into
- * @rcalllen: size of fcall buffer
- *
+ * v9fs_mux_destroy - cancels all pending requests and frees mux resources
  */
+void v9fs_mux_destroy(struct v9fs_mux_data *m)
+{
+       dprintk(DEBUG_MUX, "mux %p prev %p next %p\n", m,
+               m->mux_list.prev, m->mux_list.next);
+       v9fs_mux_cancel(m, -ECONNRESET);
+
+       if (!list_empty(&m->req_list)) {
+               /* wait until all processes waiting on this session exit */
+               dprintk(DEBUG_MUX, "mux %p waiting for empty request queue\n",
+                       m);
+               wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
+               dprintk(DEBUG_MUX, "mux %p request queue empty: %d\n", m,
+                       list_empty(&m->req_list));
+       }
+
+       v9fs_mux_poll_stop(m);
+       m->trans = NULL;
+
+       kfree(m);
+}
 
-static int
-read_message(struct v9fs_session_info *v9ses,
-            struct v9fs_fcall *rcall, int rcalllen)
+/**
+ * v9fs_pollwait - called by files poll operation to add v9fs-poll task
+ *     to files wait queue
+ */
+static void
+v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
+             poll_table * p)
 {
-       unsigned char buf[4];
-       void *data;
-       int size = 0;
-       int res = 0;
-
-       res = xread(v9ses, buf, sizeof(buf));
-       if (res < 0) {
-               dprintk(DEBUG_ERROR,
-                       "Reading of count field failed returned: %d\n", res);
-               return res;
+       int i;
+       struct v9fs_mux_data *m;
+
+       m = container_of(p, struct v9fs_mux_data, pt);
+       for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
+               if (m->poll_waddr[i] == NULL)
+                       break;
+
+       if (i >= ARRAY_SIZE(m->poll_waddr)) {
+               dprintk(DEBUG_ERROR, "not enough wait_address slots\n");
+               return;
        }
 
-       if (res < 4) {
-               dprintk(DEBUG_ERROR,
-                       "Reading of count field failed returned: %d\n", res);
-               return -EIO;
+       m->poll_waddr[i] = wait_address;
+
+       if (!wait_address) {
+               dprintk(DEBUG_ERROR, "no wait_address\n");
+               m->poll_waddr[i] = ERR_PTR(-EIO);
+               return;
        }
 
-       size = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-       dprintk(DEBUG_MUX, "got a packet count: %d\n", size);
+       init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
+       add_wait_queue(wait_address, &m->poll_wait[i]);
+}
+
+/**
+ * v9fs_poll_mux - polls a mux and schedules read or write works if necessary
+ */
+static inline void v9fs_poll_mux(struct v9fs_mux_data *m)
+{
+       int n;
 
-       /* adjust for the four bytes of size */
-       size -= 4;
+       if (m->err < 0)
+               return;
 
-       if (size > v9ses->maxdata) {
-               dprintk(DEBUG_ERROR, "packet too big: %d\n", size);
-               return -E2BIG;
+       n = m->trans->poll(m->trans, NULL);
+       if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
+               dprintk(DEBUG_MUX, "error mux %p err %d\n", m, n);
+               if (n >= 0)
+                       n = -ECONNRESET;
+               v9fs_mux_cancel(m, n);
        }
 
-       data = kmalloc(size, GFP_KERNEL);
-       if (!data) {
-               eprintk(KERN_WARNING, "out of memory\n");
-               return -ENOMEM;
+       if (n & POLLIN) {
+               set_bit(Rpending, &m->wsched);
+               dprintk(DEBUG_MUX, "mux %p can read\n", m);
+               if (!test_and_set_bit(Rworksched, &m->wsched)) {
+                       dprintk(DEBUG_MUX, "schedule read work mux %p\n", m);
+                       queue_work(v9fs_mux_wq, &m->rq);
+               }
        }
 
-       res = xread(v9ses, data, size);
-       if (res < size) {
-               dprintk(DEBUG_ERROR, "Reading of fcall failed returned: %d\n",
-                       res);
-               kfree(data);
-               return res;
+       if (n & POLLOUT) {
+               set_bit(Wpending, &m->wsched);
+               dprintk(DEBUG_MUX, "mux %p can write\n", m);
+               if ((m->wsize || !list_empty(&m->unsent_req_list))
+                   && !test_and_set_bit(Wworksched, &m->wsched)) {
+                       dprintk(DEBUG_MUX, "schedule write work mux %p\n", m);
+                       queue_work(v9fs_mux_wq, &m->wq);
+               }
        }
+}
+
+/**
+ * v9fs_poll_proc - polls all v9fs transports for new events and queues
+ *     the appropriate work to the work queue
+ */
+static int v9fs_poll_proc(void *a)
+{
+       struct v9fs_mux_data *m, *mtmp;
+       struct v9fs_mux_poll_task *vpt;
 
-       /* we now have an in-memory string that is the reply.
-        * deserialize it. There is very little to go wrong at this point
-        * save for v9fs_alloc errors.
-        */
-       res = v9fs_deserialize_fcall(v9ses, size, data, v9ses->maxdata,
-                                    rcall, rcalllen);
+       vpt = a;
+       dprintk(DEBUG_MUX, "start %p %p\n", current, vpt);
+       allow_signal(SIGKILL);
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (signal_pending(current))
+                       break;
 
-       kfree(data);
+               list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
+                       v9fs_poll_mux(m);
+               }
 
-       if (res < 0)
-               return res;
+               dprintk(DEBUG_MUX, "sleeping...\n");
+               schedule_timeout(SCHED_TIMEOUT * HZ);
+       }
 
+       __set_current_state(TASK_RUNNING);
+       dprintk(DEBUG_MUX, "finish\n");
        return 0;
 }
 
 /**
- * v9fs_recv - receive an RPC response for a particular tag
- * @v9ses: session info structure
- * @req: RPC request structure
- *
+ * v9fs_write_work - called when a transport can send some data
  */
-
-static int v9fs_recv(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
+static void v9fs_write_work(void *a)
 {
-       int ret = 0;
+       int n, err;
+       struct v9fs_mux_data *m;
+       struct v9fs_req *req;
 
-       dprintk(DEBUG_MUX, "waiting for response: %d\n", req->tcall->tag);
-       ret = wait_event_interruptible(v9ses->read_wait,
-                      ((v9ses->transport->status != Connected) ||
-                       (req->rcall != 0) || (req->err < 0) ||
-                       dprintcond(v9ses, req)));
+       m = a;
 
-       dprintk(DEBUG_MUX, "got it: rcall %p\n", req->rcall);
+       if (m->err < 0) {
+               clear_bit(Wworksched, &m->wsched);
+               return;
+       }
 
-       spin_lock(&v9ses->muxlock);
-       list_del(&req->next);
-       spin_unlock(&v9ses->muxlock);
+       if (!m->wsize) {
+               if (list_empty(&m->unsent_req_list)) {
+                       clear_bit(Wworksched, &m->wsched);
+                       return;
+               }
 
-       if (req->err < 0)
-               return req->err;
+               spin_lock(&m->lock);
+               req =
+                   list_entry(m->unsent_req_list.next, struct v9fs_req,
+                              req_list);
+               list_move_tail(&req->req_list, &m->req_list);
+               m->wbuf = req->tcall->sdata;
+               m->wsize = req->tcall->size;
+               m->wpos = 0;
+               dump_data(m->wbuf, m->wsize);
+               spin_unlock(&m->lock);
+       }
 
-       if (v9ses->transport->status == Disconnected)
-               return -ECONNRESET;
+       dprintk(DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, m->wsize);
+       clear_bit(Wpending, &m->wsched);
+       err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
+       dprintk(DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
+       if (err == -EAGAIN) {
+               clear_bit(Wworksched, &m->wsched);
+               return;
+       }
 
-       return ret;
-}
+       if (err <= 0)
+               goto error;
 
-/**
- * v9fs_send - send a 9P request
- * @v9ses: session info structure
- * @req: RPC request to send
- *
- */
+       m->wpos += err;
+       if (m->wpos == m->wsize)
+               m->wpos = m->wsize = 0;
+
+       if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
+               if (test_and_clear_bit(Wpending, &m->wsched))
+                       n = POLLOUT;
+               else
+                       n = m->trans->poll(m->trans, NULL);
+
+               if (n & POLLOUT) {
+                       dprintk(DEBUG_MUX, "schedule write work mux %p\n", m);
+                       queue_work(v9fs_mux_wq, &m->wq);
+               } else
+                       clear_bit(Wworksched, &m->wsched);
+       } else
+               clear_bit(Wworksched, &m->wsched);
+
+       return;
 
-static int v9fs_send(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
+      error:
+       v9fs_mux_cancel(m, err);
+       clear_bit(Wworksched, &m->wsched);
+}
+
+static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
 {
-       int ret = -1;
-       void *data = NULL;
-       struct v9fs_fcall *tcall = req->tcall;
+       int ecode, tag;
+       struct v9fs_str *ename;
 
-       data = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
+       tag = req->tag;
+       if (req->rcall->id == RERROR && !req->err) {
+               ecode = req->rcall->params.rerror.errno;
+               ename = &req->rcall->params.rerror.error;
 
-       tcall->size = 0;        /* enforce size recalculation */
-       ret =
-           v9fs_serialize_fcall(v9ses, tcall, data,
-                                v9ses->maxdata + V9FS_IOHDRSZ);
-       if (ret < 0)
-               goto free_data;
+               dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str);
 
-       spin_lock(&v9ses->muxlock);
-       list_add(&req->next, &v9ses->mux_fcalls);
-       spin_unlock(&v9ses->muxlock);
+               if (*m->extended)
+                       req->err = -ecode;
 
-       dprintk(DEBUG_MUX, "sending message: tag %d size %d\n", tcall->tag,
-               tcall->size);
-       ret = v9ses->transport->write(v9ses->transport, data, tcall->size);
+               if (!req->err) {
+                       req->err = v9fs_errstr2errno(ename->str, ename->len);
 
-       if (ret != tcall->size) {
-               spin_lock(&v9ses->muxlock);
-               list_del(&req->next);
-               kfree(req->rcall);
+                       if (!req->err) {        /* string match failed */
+                               PRINT_FCALL_ERROR("unknown error", req->rcall);
+                       }
+
+                       if (!req->err)
+                               req->err = -ESERVERFAULT;
+               }
+       } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
+               dprintk(DEBUG_ERROR, "fcall mismatch: expected %d, got %d\n",
+                       req->tcall->id + 1, req->rcall->id);
+               if (!req->err)
+                       req->err = -EIO;
+       }
 
-               spin_unlock(&v9ses->muxlock);
-               if (ret >= 0)
-                       ret = -EREMOTEIO;
+       if (req->cb && req->err != ERREQFLUSH) {
+               dprintk(DEBUG_MUX, "calling callback tcall %p rcall %p\n",
+                       req->tcall, req->rcall);
+
+               (*req->cb) (req->cba, req->tcall, req->rcall, req->err);
+               req->cb = NULL;
        } else
-               ret = 0;
+               kfree(req->rcall);
 
-      free_data:
-       kfree(data);
-       return ret;
+       v9fs_mux_put_tag(m, tag);
+
+       wake_up(&m->equeue);
+       kfree(req);
 }
 
 /**
- * v9fs_mux_rpc - send a request, receive a response
- * @v9ses: session info structure
- * @tcall: fcall to send
- * @rcall: buffer to place response into
- *
+ * v9fs_read_work - called when there is some data to be read from a transport
  */
-
-long
-v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall,
-            struct v9fs_fcall **rcall)
+static void v9fs_read_work(void *a)
 {
-       int tid = -1;
-       struct v9fs_fcall *fcall = NULL;
-       struct v9fs_rpcreq req;
-       int ret = -1;
-
-       if (!v9ses)
-               return -EINVAL;
-
-       if (!v9ses->transport || v9ses->transport->status != Connected)
-               return -EIO;
+       int n, err;
+       struct v9fs_mux_data *m;
+       struct v9fs_req *req, *rptr, *rreq;
+       struct v9fs_fcall *rcall;
+       char *rbuf;
+
+       m = a;
+
+       if (m->err < 0)
+               return;
+
+       rcall = NULL;
+       dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
+
+       if (!m->rcall) {
+               m->rcall =
+                   kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL);
+               if (!m->rcall) {
+                       err = -ENOMEM;
+                       goto error;
+               }
 
-       if (rcall)
-               *rcall = NULL;
+               m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
+               m->rpos = 0;
+       }
 
-       if (tcall->id != TVERSION) {
-               tid = v9fs_get_idpool(&v9ses->tidpool);
-               if (tid < 0)
-                       return -ENOMEM;
+       clear_bit(Rpending, &m->wsched);
+       err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
+       dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err);
+       if (err == -EAGAIN) {
+               clear_bit(Rworksched, &m->wsched);
+               return;
        }
 
-       tcall->tag = tid;
+       if (err <= 0)
+               goto error;
 
-       req.tcall = tcall;
-       req.err = 0;
-       req.rcall = NULL;
+       m->rpos += err;
+       while (m->rpos > 4) {
+               n = le32_to_cpu(*(__le32 *) m->rbuf);
+               if (n >= m->msize) {
+                       dprintk(DEBUG_ERROR,
+                               "requested packet size too big: %d\n", n);
+                       err = -EIO;
+                       goto error;
+               }
 
-       ret = v9fs_send(v9ses, &req);
+               if (m->rpos < n)
+                       break;
 
-       if (ret < 0) {
-               if (tcall->id != TVERSION)
-                       v9fs_put_idpool(tid, &v9ses->tidpool);
-               dprintk(DEBUG_MUX, "error %d\n", ret);
-               return ret;
-       }
+               dump_data(m->rbuf, n);
+               err =
+                   v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
+               if (err < 0) {
+                       goto error;
+               }
+
+               rcall = m->rcall;
+               rbuf = m->rbuf;
+               if (m->rpos > n) {
+                       m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize,
+                                          GFP_KERNEL);
+                       if (!m->rcall) {
+                               err = -ENOMEM;
+                               goto error;
+                       }
 
-       ret = v9fs_recv(v9ses, &req);
-
-       fcall = req.rcall;
-
-       dprintk(DEBUG_MUX, "received: tag=%x, ret=%d\n", tcall->tag, ret);
-       if (ret == -ERESTARTSYS) {
-               if (v9ses->transport->status != Disconnected
-                   && tcall->id != TFLUSH) {
-                       unsigned long flags;
-
-                       dprintk(DEBUG_MUX, "flushing the tag: %d\n",
-                               tcall->tag);
-                       clear_thread_flag(TIF_SIGPENDING);
-                       v9fs_t_flush(v9ses, tcall->tag);
-                       spin_lock_irqsave(&current->sighand->siglock, flags);
-                       recalc_sigpending();
-                       spin_unlock_irqrestore(&current->sighand->siglock,
-                                              flags);
-                       dprintk(DEBUG_MUX, "flushing done\n");
+                       m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
+                       memmove(m->rbuf, rbuf + n, m->rpos - n);
+                       m->rpos -= n;
+               } else {
+                       m->rcall = NULL;
+                       m->rbuf = NULL;
+                       m->rpos = 0;
                }
 
-               goto release_req;
-       } else if (ret < 0)
-               goto release_req;
-
-       if (!fcall)
-               ret = -EIO;
-       else {
-               if (fcall->id == RERROR) {
-                       ret = v9fs_errstr2errno(fcall->params.rerror.error);
-                       if (ret == 0) { /* string match failed */
-                               if (fcall->params.rerror.errno)
-                                       ret = -(fcall->params.rerror.errno);
-                               else
-                                       ret = -ESERVERFAULT;
+               dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id,
+                       rcall->tag);
+
+               req = NULL;
+               spin_lock(&m->lock);
+               list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
+                       if (rreq->tag == rcall->tag) {
+                               req = rreq;
+                               req->rcall = rcall;
+                               list_del(&req->req_list);
+                               spin_unlock(&m->lock);
+                               process_request(m, req);
+                               break;
                        }
-               } else if (fcall->id != tcall->id + 1) {
-                       dprintk(DEBUG_ERROR,
-                               "fcall mismatch: expected %d, got %d\n",
-                               tcall->id + 1, fcall->id);
-                       ret = -EIO;
+
+               }
+
+               if (!req) {
+                       spin_unlock(&m->lock);
+                       if (err >= 0 && rcall->id != RFLUSH)
+                               dprintk(DEBUG_ERROR,
+                                       "unexpected response mux %p id %d tag %d\n",
+                                       m, rcall->id, rcall->tag);
+                       kfree(rcall);
                }
        }
 
-      release_req:
-       if (tcall->id != TVERSION)
-               v9fs_put_idpool(tid, &v9ses->tidpool);
-       if (rcall)
-               *rcall = fcall;
-       else
-               kfree(fcall);
+       if (!list_empty(&m->req_list)) {
+               if (test_and_clear_bit(Rpending, &m->wsched))
+                       n = POLLIN;
+               else
+                       n = m->trans->poll(m->trans, NULL);
+
+               if (n & POLLIN) {
+                       dprintk(DEBUG_MUX, "schedule read work mux %p\n", m);
+                       queue_work(v9fs_mux_wq, &m->rq);
+               } else
+                       clear_bit(Rworksched, &m->wsched);
+       } else
+               clear_bit(Rworksched, &m->wsched);
+
+       return;
 
-       return ret;
+      error:
+       v9fs_mux_cancel(m, err);
+       clear_bit(Rworksched, &m->wsched);
 }
 
 /**
- * v9fs_mux_cancel_requests - cancels all pending requests
+ * v9fs_send_request - send 9P request
+ * The function can sleep until the request is scheduled for sending.
+ * The function can be interrupted. Return from the function is not
+ * a guarantee that the request is sent succesfully. Can return errors
+ * that can be retrieved by PTR_ERR macros.
  *
- * @v9ses: session info structure
- * @err: error code to return to the requests
+ * @m: mux data
+ * @tc: request to be sent
+ * @cb: callback function to call when response is received
+ * @cba: parameter to pass to the callback function
  */
-void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err)
+static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m,
+                                         struct v9fs_fcall *tc,
+                                         v9fs_mux_req_callback cb, void *cba)
 {
-       struct v9fs_rpcreq *rptr;
-       struct v9fs_rpcreq *rreq;
+       int n;
+       struct v9fs_req *req;
 
-       dprintk(DEBUG_MUX, " %d\n", err);
-       spin_lock(&v9ses->muxlock);
-       list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
-               rreq->err = err;
-       }
-       spin_unlock(&v9ses->muxlock);
-       wake_up_all(&v9ses->read_wait);
-}
+       dprintk(DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
+               tc, tc->id);
+       if (m->err < 0)
+               return ERR_PTR(m->err);
 
-/**
- * v9fs_recvproc - kproc to handle demultiplexing responses
- * @data: session info structure
- *
- */
+       req = kmalloc(sizeof(struct v9fs_req), GFP_KERNEL);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
 
-static int v9fs_recvproc(void *data)
-{
-       struct v9fs_session_info *v9ses = (struct v9fs_session_info *)data;
-       struct v9fs_fcall *rcall = NULL;
-       struct v9fs_rpcreq *rptr;
-       struct v9fs_rpcreq *req;
-       struct v9fs_rpcreq *rreq;
-       int err = 0;
+       if (tc->id == TVERSION)
+               n = V9FS_NOTAG;
+       else
+               n = v9fs_mux_get_tag(m);
 
-       allow_signal(SIGKILL);
-       set_current_state(TASK_INTERRUPTIBLE);
-       complete(&v9ses->proccmpl);
-       while (!kthread_should_stop() && err >= 0) {
-               req = rptr = rreq = NULL;
-
-               rcall = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL);
-               if (!rcall) {
-                       eprintk(KERN_ERR, "no memory for buffers\n");
-                       break;
-               }
+       if (n < 0)
+               return ERR_PTR(-ENOMEM);
 
-               err = read_message(v9ses, rcall, v9ses->maxdata + V9FS_IOHDRSZ);
-               spin_lock(&v9ses->muxlock);
-               if (err < 0) {
-                       list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
-                               rreq->err = err;
-                       }
-                       if(err != -ERESTARTSYS)
-                               eprintk(KERN_ERR,
-                                       "Transport error while reading message %d\n", err);
-               } else {
-                       list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
-                               if (rreq->tcall->tag == rcall->tag) {
-                                       req = rreq;
-                                       req->rcall = rcall;
-                                       break;
-                               }
-                       }
-               }
+       v9fs_set_tag(tc, n);
 
-               if (req && (req->tcall->id == TFLUSH)) {
-                       struct v9fs_rpcreq *treq = NULL;
-                       list_for_each_entry_safe(treq, rptr, &v9ses->mux_fcalls, next) {
-                               if (treq->tcall->tag ==
-                                   req->tcall->params.tflush.oldtag) {
-                                       list_del(&rptr->next);
-                                       kfree(treq->rcall);
-                                       break;
-                               }
+       req->tag = n;
+       req->tcall = tc;
+       req->rcall = NULL;
+       req->err = 0;
+       req->cb = cb;
+       req->cba = cba;
+
+       spin_lock(&m->lock);
+       list_add_tail(&req->req_list, &m->unsent_req_list);
+       spin_unlock(&m->lock);
+
+       if (test_and_clear_bit(Wpending, &m->wsched))
+               n = POLLOUT;
+       else
+               n = m->trans->poll(m->trans, NULL);
+
+       if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
+               queue_work(v9fs_mux_wq, &m->wq);
+
+       return req;
+}
+
+static inline void
+v9fs_mux_flush_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc,
+                 int err)
+{
+       v9fs_mux_req_callback cb;
+       int tag;
+       struct v9fs_mux_data *m;
+       struct v9fs_req *req, *rptr;
+
+       m = a;
+       dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, tc,
+               rc, err, tc->params.tflush.oldtag);
+
+       spin_lock(&m->lock);
+       cb = NULL;
+       tag = tc->params.tflush.oldtag;
+       list_for_each_entry_safe(req, rptr, &m->req_list, req_list) {
+               if (req->tag == tag) {
+                       list_del(&req->req_list);
+                       if (req->cb) {
+                               cb = req->cb;
+                               req->cb = NULL;
+                               spin_unlock(&m->lock);
+                               (*cb) (req->cba, req->tcall, req->rcall,
+                                      req->err);
                        }
+                       kfree(req);
+                       wake_up(&m->equeue);
+                       break;
                }
+       }
 
-               spin_unlock(&v9ses->muxlock);
+       if (!cb)
+               spin_unlock(&m->lock);
 
-               if (!req) {
-                       if (err >= 0)
-                               dprintk(DEBUG_ERROR,
-                                       "unexpected response: id %d tag %d\n",
-                                       rcall->id, rcall->tag);
+       v9fs_mux_put_tag(m, tag);
+       kfree(tc);
+       kfree(rc);
+}
 
-                       kfree(rcall);
-               }
+static void
+v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req)
+{
+       struct v9fs_fcall *fc;
 
-               wake_up_all(&v9ses->read_wait);
-               set_current_state(TASK_INTERRUPTIBLE);
+       dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
+
+       fc = v9fs_create_tflush(req->tag);
+       v9fs_send_request(m, fc, v9fs_mux_flush_cb, m);
+}
+
+static void
+v9fs_mux_rpc_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err)
+{
+       struct v9fs_mux_rpc *r;
+
+       if (err == ERREQFLUSH) {
+               dprintk(DEBUG_MUX, "err req flush\n");
+               return;
        }
 
-       v9ses->transport->close(v9ses->transport);
+       r = a;
+       dprintk(DEBUG_MUX, "mux %p req %p tc %p rc %p err %d\n", r->m, r->req,
+               tc, rc, err);
+       r->rcall = rc;
+       r->err = err;
+       wake_up(&r->wqueue);
+}
 
-       /* Inform all pending processes about the failure */
-       wake_up_all(&v9ses->read_wait);
+/**
+ * v9fs_mux_rpc - sends 9P request and waits until a response is available.
+ *     The function can be interrupted.
+ * @m: mux data
+ * @tc: request to be sent
+ * @rc: pointer where a pointer to the response is stored
+ */
+int
+v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
+            struct v9fs_fcall **rc)
+{
+       int err;
+       unsigned long flags;
+       struct v9fs_req *req;
+       struct v9fs_mux_rpc r;
+
+       r.err = 0;
+       r.rcall = NULL;
+       r.m = m;
+       init_waitqueue_head(&r.wqueue);
+
+       if (rc)
+               *rc = NULL;
+
+       req = v9fs_send_request(m, tc, v9fs_mux_rpc_cb, &r);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               dprintk(DEBUG_MUX, "error %d\n", err);
+               return PTR_ERR(req);
+       }
 
-       if (signal_pending(current))
-               complete(&v9ses->proccmpl);
+       r.req = req;
+       dprintk(DEBUG_MUX, "mux %p tc %p tag %d rpc %p req %p\n", m, tc,
+               req->tag, &r, req);
+       err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
+       if (r.err < 0)
+               err = r.err;
+
+       if (err == -ERESTARTSYS && m->trans->status == Connected && m->err == 0) {
+               spin_lock(&m->lock);
+               req->tcall = NULL;
+               req->err = ERREQFLUSH;
+               spin_unlock(&m->lock);
+
+               clear_thread_flag(TIF_SIGPENDING);
+               v9fs_mux_flush_request(m, req);
+               spin_lock_irqsave(&current->sighand->siglock, flags);
+               recalc_sigpending();
+               spin_unlock_irqrestore(&current->sighand->siglock, flags);
+       }
 
-       dprintk(DEBUG_MUX, "recvproc: end\n");
-       v9ses->recvproc = NULL;
+       if (!err) {
+               if (r.rcall)
+                       dprintk(DEBUG_MUX, "got response id %d tag %d\n",
+                               r.rcall->id, r.rcall->tag);
+
+               if (rc)
+                       *rc = r.rcall;
+               else
+                       kfree(r.rcall);
+       } else {
+               kfree(r.rcall);
+               dprintk(DEBUG_MUX, "got error %d\n", err);
+               if (err > 0)
+                       err = -EIO;
+       }
 
-       return err >= 0;
+       return err;
 }
 
 /**
- * v9fs_mux_init - initialize multiplexer (spawn kproc)
- * @v9ses: session info structure
- * @dev_name: mount device information (to create unique kproc)
- *
+ * v9fs_mux_rpcnb - sends 9P request without waiting for response.
+ * @m: mux data
+ * @tc: request to be sent
+ * @cb: callback function to be called when response arrives
+ * @cba: value to pass to the callback function
  */
+int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
+                  v9fs_mux_req_callback cb, void *a)
+{
+       int err;
+       struct v9fs_req *req;
+
+       req = v9fs_send_request(m, tc, cb, a);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               dprintk(DEBUG_MUX, "error %d\n", err);
+               return PTR_ERR(req);
+       }
+
+       dprintk(DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
+       return 0;
+}
 
-int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name)
+/**
+ * v9fs_mux_cancel - cancel all pending requests with error
+ * @m: mux data
+ * @err: error code
+ */
+void v9fs_mux_cancel(struct v9fs_mux_data *m, int err)
 {
-       char procname[60];
-
-       strncpy(procname, dev_name, sizeof(procname));
-       procname[sizeof(procname) - 1] = 0;
-
-       init_waitqueue_head(&v9ses->read_wait);
-       init_completion(&v9ses->fcread);
-       init_completion(&v9ses->proccmpl);
-       spin_lock_init(&v9ses->muxlock);
-       INIT_LIST_HEAD(&v9ses->mux_fcalls);
-       v9ses->recvproc = NULL;
-       v9ses->curfcall = NULL;
-
-       v9ses->recvproc = kthread_create(v9fs_recvproc, v9ses,
-                                        "v9fs_recvproc %s", procname);
-
-       if (IS_ERR(v9ses->recvproc)) {
-               eprintk(KERN_ERR, "cannot create receiving thread\n");
-               v9fs_session_close(v9ses);
-               return -ECONNABORTED;
+       struct v9fs_req *req, *rtmp;
+       LIST_HEAD(cancel_list);
+
+       dprintk(DEBUG_MUX, "mux %p err %d\n", m, err);
+       m->err = err;
+       spin_lock(&m->lock);
+       list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
+               list_move(&req->req_list, &cancel_list);
        }
+       spin_unlock(&m->lock);
 
-       wake_up_process(v9ses->recvproc);
-       wait_for_completion(&v9ses->proccmpl);
+       list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
+               list_del(&req->req_list);
+               if (!req->err)
+                       req->err = err;
 
-       return 0;
+               if (req->cb)
+                       (*req->cb) (req->cba, req->tcall, req->rcall, req->err);
+               else
+                       kfree(req->rcall);
+
+               kfree(req);
+       }
+
+       wake_up(&m->equeue);
+}
+
+static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m)
+{
+       int tag;
+
+       tag = v9fs_get_idpool(&m->tidpool);
+       if (tag < 0)
+               return V9FS_NOTAG;
+       else
+               return (u16) tag;
+}
+
+static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag)
+{
+       if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tidpool))
+               v9fs_put_idpool(tag, &m->tidpool);
 }
index 4994cb10badfef1498931d85928a5fb140960e7b..9473b84f24b24e397643fafea035af9aad255a13 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Multiplexer Definitions
  *
+ *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-/* structure to manage each RPC transaction */
+struct v9fs_mux_data;
 
-struct v9fs_rpcreq {
-       struct v9fs_fcall *tcall;
-       struct v9fs_fcall *rcall;
-       int err;        /* error code if response failed */
+/**
+ * v9fs_mux_req_callback - callback function that is called when the
+ * response of a request is received. The callback is called from
+ * a workqueue and shouldn't block.
+ *
+ * @a - the pointer that was specified when the request was send to be
+ *      passed to the callback
+ * @tc - request call
+ * @rc - response call
+ * @err - error code (non-zero if error occured)
+ */
+typedef void (*v9fs_mux_req_callback)(void *a, struct v9fs_fcall *tc,
+       struct v9fs_fcall *rc, int err);
+
+int v9fs_mux_global_init(void);
+void v9fs_mux_global_exit(void);
 
-       /* XXX - could we put scatter/gather buffers here? */
+struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
+       unsigned char *extended);
+void v9fs_mux_destroy(struct v9fs_mux_data *);
 
-       struct list_head next;
-};
+int v9fs_mux_send(struct v9fs_mux_data *m, struct v9fs_fcall *tc);
+struct v9fs_fcall *v9fs_mux_recv(struct v9fs_mux_data *m);
+int v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, struct v9fs_fcall **rc);
+int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
+       v9fs_mux_req_callback cb, void *a);
 
-int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name);
-long v9fs_mux_rpc(struct v9fs_session_info *v9ses,
-                 struct v9fs_fcall *tcall, struct v9fs_fcall **rcall);
-void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err);
+void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush);
+void v9fs_mux_cancel(struct v9fs_mux_data *m, int err);
+int v9fs_errstr2errno(char *errstr, int len);
index 63b58ce98ff45cbc4c1f19eb668b8fb61f18b706..1a28ef97a3d116f9aa307443794ffe6314fefb60 100644 (file)
@@ -3,6 +3,7 @@
  *
  * File Descriptor Transport Layer
  *
+ *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
  *  Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -106,9 +107,6 @@ v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
                return -ENOPROTOOPT;
        }
 
-       sema_init(&trans->writelock, 1);
-       sema_init(&trans->readlock, 1);
-
        ts = kmalloc(sizeof(struct v9fs_trans_fd), GFP_KERNEL);
 
        if (!ts)
@@ -148,12 +146,12 @@ static void v9fs_fd_close(struct v9fs_transport *trans)
        if (!trans)
                return;
 
-       trans->status = Disconnected;
-       ts = trans->priv;
+       ts = xchg(&trans->priv, NULL);
 
        if (!ts)
                return;
 
+       trans->status = Disconnected;
        if (ts->in_file)
                fput(ts->in_file);
 
@@ -163,10 +161,55 @@ static void v9fs_fd_close(struct v9fs_transport *trans)
        kfree(ts);
 }
 
+static unsigned int
+v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt)
+{
+       int ret, n;
+       struct v9fs_trans_fd *ts;
+       mm_segment_t oldfs;
+
+       if (!trans)
+               return -EIO;
+
+       ts = trans->priv;
+       if (trans->status != Connected || !ts)
+               return -EIO;
+
+       oldfs = get_fs();
+       set_fs(get_ds());
+
+       if (!ts->in_file->f_op || !ts->in_file->f_op->poll) {
+               ret = -EIO;
+               goto end;
+       }
+
+       ret = ts->in_file->f_op->poll(ts->in_file, pt);
+
+       if (ts->out_file != ts->in_file) {
+               if (!ts->out_file->f_op || !ts->out_file->f_op->poll) {
+                       ret = -EIO;
+                       goto end;
+               }
+
+               n = ts->out_file->f_op->poll(ts->out_file, pt);
+
+               ret &= ~POLLOUT;
+               n &= ~POLLIN;
+
+               ret |= n;
+       }
+
+end:
+       set_fs(oldfs);
+       return ret;
+}
+
+
 struct v9fs_transport v9fs_trans_fd = {
        .init = v9fs_fd_init,
        .write = v9fs_fd_send,
        .read = v9fs_fd_recv,
        .close = v9fs_fd_close,
+       .poll = v9fs_fd_poll,
 };
 
index 6a9a75d40f735c209c4e95aefab71178f07990fd..44e830697acb04b9fa205d84f5e3adc2da05bbbb 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Socket Transport Layer
  *
+ *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
  *  Copyright (C) 1995, 1996 by Olaf Kirch <okir@monad.swb.de>
@@ -36,6 +37,7 @@
 #include <asm/uaccess.h>
 #include <linux/inet.h>
 #include <linux/idr.h>
+#include <linux/file.h>
 
 #include "debug.h"
 #include "v9fs.h"
@@ -45,6 +47,7 @@
 
 struct v9fs_trans_sock {
        struct socket *s;
+       struct file *filp;
 };
 
 /**
@@ -57,41 +60,26 @@ struct v9fs_trans_sock {
 
 static int v9fs_sock_recv(struct v9fs_transport *trans, void *v, int len)
 {
-       struct msghdr msg;
-       struct kvec iov;
-       int result;
-       mm_segment_t oldfs;
-       struct v9fs_trans_sock *ts = trans ? trans->priv : NULL;
+       int ret;
+       struct v9fs_trans_sock *ts;
 
-       if (trans->status == Disconnected)
+       if (!trans || trans->status == Disconnected) {
+               dprintk(DEBUG_ERROR, "disconnected ...\n");
                return -EREMOTEIO;
+       }
 
-       result = -EINVAL;
-
-       oldfs = get_fs();
-       set_fs(get_ds());
-
-       iov.iov_base = v;
-       iov.iov_len = len;
-       msg.msg_name = NULL;
-       msg.msg_namelen = 0;
-       msg.msg_iovlen = 1;
-       msg.msg_control = NULL;
-       msg.msg_controllen = 0;
-       msg.msg_namelen = 0;
-       msg.msg_flags = MSG_NOSIGNAL;
+       ts = trans->priv;
 
-       result = kernel_recvmsg(ts->s, &msg, &iov, 1, len, 0);
+       if (!(ts->filp->f_flags & O_NONBLOCK))
+               dprintk(DEBUG_ERROR, "blocking read ...\n");
 
-       dprintk(DEBUG_TRANS, "socket state %d\n", ts->s->state);
-       set_fs(oldfs);
-
-       if (result <= 0) {
-               if (result != -ERESTARTSYS)
+       ret = kernel_read(ts->filp, ts->filp->f_pos, v, len);
+       if (ret <= 0) {
+               if (ret != -ERESTARTSYS && ret != -EAGAIN)
                        trans->status = Disconnected;
        }
 
-       return result;
+       return ret;
 }
 
 /**
@@ -104,40 +92,72 @@ static int v9fs_sock_recv(struct v9fs_transport *trans, void *v, int len)
 
 static int v9fs_sock_send(struct v9fs_transport *trans, void *v, int len)
 {
-       struct kvec iov;
-       struct msghdr msg;
-       int result = -1;
+       int ret;
        mm_segment_t oldfs;
-       struct v9fs_trans_sock *ts = trans ? trans->priv : NULL;
+       struct v9fs_trans_sock *ts;
 
-       dprintk(DEBUG_TRANS, "Sending packet size %d (%x)\n", len, len);
-       dump_data(v, len);
+       if (!trans || trans->status == Disconnected) {
+               dprintk(DEBUG_ERROR, "disconnected ...\n");
+               return -EREMOTEIO;
+       }
+
+       ts = trans->priv;
+       if (!ts) {
+               dprintk(DEBUG_ERROR, "no transport ...\n");
+               return -EREMOTEIO;
+       }
 
-       down(&trans->writelock);
+       if (!(ts->filp->f_flags & O_NONBLOCK))
+               dprintk(DEBUG_ERROR, "blocking write ...\n");
 
        oldfs = get_fs();
        set_fs(get_ds());
-       iov.iov_base = v;
-       iov.iov_len = len;
-       msg.msg_name = NULL;
-       msg.msg_namelen = 0;
-       msg.msg_iovlen = 1;
-       msg.msg_control = NULL;
-       msg.msg_controllen = 0;
-       msg.msg_namelen = 0;
-       msg.msg_flags = MSG_NOSIGNAL;
-       result = kernel_sendmsg(ts->s, &msg, &iov, 1, len);
+       ret = vfs_write(ts->filp, (void __user *)v, len, &ts->filp->f_pos);
        set_fs(oldfs);
 
-       if (result < 0) {
-               if (result != -ERESTARTSYS)
+       if (ret < 0) {
+               if (ret != -ERESTARTSYS)
                        trans->status = Disconnected;
        }
 
-       up(&trans->writelock);
-       return result;
+       return ret;
+}
+
+static unsigned int v9fs_sock_poll(struct v9fs_transport *trans,
+       struct poll_table_struct *pt) {
+
+       int ret;
+       struct v9fs_trans_sock *ts;
+       mm_segment_t oldfs;
+
+       if (!trans) {
+               dprintk(DEBUG_ERROR, "no transport\n");
+               return -EIO;
+       }
+
+       ts = trans->priv;
+       if (trans->status != Connected || !ts) {
+               dprintk(DEBUG_ERROR, "transport disconnected: %d\n", trans->status);
+               return -EIO;
+       }
+
+       oldfs = get_fs();
+       set_fs(get_ds());
+
+       if (!ts->filp->f_op || !ts->filp->f_op->poll) {
+               dprintk(DEBUG_ERROR, "no poll operation\n");
+               ret = -EIO;
+               goto end;
+       }
+
+       ret = ts->filp->f_op->poll(ts->filp, pt);
+
+end:
+       set_fs(oldfs);
+       return ret;
 }
 
+
 /**
  * v9fs_tcp_init - initialize TCP socket
  * @v9ses: session information
@@ -154,9 +174,9 @@ v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
        int rc = 0;
        struct v9fs_trans_sock *ts = NULL;
        struct v9fs_transport *trans = v9ses->transport;
+       int fd;
 
-       sema_init(&trans->writelock, 1);
-       sema_init(&trans->readlock, 1);
+       trans->status = Disconnected;
 
        ts = kmalloc(sizeof(struct v9fs_trans_sock), GFP_KERNEL);
 
@@ -165,6 +185,7 @@ v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
 
        trans->priv = ts;
        ts->s = NULL;
+       ts->filp = NULL;
 
        if (!addr)
                return -EINVAL;
@@ -185,7 +206,18 @@ v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
                return rc;
        }
        csocket->sk->sk_allocation = GFP_NOIO;
+
+       fd = sock_map_fd(csocket);
+       if (fd < 0) {
+               sock_release(csocket);
+               kfree(ts);
+               trans->priv = NULL;
+               return fd;
+       }
+
        ts->s = csocket;
+       ts->filp = fget(fd);
+       ts->filp->f_flags |= O_NONBLOCK;
        trans->status = Connected;
 
        return 0;
@@ -203,7 +235,7 @@ static int
 v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name,
               char *data)
 {
-       int rc;
+       int rc, fd;
        struct socket *csocket;
        struct sockaddr_un sun_server;
        struct v9fs_transport *trans;
@@ -213,6 +245,8 @@ v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name,
        csocket = NULL;
        trans = v9ses->transport;
 
+       trans->status = Disconnected;
+
        if (strlen(dev_name) > UNIX_PATH_MAX) {
                eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n",
                        dev_name);
@@ -225,9 +259,7 @@ v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name,
 
        trans->priv = ts;
        ts->s = NULL;
-
-       sema_init(&trans->writelock, 1);
-       sema_init(&trans->readlock, 1);
+       ts->filp = NULL;
 
        sun_server.sun_family = PF_UNIX;
        strcpy(sun_server.sun_path, dev_name);
@@ -241,7 +273,18 @@ v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name,
                return rc;
        }
        csocket->sk->sk_allocation = GFP_NOIO;
+
+       fd = sock_map_fd(csocket);
+       if (fd < 0) {
+               sock_release(csocket);
+               kfree(ts);
+               trans->priv = NULL;
+               return fd;
+       }
+
        ts->s = csocket;
+       ts->filp = fget(fd);
+       ts->filp->f_flags |= O_NONBLOCK;
        trans->status = Connected;
 
        return 0;
@@ -262,12 +305,11 @@ static void v9fs_sock_close(struct v9fs_transport *trans)
 
        ts = trans->priv;
 
-       if ((ts) && (ts->s)) {
-               dprintk(DEBUG_TRANS, "closing the socket %p\n", ts->s);
-               sock_release(ts->s);
+       if ((ts) && (ts->filp)) {
+               fput(ts->filp);
+               ts->filp = NULL;
                ts->s = NULL;
                trans->status = Disconnected;
-               dprintk(DEBUG_TRANS, "socket closed\n");
        }
 
        kfree(ts);
@@ -280,6 +322,7 @@ struct v9fs_transport v9fs_trans_tcp = {
        .write = v9fs_sock_send,
        .read = v9fs_sock_recv,
        .close = v9fs_sock_close,
+       .poll = v9fs_sock_poll,
 };
 
 struct v9fs_transport v9fs_trans_unix = {
@@ -287,4 +330,5 @@ struct v9fs_transport v9fs_trans_unix = {
        .write = v9fs_sock_send,
        .read = v9fs_sock_recv,
        .close = v9fs_sock_close,
+       .poll = v9fs_sock_poll,
 };
index 9e9cd418efd54c6aea248e1068577d7a72317c46..91fcdb94b361be46b5f160f793e0dadfd705974c 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Transport Definition
  *
+ *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -31,14 +32,13 @@ enum v9fs_transport_status {
 
 struct v9fs_transport {
        enum v9fs_transport_status status;
-       struct semaphore writelock;
-       struct semaphore readlock;
        void *priv;
 
        int (*init) (struct v9fs_session_info *, const char *, char *);
        int (*write) (struct v9fs_transport *, void *, int);
        int (*read) (struct v9fs_transport *, void *, int);
        void (*close) (struct v9fs_transport *);
+       unsigned int (*poll)(struct v9fs_transport *, struct poll_table_struct *);
 };
 
 extern struct v9fs_transport v9fs_trans_tcp;
index 418c3743fdee85c89452f9f6c0dda13dbb404007..5250c428fc1f0badf7b6bac4c4cb15fde72ed2cc 100644 (file)
@@ -37,7 +37,6 @@
 #include "v9fs_vfs.h"
 #include "transport.h"
 #include "mux.h"
-#include "conv.h"
 
 /* TODO: sysfs or debugfs interface */
 int v9fs_debug_level = 0;      /* feature-rific global debug level  */
@@ -213,7 +212,8 @@ retry:
                return -1;
        }
 
-       error = idr_get_new(&p->pool, NULL, &i);
+       /* no need to store exactly p, we just need something non-null */
+       error = idr_get_new(&p->pool, p, &i);
        up(&p->lock);
 
        if (error == -EAGAIN)
@@ -242,6 +242,16 @@ void v9fs_put_idpool(int id, struct v9fs_idpool *p)
        up(&p->lock);
 }
 
+/**
+ * v9fs_check_idpool - check if the specified id is available
+ * @id - id to check
+ * @p - pool
+ */
+int v9fs_check_idpool(int id, struct v9fs_idpool *p)
+{
+       return idr_find(&p->pool, id) != NULL;
+}
+
 /**
  * v9fs_session_init - initialize session
  * @v9ses: session information structure
@@ -259,6 +269,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
        int n = 0;
        int newfid = -1;
        int retval = -EINVAL;
+       struct v9fs_str *version;
 
        v9ses->name = __getname();
        if (!v9ses->name)
@@ -281,9 +292,6 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
        /* id pools that are session-dependent: FIDs and TIDs */
        idr_init(&v9ses->fidpool.pool);
        init_MUTEX(&v9ses->fidpool.lock);
-       idr_init(&v9ses->tidpool.pool);
-       init_MUTEX(&v9ses->tidpool.lock);
-
 
        switch (v9ses->proto) {
        case PROTO_TCP:
@@ -320,7 +328,12 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
        v9ses->shutdown = 0;
        v9ses->session_hung = 0;
 
-       if ((retval = v9fs_mux_init(v9ses, dev_name)) < 0) {
+       v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ,
+               &v9ses->extended);
+
+       if (IS_ERR(v9ses->mux)) {
+               retval = PTR_ERR(v9ses->mux);
+               v9ses->mux = NULL;
                dprintk(DEBUG_ERROR, "problem initializing mux\n");
                goto SessCleanUp;
        }
@@ -339,13 +352,16 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
                        goto FreeFcall;
                }
 
-               /* Really should check for 9P1 and report error */
-               if (!strcmp(fcall->params.rversion.version, "9P2000.u")) {
+               version = &fcall->params.rversion.version;
+               if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) {
                        dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
                        v9ses->extended = 1;
-               } else {
+               } else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) {
                        dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n");
                        v9ses->extended = 0;
+               } else {
+                       retval = -EREMOTEIO;
+                       goto FreeFcall;
                }
 
                n = fcall->params.rversion.msize;
@@ -381,7 +397,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
        }
 
        if (v9ses->afid != ~0) {
-               if (v9fs_t_clunk(v9ses, v9ses->afid, NULL))
+               if (v9fs_t_clunk(v9ses, v9ses->afid))
                        dprintk(DEBUG_ERROR, "clunk failed\n");
        }
 
@@ -403,13 +419,16 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
 
 void v9fs_session_close(struct v9fs_session_info *v9ses)
 {
-       if (v9ses->recvproc) {
-               send_sig(SIGKILL, v9ses->recvproc, 1);
-               wait_for_completion(&v9ses->proccmpl);
+       if (v9ses->mux) {
+               v9fs_mux_destroy(v9ses->mux);
+               v9ses->mux = NULL;
        }
 
-       if (v9ses->transport)
+       if (v9ses->transport) {
                v9ses->transport->close(v9ses->transport);
+               kfree(v9ses->transport);
+               v9ses->transport = NULL;
+       }
 
        __putname(v9ses->name);
        __putname(v9ses->remotename);
@@ -420,8 +439,9 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
  *     and cancel all pending requests.
  */
 void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
+       dprintk(DEBUG_ERROR, "cancel session %p\n", v9ses);
        v9ses->transport->status = Disconnected;
-       v9fs_mux_cancel_requests(v9ses, -EIO);
+       v9fs_mux_cancel(v9ses->mux, -EIO);
 }
 
 extern int v9fs_error_init(void);
@@ -433,11 +453,17 @@ extern int v9fs_error_init(void);
 
 static int __init init_v9fs(void)
 {
+       int ret;
+
        v9fs_error_init();
 
        printk(KERN_INFO "Installing v9fs 9P2000 file system support\n");
 
-       return register_filesystem(&v9fs_fs_type);
+       ret = v9fs_mux_global_init();
+       if (!ret)
+               ret = register_filesystem(&v9fs_fs_type);
+
+       return ret;
 }
 
 /**
@@ -447,6 +473,7 @@ static int __init init_v9fs(void)
 
 static void __exit exit_v9fs(void)
 {
+       v9fs_mux_global_exit();
        unregister_filesystem(&v9fs_fs_type);
 }
 
index 45dcef42bdd63b7de3c74a46577f616a27d006f6..f337da7a0eec1c4c6be93307172ba5e9f7511b70 100644 (file)
@@ -57,24 +57,14 @@ struct v9fs_session_info {
 
        /* book keeping */
        struct v9fs_idpool fidpool;     /* The FID pool for file descriptors */
-       struct v9fs_idpool tidpool;     /* The TID pool for transactions ids */
 
-       /* transport information */
        struct v9fs_transport *transport;
+       struct v9fs_mux_data *mux;
 
        int inprogress;         /* session in progress => true */
        int shutdown;           /* session shutting down. no more attaches. */
        unsigned char session_hung;
-
-       /* mux private data */
-       struct v9fs_fcall *curfcall;
-       wait_queue_head_t read_wait;
-       struct completion fcread;
-       struct completion proccmpl;
-       struct task_struct *recvproc;
-
-       spinlock_t muxlock;
-       struct list_head mux_fcalls;
+       struct dentry *debugfs_dir;
 };
 
 /* possible values of ->proto */
@@ -84,11 +74,14 @@ enum {
        PROTO_FD,
 };
 
+extern struct dentry *v9fs_debugfs_root;
+
 int v9fs_session_init(struct v9fs_session_info *, const char *, char *);
 struct v9fs_session_info *v9fs_inode2v9ses(struct inode *);
 void v9fs_session_close(struct v9fs_session_info *v9ses);
 int v9fs_get_idpool(struct v9fs_idpool *p);
 void v9fs_put_idpool(int id, struct v9fs_idpool *p);
+int v9fs_check_idpool(int id, struct v9fs_idpool *p);
 void v9fs_session_cancel(struct v9fs_session_info *v9ses);
 
 #define V9FS_MAGIC 0x01021997
index 2f2cea7ee3e7123fcdedac046c191e24cf227c67..c78502ad00ed3d1dcd52da9a28c556aa9c675adc 100644 (file)
@@ -45,9 +45,8 @@ extern struct dentry_operations v9fs_dentry_operations;
 
 struct inode *v9fs_get_inode(struct super_block *sb, int mode);
 ino_t v9fs_qid2ino(struct v9fs_qid *qid);
-void v9fs_mistat2inode(struct v9fs_stat *, struct inode *,
-                      struct super_block *);
+void v9fs_stat2inode(struct v9fs_stat *, struct inode *, struct super_block *);
 int v9fs_dir_release(struct inode *inode, struct file *filp);
 int v9fs_file_open(struct inode *inode, struct file *file);
-void v9fs_inode2mistat(struct inode *inode, struct v9fs_stat *mistat);
+void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat);
 void v9fs_dentry_release(struct dentry *);
index a6aa947de0f9b7e0c44b4eda3f6df531b2e112bb..2dd806dac9f192bb6075a1164f1d7fc69420f9c9 100644 (file)
@@ -40,7 +40,6 @@
 #include "v9fs.h"
 #include "9p.h"
 #include "v9fs_vfs.h"
-#include "conv.h"
 #include "fid.h"
 
 /**
@@ -95,24 +94,22 @@ static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd)
 
 void v9fs_dentry_release(struct dentry *dentry)
 {
+       int err;
+
        dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
 
        if (dentry->d_fsdata != NULL) {
                struct list_head *fid_list = dentry->d_fsdata;
                struct v9fs_fid *temp = NULL;
                struct v9fs_fid *current_fid = NULL;
-               struct v9fs_fcall *fcall = NULL;
 
                list_for_each_entry_safe(current_fid, temp, fid_list, list) {
-                       if (v9fs_t_clunk
-                           (current_fid->v9ses, current_fid->fid, &fcall))
-                               dprintk(DEBUG_ERROR, "clunk failed: %s\n",
-                                       FCALL_ERROR(fcall));
+                       err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid);
 
-                       v9fs_put_idpool(current_fid->fid,
-                                       &current_fid->v9ses->fidpool);
+                       if (err < 0)
+                               dprintk(DEBUG_ERROR, "clunk failed: %d name %s\n",
+                                       err, dentry->d_iname);
 
-                       kfree(fcall);
                        v9fs_fid_destroy(current_fid);
                }
 
index 57a43b8feef56e9f257434129edcb9b72a07016b..ae6d032b9b59f921118ddfa430532bb4133a72f5 100644 (file)
@@ -37,8 +37,8 @@
 #include "debug.h"
 #include "v9fs.h"
 #include "9p.h"
-#include "v9fs_vfs.h"
 #include "conv.h"
+#include "v9fs_vfs.h"
 #include "fid.h"
 
 /**
@@ -74,20 +74,16 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct inode *inode = filp->f_dentry->d_inode;
        struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
        struct v9fs_fid *file = filp->private_data;
-       unsigned int i, n;
+       unsigned int i, n, s;
        int fid = -1;
        int ret = 0;
-       struct v9fs_stat *mi = NULL;
+       struct v9fs_stat stat;
        int over = 0;
 
        dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name);
 
        fid = file->fid;
 
-       mi = kmalloc(v9ses->maxdata, GFP_KERNEL);
-       if (!mi)
-               return -ENOMEM;
-
        if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) {
                kfree(file->rdir_fcall);
                file->rdir_fcall = NULL;
@@ -97,20 +93,20 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
                n = file->rdir_fcall->params.rread.count;
                i = file->rdir_fpos;
                while (i < n) {
-                       int s = v9fs_deserialize_stat(v9ses,
-                                 file->rdir_fcall->params.rread.data + i,
-                                 n - i, mi, v9ses->maxdata);
+                       s = v9fs_deserialize_stat(
+                               file->rdir_fcall->params.rread.data + i,
+                               n - i, &stat, v9ses->extended);
 
                        if (s == 0) {
                                dprintk(DEBUG_ERROR,
-                                       "error while deserializing mistat\n");
+                                       "error while deserializing stat\n");
                                ret = -EIO;
                                goto FreeStructs;
                        }
 
-                       over = filldir(dirent, mi->name, strlen(mi->name),
-                                   filp->f_pos, v9fs_qid2ino(&mi->qid),
-                                   dt_type(mi));
+                       over = filldir(dirent, stat.name.str, stat.name.len,
+                                   filp->f_pos, v9fs_qid2ino(&stat.qid),
+                                   dt_type(&stat));
 
                        if (over) {
                                file->rdir_fpos = i;
@@ -130,7 +126,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        while (!over) {
                ret = v9fs_t_read(v9ses, fid, filp->f_pos,
-                                           v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
+                       v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
                if (ret < 0) {
                        dprintk(DEBUG_ERROR, "error while reading: %d: %p\n",
                                ret, fcall);
@@ -141,19 +137,18 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
                n = ret;
                i = 0;
                while (i < n) {
-                       int s = v9fs_deserialize_stat(v9ses,
-                                 fcall->params.rread.data + i, n - i, mi,
-                                 v9ses->maxdata);
+                       s = v9fs_deserialize_stat(fcall->params.rread.data + i,
+                               n - i, &stat, v9ses->extended);
 
                        if (s == 0) {
                                dprintk(DEBUG_ERROR,
-                                       "error while deserializing mistat\n");
+                                       "error while deserializing stat\n");
                                return -EIO;
                        }
 
-                       over = filldir(dirent, mi->name, strlen(mi->name),
-                                   filp->f_pos, v9fs_qid2ino(&mi->qid),
-                                   dt_type(mi));
+                       over = filldir(dirent, stat.name.str, stat.name.len,
+                                   filp->f_pos, v9fs_qid2ino(&stat.qid),
+                                   dt_type(&stat));
 
                        if (over) {
                                file->rdir_fcall = fcall;
@@ -172,7 +167,6 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
       FreeStructs:
        kfree(fcall);
-       kfree(mi);
        return ret;
 }
 
@@ -193,18 +187,15 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
                fid->fid);
        fidnum = fid->fid;
 
-       filemap_fdatawrite(inode->i_mapping);
-       filemap_fdatawait(inode->i_mapping);
+       filemap_write_and_wait(inode->i_mapping);
 
        if (fidnum >= 0) {
                dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen,
                        fid->fid);
 
-               if (v9fs_t_clunk(v9ses, fidnum, NULL))
+               if (v9fs_t_clunk(v9ses, fidnum))
                        dprintk(DEBUG_ERROR, "clunk failed\n");
 
-               v9fs_put_idpool(fid->fid, &v9ses->fidpool);
-
                kfree(fid->rdir_fcall);
                kfree(fid);
 
index 89c849da85040edeb0794a93a2a0ad5ba5352387..6852f0eb96ed3a81641a75370bd2a2ce23df4ac7 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 #include <linux/inet.h>
+#include <linux/version.h>
 #include <linux/list.h>
 #include <asm/uaccess.h>
 #include <linux/idr.h>
@@ -117,9 +118,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
 
                result = v9fs_t_open(v9ses, newfid, open_mode, &fcall);
                if (result < 0) {
-                       dprintk(DEBUG_ERROR,
-                               "open failed, open_mode 0x%x: %s\n", open_mode,
-                               FCALL_ERROR(fcall));
+                       PRINT_FCALL_ERROR("open failed", fcall);
                        kfree(fcall);
                        return result;
                }
@@ -165,8 +164,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
                return -ENOLCK;
 
        if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
-               filemap_fdatawrite(inode->i_mapping);
-               filemap_fdatawait(inode->i_mapping);
+               filemap_write_and_wait(inode->i_mapping);
                invalidate_inode_pages(&inode->i_data);
        }
 
@@ -257,7 +255,6 @@ v9fs_file_write(struct file *filp, const char __user * data,
        int result = -EIO;
        int rsize = 0;
        int total = 0;
-       char *buf;
 
        dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count,
                (int)*offset);
@@ -265,28 +262,14 @@ v9fs_file_write(struct file *filp, const char __user * data,
        if (v9fid->iounit != 0 && rsize > v9fid->iounit)
                rsize = v9fid->iounit;
 
-       buf = kmalloc(v9ses->maxdata - V9FS_IOHDRSZ, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
        do {
                if (count < rsize)
                        rsize = count;
 
-               result = copy_from_user(buf, data, rsize);
-               if (result) {
-                       dprintk(DEBUG_ERROR, "Problem copying from user\n");
-                       kfree(buf);
-                       return -EFAULT;
-               }
-
-               dump_data(buf, rsize);
-               result = v9fs_t_write(v9ses, fid, *offset, rsize, buf, &fcall);
+               result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall);
                if (result < 0) {
-                       eprintk(KERN_ERR, "error while writing: %s(%d)\n",
-                               FCALL_ERROR(fcall), result);
+                       PRINT_FCALL_ERROR("error while writing", fcall);
                        kfree(fcall);
-                       kfree(buf);
                        return result;
                } else
                        *offset += result;
@@ -306,7 +289,6 @@ v9fs_file_write(struct file *filp, const char __user * data,
                total += result;
        } while (count);
 
-       kfree(buf);
        return total;
 }
 
index 0ea965c3bb7d0d7233e320a8957be96aaefb33ad..d933ef1fbd8ac4917e5f6efb39cc71fd5abbf0ff 100644 (file)
@@ -40,7 +40,6 @@
 #include "v9fs.h"
 #include "9p.h"
 #include "v9fs_vfs.h"
-#include "conv.h"
 #include "fid.h"
 
 static struct inode_operations v9fs_dir_inode_operations;
@@ -127,100 +126,32 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
 }
 
 /**
- * v9fs_blank_mistat - helper function to setup a 9P stat structure
+ * v9fs_blank_wstat - helper function to setup a 9P stat structure
  * @v9ses: 9P session info (for determining extended mode)
- * @mistat: structure to initialize
+ * @wstat: structure to initialize
  *
  */
 
 static void
-v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat)
+v9fs_blank_wstat(struct v9fs_wstat *wstat)
 {
-       mistat->type = ~0;
-       mistat->dev = ~0;
-       mistat->qid.type = ~0;
-       mistat->qid.version = ~0;
-       *((long long *)&mistat->qid.path) = ~0;
-       mistat->mode = ~0;
-       mistat->atime = ~0;
-       mistat->mtime = ~0;
-       mistat->length = ~0;
-       mistat->name = mistat->data;
-       mistat->uid = mistat->data;
-       mistat->gid = mistat->data;
-       mistat->muid = mistat->data;
-       if (v9ses->extended) {
-               mistat->n_uid = ~0;
-               mistat->n_gid = ~0;
-               mistat->n_muid = ~0;
-               mistat->extension = mistat->data;
-       }
-       *mistat->data = 0;
-}
-
-/**
- * v9fs_mistat2unix - convert mistat to unix stat
- * @mistat: Plan 9 metadata (mistat) structure
- * @buf: unix metadata (stat) structure to populate
- * @sb: superblock
- *
- */
-
-static void
-v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf,
-                struct super_block *sb)
-{
-       struct v9fs_session_info *v9ses = sb ? sb->s_fs_info : NULL;
-
-       buf->st_nlink = 1;
-
-       buf->st_atime = mistat->atime;
-       buf->st_mtime = mistat->mtime;
-       buf->st_ctime = mistat->mtime;
-
-       buf->st_uid = (unsigned short)-1;
-       buf->st_gid = (unsigned short)-1;
-
-       if (v9ses && v9ses->extended) {
-               /* TODO: string to uid mapping via user-space daemon */
-               if (mistat->n_uid != -1)
-                       sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid);
-
-               if (mistat->n_gid != -1)
-                       sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid);
-       }
-
-       if (buf->st_uid == (unsigned short)-1)
-               buf->st_uid = v9ses->uid;
-       if (buf->st_gid == (unsigned short)-1)
-               buf->st_gid = v9ses->gid;
-
-       buf->st_mode = p9mode2unixmode(v9ses, mistat->mode);
-       if ((S_ISBLK(buf->st_mode)) || (S_ISCHR(buf->st_mode))) {
-               char type = 0;
-               int major = -1;
-               int minor = -1;
-               sscanf(mistat->extension, "%c %u %u", &type, &major, &minor);
-               switch (type) {
-               case 'c':
-                       buf->st_mode &= ~S_IFBLK;
-                       buf->st_mode |= S_IFCHR;
-                       break;
-               case 'b':
-                       break;
-               default:
-                       dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n",
-                               type, mistat->extension);
-               };
-               buf->st_rdev = MKDEV(major, minor);
-       } else
-               buf->st_rdev = 0;
-
-       buf->st_size = mistat->length;
-
-       buf->st_blksize = sb->s_blocksize;
-       buf->st_blocks =
-           (buf->st_size + buf->st_blksize - 1) >> sb->s_blocksize_bits;
+       wstat->type = ~0;
+       wstat->dev = ~0;
+       wstat->qid.type = ~0;
+       wstat->qid.version = ~0;
+       *((long long *)&wstat->qid.path) = ~0;
+       wstat->mode = ~0;
+       wstat->atime = ~0;
+       wstat->mtime = ~0;
+       wstat->length = ~0;
+       wstat->name = NULL;
+       wstat->uid = NULL;
+       wstat->gid = NULL;
+       wstat->muid = NULL;
+       wstat->n_uid = ~0;
+       wstat->n_gid = ~0;
+       wstat->n_muid = ~0;
+       wstat->extension = NULL;
 }
 
 /**
@@ -312,12 +243,12 @@ v9fs_create(struct inode *dir,
        struct inode *file_inode = NULL;
        struct v9fs_fcall *fcall = NULL;
        struct v9fs_qid qid;
-       struct stat newstat;
        int dirfidnum = -1;
        long newfid = -1;
        int result = 0;
        unsigned int iounit = 0;
        int wfidno = -1;
+       int err;
 
        perm = unixmode2p9mode(v9ses, perm);
 
@@ -349,57 +280,64 @@ v9fs_create(struct inode *dir,
 
        result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall);
        if (result < 0) {
-               dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall));
+               PRINT_FCALL_ERROR("clone error", fcall);
                v9fs_put_idpool(newfid, &v9ses->fidpool);
                newfid = -1;
                goto CleanUpFid;
        }
 
        kfree(fcall);
+       fcall = NULL;
 
        result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name,
                               perm, open_mode, &fcall);
        if (result < 0) {
-               dprintk(DEBUG_ERROR, "create fails: %s(%d)\n",
-                       FCALL_ERROR(fcall), result);
-
+               PRINT_FCALL_ERROR("create fails", fcall);
                goto CleanUpFid;
        }
 
        iounit = fcall->params.rcreate.iounit;
        qid = fcall->params.rcreate.qid;
        kfree(fcall);
+       fcall = NULL;
 
-       fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1);
-       dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate);
-       if (!fid) {
-               result = -ENOMEM;
-               goto CleanUpFid;
-       }
+       if (!(perm&V9FS_DMDIR)) {
+               fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1);
+               dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate);
+               if (!fid) {
+                       result = -ENOMEM;
+                       goto CleanUpFid;
+               }
 
-       fid->qid = qid;
-       fid->iounit = iounit;
+               fid->qid = qid;
+               fid->iounit = iounit;
+       } else {
+               err = v9fs_t_clunk(v9ses, newfid);
+               newfid = -1;
+               if (err < 0)
+                       dprintk(DEBUG_ERROR, "clunk for mkdir failed: %d\n", err);
+       }
 
        /* walk to the newly created file and put the fid in the dentry */
        wfidno = v9fs_get_idpool(&v9ses->fidpool);
-       if (newfid < 0) {
+       if (wfidno < 0) {
                eprintk(KERN_WARNING, "no free fids available\n");
                return -ENOSPC;
        }
 
        result = v9fs_t_walk(v9ses, dirfidnum, wfidno,
-               (char *) file_dentry->d_name.name, NULL);
+               (char *) file_dentry->d_name.name, &fcall);
        if (result < 0) {
-               dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall));
+               PRINT_FCALL_ERROR("clone error", fcall);
                v9fs_put_idpool(wfidno, &v9ses->fidpool);
                wfidno = -1;
                goto CleanUpFid;
        }
+       kfree(fcall);
+       fcall = NULL;
 
        if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) {
-               if (!v9fs_t_clunk(v9ses, newfid, &fcall)) {
-                       v9fs_put_idpool(wfidno, &v9ses->fidpool);
-               }
+               v9fs_put_idpool(wfidno, &v9ses->fidpool);
 
                goto CleanUpFid;
        }
@@ -409,62 +347,43 @@ v9fs_create(struct inode *dir,
            (perm & V9FS_DMDEVICE))
                return 0;
 
-       result = v9fs_t_stat(v9ses, newfid, &fcall);
+       result = v9fs_t_stat(v9ses, wfidno, &fcall);
        if (result < 0) {
-               dprintk(DEBUG_ERROR, "stat error: %s(%d)\n", FCALL_ERROR(fcall),
-                       result);
+               PRINT_FCALL_ERROR("stat error", fcall);
                goto CleanUpFid;
        }
 
-       v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb);
 
-       file_inode = v9fs_get_inode(sb, newstat.st_mode);
+       file_inode = v9fs_get_inode(sb,
+               p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode));
+
        if ((!file_inode) || IS_ERR(file_inode)) {
                dprintk(DEBUG_ERROR, "create inode failed\n");
                result = -EBADF;
                goto CleanUpFid;
        }
 
-       v9fs_mistat2inode(fcall->params.rstat.stat, file_inode, sb);
+       v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb);
        kfree(fcall);
        fcall = NULL;
        file_dentry->d_op = &v9fs_dentry_operations;
        d_instantiate(file_dentry, file_inode);
 
-       if (perm & V9FS_DMDIR) {
-               if (!v9fs_t_clunk(v9ses, newfid, &fcall))
-                       v9fs_put_idpool(newfid, &v9ses->fidpool);
-               else
-                       dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n",
-                               FCALL_ERROR(fcall));
-               kfree(fcall);
-               fid->fidopen = 0;
-               fid->fidcreate = 0;
-               d_drop(file_dentry);
-       }
-
        return 0;
 
       CleanUpFid:
        kfree(fcall);
+       fcall = NULL;
 
        if (newfid >= 0) {
-               if (!v9fs_t_clunk(v9ses, newfid, &fcall))
-                       v9fs_put_idpool(newfid, &v9ses->fidpool);
-               else
-                       dprintk(DEBUG_ERROR, "clunk failed: %s\n",
-                               FCALL_ERROR(fcall));
-
-               kfree(fcall);
+               err = v9fs_t_clunk(v9ses, newfid);
+               if (err < 0)
+                       dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
        }
        if (wfidno >= 0) {
-               if (!v9fs_t_clunk(v9ses, wfidno, &fcall))
-                       v9fs_put_idpool(wfidno, &v9ses->fidpool);
-               else
-                       dprintk(DEBUG_ERROR, "clunk failed: %s\n",
-                               FCALL_ERROR(fcall));
-
-               kfree(fcall);
+               err = v9fs_t_clunk(v9ses, wfidno);
+               if (err < 0)
+                       dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
        }
        return result;
 }
@@ -509,10 +428,9 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
        }
 
        result = v9fs_t_remove(v9ses, fid, &fcall);
-       if (result < 0)
-               dprintk(DEBUG_ERROR, "remove of file fails: %s(%d)\n",
-                       FCALL_ERROR(fcall), result);
-       else {
+       if (result < 0) {
+               PRINT_FCALL_ERROR("remove fails", fcall);
+       } else {
                v9fs_put_idpool(fid, &v9ses->fidpool);
                v9fs_fid_destroy(v9fid);
        }
@@ -567,7 +485,6 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
        struct v9fs_fid *fid;
        struct inode *inode;
        struct v9fs_fcall *fcall = NULL;
-       struct stat newstat;
        int dirfidnum = -1;
        int newfid = -1;
        int result = 0;
@@ -620,8 +537,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
                goto FreeFcall;
        }
 
-       v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb);
-       inode = v9fs_get_inode(sb, newstat.st_mode);
+       inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses,
+               fcall->params.rstat.stat.mode));
 
        if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) {
                eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n",
@@ -631,7 +548,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
                goto FreeFcall;
        }
 
-       inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid);
+       inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid);
 
        fid = v9fs_fid_create(dentry, v9ses, newfid, 0);
        if (fid == NULL) {
@@ -640,10 +557,10 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
                goto FreeFcall;
        }
 
-       fid->qid = fcall->params.rstat.stat->qid;
+       fid->qid = fcall->params.rstat.stat.qid;
 
        dentry->d_op = &v9fs_dentry_operations;
-       v9fs_mistat2inode(fcall->params.rstat.stat, inode, inode->i_sb);
+       v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb);
 
        d_add(dentry, inode);
        kfree(fcall);
@@ -699,7 +616,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
            v9fs_fid_lookup(old_dentry->d_parent);
        struct v9fs_fid *newdirfid =
            v9fs_fid_lookup(new_dentry->d_parent);
-       struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
+       struct v9fs_wstat wstat;
        struct v9fs_fcall *fcall = NULL;
        int fid = -1;
        int olddirfidnum = -1;
@@ -708,9 +625,6 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        dprintk(DEBUG_VFS, "\n");
 
-       if (!mistat)
-               return -ENOMEM;
-
        if ((!oldfid) || (!olddirfid) || (!newdirfid)) {
                dprintk(DEBUG_ERROR, "problem with arguments\n");
                return -EBADF;
@@ -734,26 +648,15 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                goto FreeFcallnBail;
        }
 
-       v9fs_blank_mistat(v9ses, mistat);
+       v9fs_blank_wstat(&wstat);
+       wstat.muid = v9ses->name;
+       wstat.name = (char *) new_dentry->d_name.name;
 
-       strcpy(mistat->data + 1, v9ses->name);
-       mistat->name = mistat->data + 1 + strlen(v9ses->name);
-
-       if (new_dentry->d_name.len >
-           (v9ses->maxdata - strlen(v9ses->name) - sizeof(struct v9fs_stat))) {
-               dprintk(DEBUG_ERROR, "new name too long\n");
-               goto FreeFcallnBail;
-       }
-
-       strcpy(mistat->name, new_dentry->d_name.name);
-       retval = v9fs_t_wstat(v9ses, fid, mistat, &fcall);
+       retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall);
 
       FreeFcallnBail:
-       kfree(mistat);
-
        if (retval < 0)
-               dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
-                       FCALL_ERROR(fcall));
+               PRINT_FCALL_ERROR("wstat error", fcall);
 
        kfree(fcall);
        return retval;
@@ -788,7 +691,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        if (err < 0)
                dprintk(DEBUG_ERROR, "stat error\n");
        else {
-               v9fs_mistat2inode(fcall->params.rstat.stat, dentry->d_inode,
+               v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode,
                                  dentry->d_inode->i_sb);
                generic_fillattr(dentry->d_inode, stat);
        }
@@ -809,57 +712,44 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
        struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
        struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
        struct v9fs_fcall *fcall = NULL;
-       struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
+       struct v9fs_wstat wstat;
        int res = -EPERM;
 
        dprintk(DEBUG_VFS, "\n");
 
-       if (!mistat)
-               return -ENOMEM;
-
        if (!fid) {
                dprintk(DEBUG_ERROR,
                        "Couldn't find fid associated with dentry\n");
                return -EBADF;
        }
 
-       v9fs_blank_mistat(v9ses, mistat);
+       v9fs_blank_wstat(&wstat);
        if (iattr->ia_valid & ATTR_MODE)
-               mistat->mode = unixmode2p9mode(v9ses, iattr->ia_mode);
+               wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode);
 
        if (iattr->ia_valid & ATTR_MTIME)
-               mistat->mtime = iattr->ia_mtime.tv_sec;
+               wstat.mtime = iattr->ia_mtime.tv_sec;
 
        if (iattr->ia_valid & ATTR_ATIME)
-               mistat->atime = iattr->ia_atime.tv_sec;
+               wstat.atime = iattr->ia_atime.tv_sec;
 
        if (iattr->ia_valid & ATTR_SIZE)
-               mistat->length = iattr->ia_size;
+               wstat.length = iattr->ia_size;
 
        if (v9ses->extended) {
-               char *ptr = mistat->data+1;
-
-               if (iattr->ia_valid & ATTR_UID) {
-                       mistat->uid = ptr;
-                       ptr += 1+sprintf(ptr, "%08x", iattr->ia_uid);
-                       mistat->n_uid = iattr->ia_uid;
-               }
+               if (iattr->ia_valid & ATTR_UID)
+                       wstat.n_uid = iattr->ia_uid;
 
-               if (iattr->ia_valid & ATTR_GID) {
-                       mistat->gid = ptr;
-                       ptr += 1+sprintf(ptr, "%08x", iattr->ia_gid);
-                       mistat->n_gid = iattr->ia_gid;
-               }
+               if (iattr->ia_valid & ATTR_GID)
+                       wstat.n_gid = iattr->ia_gid;
        }
 
-       res = v9fs_t_wstat(v9ses, fid->fid, mistat, &fcall);
+       res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
 
        if (res < 0)
-               dprintk(DEBUG_ERROR, "wstat error: %s\n", FCALL_ERROR(fcall));
+               PRINT_FCALL_ERROR("wstat error", fcall);
 
-       kfree(mistat);
        kfree(fcall);
-
        if (res >= 0)
                res = inode_setattr(dentry->d_inode, iattr);
 
@@ -867,51 +757,47 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
 }
 
 /**
- * v9fs_mistat2inode - populate an inode structure with mistat info
- * @mistat: Plan 9 metadata (mistat) structure
+ * v9fs_stat2inode - populate an inode structure with mistat info
+ * @stat: Plan 9 metadata (mistat) structure
  * @inode: inode to populate
  * @sb: superblock of filesystem
  *
  */
 
 void
-v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode,
-                 struct super_block *sb)
+v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
+       struct super_block *sb)
 {
+       int n;
+       char ext[32];
        struct v9fs_session_info *v9ses = sb->s_fs_info;
 
        inode->i_nlink = 1;
 
-       inode->i_atime.tv_sec = mistat->atime;
-       inode->i_mtime.tv_sec = mistat->mtime;
-       inode->i_ctime.tv_sec = mistat->mtime;
+       inode->i_atime.tv_sec = stat->atime;
+       inode->i_mtime.tv_sec = stat->mtime;
+       inode->i_ctime.tv_sec = stat->mtime;
 
-       inode->i_uid = -1;
-       inode->i_gid = -1;
+       inode->i_uid = v9ses->uid;
+       inode->i_gid = v9ses->gid;
 
        if (v9ses->extended) {
-               /* TODO: string to uid mapping via user-space daemon */
-               inode->i_uid = mistat->n_uid;
-               inode->i_gid = mistat->n_gid;
-
-               if (mistat->n_uid == -1)
-                       sscanf(mistat->uid, "%x", &inode->i_uid);
-
-               if (mistat->n_gid == -1)
-                       sscanf(mistat->gid, "%x", &inode->i_gid);
+               inode->i_uid = stat->n_uid;
+               inode->i_gid = stat->n_gid;
        }
 
-       if (inode->i_uid == -1)
-               inode->i_uid = v9ses->uid;
-       if (inode->i_gid == -1)
-               inode->i_gid = v9ses->gid;
-
-       inode->i_mode = p9mode2unixmode(v9ses, mistat->mode);
+       inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
        if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
                char type = 0;
                int major = -1;
                int minor = -1;
-               sscanf(mistat->extension, "%c %u %u", &type, &major, &minor);
+
+               n = stat->extension.len;
+               if (n > sizeof(ext)-1)
+                       n = sizeof(ext)-1;
+               memmove(ext, stat->extension.str, n);
+               ext[n] = 0;
+               sscanf(ext, "%c %u %u", &type, &major, &minor);
                switch (type) {
                case 'c':
                        inode->i_mode &= ~S_IFBLK;
@@ -920,14 +806,14 @@ v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode,
                case 'b':
                        break;
                default:
-                       dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n",
-                               type, mistat->extension);
+                       dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n",
+                               type, stat->extension.len, stat->extension.str);
                };
                inode->i_rdev = MKDEV(major, minor);
        } else
                inode->i_rdev = 0;
 
-       inode->i_size = mistat->length;
+       inode->i_size = stat->length;
 
        inode->i_blksize = sb->s_blocksize;
        inode->i_blocks =
@@ -954,71 +840,6 @@ ino_t v9fs_qid2ino(struct v9fs_qid *qid)
        return i;
 }
 
-/**
- * v9fs_vfs_symlink - helper function to create symlinks
- * @dir: directory inode containing symlink
- * @dentry: dentry for symlink
- * @symname: symlink data
- *
- * See 9P2000.u RFC for more information
- *
- */
-
-static int
-v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
-{
-       int retval = -EPERM;
-       struct v9fs_fid *newfid;
-       struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
-       struct v9fs_fcall *fcall = NULL;
-       struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
-
-       dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
-               symname);
-
-       if (!mistat)
-               return -ENOMEM;
-
-       if (!v9ses->extended) {
-               dprintk(DEBUG_ERROR, "not extended\n");
-               goto FreeFcall;
-       }
-
-       /* issue a create */
-       retval = v9fs_create(dir, dentry, S_IFLNK, 0);
-       if (retval != 0)
-               goto FreeFcall;
-
-       newfid = v9fs_fid_lookup(dentry);
-
-       /* issue a twstat */
-       v9fs_blank_mistat(v9ses, mistat);
-       strcpy(mistat->data + 1, symname);
-       mistat->extension = mistat->data + 1;
-       retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
-       if (retval < 0) {
-               dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
-                       FCALL_ERROR(fcall));
-               goto FreeFcall;
-       }
-
-       kfree(fcall);
-
-       if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) {
-               dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n",
-                       FCALL_ERROR(fcall));
-               goto FreeFcall;
-       }
-
-       d_drop(dentry);         /* FID - will this also clunk? */
-
-      FreeFcall:
-       kfree(mistat);
-       kfree(fcall);
-
-       return retval;
-}
-
 /**
  * v9fs_readlink - read a symlink's location (internal version)
  * @dentry: dentry for symlink
@@ -1058,16 +879,17 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        if (!fcall)
                return -EIO;
 
-       if (!(fcall->params.rstat.stat->mode & V9FS_DMSYMLINK)) {
+       if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) {
                retval = -EINVAL;
                goto FreeFcall;
        }
 
        /* copy extension buffer into buffer */
-       if (strlen(fcall->params.rstat.stat->extension) < buflen)
-               buflen = strlen(fcall->params.rstat.stat->extension);
+       if (fcall->params.rstat.stat.extension.len < buflen)
+               buflen = fcall->params.rstat.stat.extension.len;
 
-       memcpy(buffer, fcall->params.rstat.stat->extension, buflen + 1);
+       memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
+       buffer[buflen-1] = 0;
 
        retval = buflen;
 
@@ -1157,6 +979,77 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
                __putname(s);
 }
 
+static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
+       int mode, const char *extension)
+{
+       int err, retval;
+       struct v9fs_session_info *v9ses;
+       struct v9fs_fcall *fcall;
+       struct v9fs_fid *fid;
+       struct v9fs_wstat wstat;
+
+       v9ses = v9fs_inode2v9ses(dir);
+       retval = -EPERM;
+       fcall = NULL;
+
+       if (!v9ses->extended) {
+               dprintk(DEBUG_ERROR, "not extended\n");
+               goto free_mem;
+       }
+
+       /* issue a create */
+       retval = v9fs_create(dir, dentry, mode, 0);
+       if (retval != 0)
+               goto free_mem;
+
+       fid = v9fs_fid_get_created(dentry);
+       if (!fid) {
+               dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n");
+               goto free_mem;
+       }
+
+       /* issue a Twstat */
+       v9fs_blank_wstat(&wstat);
+       wstat.muid = v9ses->name;
+       wstat.extension = (char *) extension;
+       retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
+       if (retval < 0) {
+               PRINT_FCALL_ERROR("wstat error", fcall);
+               goto free_mem;
+       }
+
+       err = v9fs_t_clunk(v9ses, fid->fid);
+       if (err < 0) {
+               dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
+               goto free_mem;
+       }
+
+       d_drop(dentry);         /* FID - will this also clunk? */
+
+free_mem:
+       kfree(fcall);
+       return retval;
+}
+
+/**
+ * v9fs_vfs_symlink - helper function to create symlinks
+ * @dir: directory inode containing symlink
+ * @dentry: dentry for symlink
+ * @symname: symlink data
+ *
+ * See 9P2000.u RFC for more information
+ *
+ */
+
+static int
+v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+{
+       dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
+               symname);
+
+       return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);
+}
+
 /**
  * v9fs_vfs_link - create a hardlink
  * @old_dentry: dentry for file to link to
@@ -1173,64 +1066,24 @@ static int
 v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
              struct dentry *dentry)
 {
-       int retval = -EPERM;
-       struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
-       struct v9fs_fcall *fcall = NULL;
-       struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
-       struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry);
-       struct v9fs_fid *newfid = NULL;
-       char *symname = __getname();
+       int retval;
+       struct v9fs_fid *oldfid;
+       char *name;
 
        dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
                old_dentry->d_name.name);
 
-       if (!v9ses->extended) {
-               dprintk(DEBUG_ERROR, "not extended\n");
-               goto FreeMem;
-       }
-
-       /* get fid of old_dentry */
-       sprintf(symname, "hardlink(%d)\n", oldfid->fid);
-
-       /* issue a create */
-       retval = v9fs_create(dir, dentry, V9FS_DMLINK, 0);
-       if (retval != 0)
-               goto FreeMem;
-
-       newfid = v9fs_fid_lookup(dentry);
-       if (!newfid) {
-               dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n");
-               goto FreeMem;
-       }
-
-       /* issue a twstat */
-       v9fs_blank_mistat(v9ses, mistat);
-       strcpy(mistat->data + 1, symname);
-       mistat->extension = mistat->data + 1;
-       retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
-       if (retval < 0) {
-               dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
-                       FCALL_ERROR(fcall));
-               goto FreeMem;
-       }
-
-       kfree(fcall);
-
-       if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) {
-               dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n",
-                       FCALL_ERROR(fcall));
-               goto FreeMem;
+       oldfid = v9fs_fid_lookup(old_dentry);
+       if (!oldfid) {
+               dprintk(DEBUG_ERROR, "can't find oldfid\n");
+               return -EPERM;
        }
 
-       d_drop(dentry);         /* FID - will this also clunk? */
-
-       kfree(fcall);
-       fcall = NULL;
+       name = __getname();
+       sprintf(name, "hardlink(%d)\n", oldfid->fid);
+       retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
+       __putname(name);
 
-      FreeMem:
-       kfree(mistat);
-       kfree(fcall);
-       __putname(symname);
        return retval;
 }
 
@@ -1246,82 +1099,30 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
 static int
 v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
 {
-       int retval = -EPERM;
-       struct v9fs_fid *newfid;
-       struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
-       struct v9fs_fcall *fcall = NULL;
-       struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
-       char *symname = __getname();
+       int retval;
+       char *name;
 
        dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
                dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
 
-       if (!mistat)
-               return -ENOMEM;
-
-       if (!new_valid_dev(rdev)) {
-               retval = -EINVAL;
-               goto FreeMem;
-       }
-
-       if (!v9ses->extended) {
-               dprintk(DEBUG_ERROR, "not extended\n");
-               goto FreeMem;
-       }
-
-       /* issue a create */
-       retval = v9fs_create(dir, dentry, mode, 0);
-
-       if (retval != 0)
-               goto FreeMem;
-
-       newfid = v9fs_fid_lookup(dentry);
-       if (!newfid) {
-               dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n");
-               retval = -EINVAL;
-               goto FreeMem;
-       }
+       if (!new_valid_dev(rdev))
+               return -EINVAL;
 
+       name = __getname();
        /* build extension */
        if (S_ISBLK(mode))
-               sprintf(symname, "b %u %u", MAJOR(rdev), MINOR(rdev));
+               sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
        else if (S_ISCHR(mode))
-               sprintf(symname, "c %u %u", MAJOR(rdev), MINOR(rdev));
+               sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
        else if (S_ISFIFO(mode))
-               ;       /* DO NOTHING */
+               *name = 0;
        else {
-               retval = -EINVAL;
-               goto FreeMem;
-       }
-
-       if (!S_ISFIFO(mode)) {
-               /* issue a twstat */
-               v9fs_blank_mistat(v9ses, mistat);
-               strcpy(mistat->data + 1, symname);
-               mistat->extension = mistat->data + 1;
-               retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
-               if (retval < 0) {
-                       dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
-                               FCALL_ERROR(fcall));
-                       goto FreeMem;
-               }
+               __putname(name);
+               return -EINVAL;
        }
 
-       /* need to update dcache so we show up */
-       kfree(fcall);
-
-       if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) {
-               dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n",
-                       FCALL_ERROR(fcall));
-               goto FreeMem;
-       }
-
-       d_drop(dentry);         /* FID - will this also clunk? */
-
-      FreeMem:
-       kfree(mistat);
-       kfree(fcall);
-       __putname(symname);
+       retval = v9fs_vfs_mkspecial(dir, dentry, mode, name);
+       __putname(name);
 
        return retval;
 }
index 82c5b00840796d5f82bd6810a92f783b11e953d1..ae0f06b3c11a041659d6fea8db12e0cf0732114e 100644 (file)
@@ -44,7 +44,6 @@
 #include "v9fs.h"
 #include "9p.h"
 #include "v9fs_vfs.h"
-#include "conv.h"
 #include "fid.h"
 
 static void v9fs_clear_inode(struct inode *);
@@ -123,12 +122,13 @@ static struct super_block *v9fs_get_sb(struct file_system_type
 
        dprintk(DEBUG_VFS, " \n");
 
-       v9ses = kcalloc(1, sizeof(struct v9fs_session_info), GFP_KERNEL);
+       v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
        if (!v9ses)
                return ERR_PTR(-ENOMEM);
 
        if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
                dprintk(DEBUG_ERROR, "problem initiating session\n");
+               kfree(v9ses);
                return ERR_PTR(newfid);
        }
 
@@ -157,7 +157,7 @@ static struct super_block *v9fs_get_sb(struct file_system_type
        stat_result = v9fs_t_stat(v9ses, newfid, &fcall);
        if (stat_result < 0) {
                dprintk(DEBUG_ERROR, "stat error\n");
-               v9fs_t_clunk(v9ses, newfid, NULL);
+               v9fs_t_clunk(v9ses, newfid);
                v9fs_put_idpool(newfid, &v9ses->fidpool);
        } else {
                /* Setup the Root Inode */
@@ -167,10 +167,10 @@ static struct super_block *v9fs_get_sb(struct file_system_type
                        goto put_back_sb;
                }
 
-               root_fid->qid = fcall->params.rstat.stat->qid;
+               root_fid->qid = fcall->params.rstat.stat.qid;
                root->d_inode->i_ino =
-                   v9fs_qid2ino(&fcall->params.rstat.stat->qid);
-               v9fs_mistat2inode(fcall->params.rstat.stat, root->d_inode, sb);
+                   v9fs_qid2ino(&fcall->params.rstat.stat.qid);
+               v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb);
        }
 
        kfree(fcall);
index 175b2e8177c13690719ea26e61e6851183430e15..f3d3d81eb7e985170b853558b66b441d469af8bf 100644 (file)
@@ -1,6 +1,6 @@
 config BINFMT_ELF
        bool "Kernel support for ELF binaries"
-       depends on MMU
+       depends on MMU && (BROKEN || !FRV)
        default y
        ---help---
          ELF (Executable and Linkable Format) is a format for libraries and
index 73676111ebbe763b2f23b51ff27131589cff6ae3..35e9aec608e4945565a5f20bc829006da5a9d72d 100644 (file)
@@ -10,7 +10,7 @@ obj-y :=      open.o read_write.o file_table.o buffer.o  bio.o super.o \
                ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
                attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
                seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
-               ioprio.o pnode.o
+               ioprio.o pnode.o drop_caches.o
 
 obj-$(CONFIG_INOTIFY)          += inotify.o
 obj-$(CONFIG_EPOLL)            += eventpoll.o
index 6682d6d7f2940800bff6fe51e84bfe67cc5c3619..5c61c24dab2a12dac4b55ae70ef87191cc53defd 100644 (file)
@@ -137,7 +137,7 @@ static inline void afs_dir_check_page(struct inode *dir, struct page *page)
 #endif
 
        /* determine how many magic numbers there should be in this page */
-       latter = dir->i_size - (page->index << PAGE_CACHE_SHIFT);
+       latter = dir->i_size - page_offset(page);
        if (latter >= PAGE_SIZE)
                qty = PAGE_SIZE;
        else
index 1e691889c4c96911bc036f7b7539184b4ccc10fb..bfdcf19ba3f387080523c6e78027197058808c58 100644 (file)
@@ -18,8 +18,6 @@
 #include "kafsasyncd.h"
 #include "cache.h"
 
-#define __packed __attribute__((packed))
-
 typedef enum {
        AFS_VLUPD_SLEEP,                /* sleeping waiting for update timer to fire */
        AFS_VLUPD_PENDING,              /* on pending queue */
@@ -115,7 +113,7 @@ struct afs_volume
        struct cachefs_cookie   *cache;         /* caching cookie */
 #endif
        afs_volid_t             vid;            /* volume ID */
-       afs_voltype_t __packed  type;           /* type of volume */
+       afs_voltype_t           type;           /* type of volume */
        char                    type_force;     /* force volume type (suppress R/O -> R/W) */
        unsigned short          nservers;       /* number of server slots filled */
        unsigned short          rjservers;      /* number of servers discarded due to -ENOMEDIUM */
index 5a28b69ad223b243121c8eb65495f9a519891d33..aec2b1916d1b27e4bc9411212359801b8ba70386 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -29,7 +29,6 @@
 #include <linux/highmem.h>
 #include <linux/workqueue.h>
 #include <linux/security.h>
-#include <linux/rcuref.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
@@ -514,7 +513,7 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
        /* Must be done under the lock to serialise against cancellation.
         * Call this aio_fput as it duplicates fput via the fput_work.
         */
-       if (unlikely(rcuref_dec_and_test(&req->ki_filp->f_count))) {
+       if (unlikely(atomic_dec_and_test(&req->ki_filp->f_count))) {
                get_ioctx(ctx);
                spin_lock(&fput_lock);
                list_add(&req->ki_list, &fput_head);
index 67bcd9b14ea58046efa53cef41db47d96f36f9b2..b34732506f1dcf3602ac721c5c4336f6e59697a1 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -67,20 +67,12 @@ EXPORT_SYMBOL(inode_change_ok);
 int inode_setattr(struct inode * inode, struct iattr * attr)
 {
        unsigned int ia_valid = attr->ia_valid;
-       int error = 0;
-
-       if (ia_valid & ATTR_SIZE) {
-               if (attr->ia_size != i_size_read(inode)) {
-                       error = vmtruncate(inode, attr->ia_size);
-                       if (error || (ia_valid == ATTR_SIZE))
-                               goto out;
-               } else {
-                       /*
-                        * We skipped the truncate but must still update
-                        * timestamps
-                        */
-                       ia_valid |= ATTR_MTIME|ATTR_CTIME;
-               }
+
+       if (ia_valid & ATTR_SIZE &&
+           attr->ia_size != i_size_read(inode)) {
+               int error = vmtruncate(inode, attr->ia_size);
+               if (error)
+                       return error;
        }
 
        if (ia_valid & ATTR_UID)
@@ -104,8 +96,8 @@ int inode_setattr(struct inode * inode, struct iattr * attr)
                inode->i_mode = mode;
        }
        mark_inode_dirty(inode);
-out:
-       return error;
+
+       return 0;
 }
 EXPORT_SYMBOL(inode_setattr);
 
index fca83e28edcf678cb8de5bb6838c7ec654c2455f..385bed09b0d84005674acc1bba64ad816ced5e6c 100644 (file)
@@ -209,7 +209,7 @@ static inline int simple_empty_nolock(struct dentry *dentry)
        struct dentry *child;
        int ret = 0;
 
-       list_for_each_entry(child, &dentry->d_subdirs, d_child)
+       list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child)
                if (simple_positive(child))
                        goto out;
        ret = 1;
index feb6ac427d058b8a1c02b420bbe6ad81ffd581aa..dc39589df165a049a465208949f9d22c760ce0c2 100644 (file)
@@ -105,7 +105,7 @@ repeat:
        next = this_parent->d_subdirs.next;
 resume:
        while (next != &this_parent->d_subdirs) {
-               struct dentry *dentry = list_entry(next, struct dentry, d_child);
+               struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
 
                /* Negative dentry - give up */
                if (!simple_positive(dentry)) {
@@ -138,7 +138,7 @@ resume:
        }
 
        if (this_parent != top) {
-               next = this_parent->d_child.next;
+               next = this_parent->d_u.d_child.next;
                this_parent = this_parent->d_parent;
                goto resume;
        }
@@ -163,7 +163,7 @@ repeat:
        next = this_parent->d_subdirs.next;
 resume:
        while (next != &this_parent->d_subdirs) {
-               struct dentry *dentry = list_entry(next, struct dentry, d_child);
+               struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
 
                /* Negative dentry - give up */
                if (!simple_positive(dentry)) {
@@ -199,7 +199,7 @@ cont:
        }
 
        if (this_parent != parent) {
-               next = this_parent->d_child.next;
+               next = this_parent->d_u.d_child.next;
                this_parent = this_parent->d_parent;
                goto resume;
        }
@@ -238,7 +238,7 @@ static struct dentry *autofs4_expire(struct super_block *sb,
        /* On exit from the loop expire is set to a dgot dentry
         * to expire or it's NULL */
        while ( next != &root->d_subdirs ) {
-               struct dentry *dentry = list_entry(next, struct dentry, d_child);
+               struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
 
                /* Negative dentry - give up */
                if ( !simple_positive(dentry) ) {
@@ -302,7 +302,7 @@ next:
                        expired, (int)expired->d_name.len, expired->d_name.name);
                spin_lock(&dcache_lock);
                list_del(&expired->d_parent->d_subdirs);
-               list_add(&expired->d_parent->d_subdirs, &expired->d_child);
+               list_add(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
                spin_unlock(&dcache_lock);
                return expired;
        }
index 818b37be5153f3d7508ac00c215c2f523f01999f..2d3082854a292dec3fc1ad749b81b9c700a4addb 100644 (file)
@@ -91,7 +91,7 @@ repeat:
        next = this_parent->d_subdirs.next;
 resume:
        while (next != &this_parent->d_subdirs) {
-               struct dentry *dentry = list_entry(next, struct dentry, d_child);
+               struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
 
                /* Negative dentry - don`t care */
                if (!simple_positive(dentry)) {
@@ -117,7 +117,7 @@ resume:
        if (this_parent != sbi->root) {
                struct dentry *dentry = this_parent;
 
-               next = this_parent->d_child.next;
+               next = this_parent->d_u.d_child.next;
                this_parent = this_parent->d_parent;
                spin_unlock(&dcache_lock);
                DPRINTK("parent dentry %p %.*s",
index 2a771ec66956f92615de35694dc512f0144aedba..2241405ffc413a49035cad0085be9c481c325165 100644 (file)
@@ -143,7 +143,8 @@ static int autofs4_dcache_readdir(struct file * filp, void * dirent, filldir_t f
                        }
 
                        while(1) {
-                               struct dentry *de = list_entry(list, struct dentry, d_child);
+                               struct dentry *de = list_entry(list,
+                                               struct dentry, d_u.d_child);
 
                                if (!d_unhashed(de) && de->d_inode) {
                                        spin_unlock(&dcache_lock);
index f36f2210204f524b2922fa69ea704295bfbe5a59..80ca932ba0bddaaf2d5a520d5fe408c14af508db 100644 (file)
@@ -58,7 +58,7 @@ extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
  * If we don't support core dumping, then supply a NULL so we
  * don't even try.
  */
-#ifdef USE_ELF_CORE_DUMP
+#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
 static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file);
 #else
 #define elf_core_dump  NULL
@@ -288,11 +288,17 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
                        struct elf_phdr *eppnt, int prot, int type)
 {
        unsigned long map_addr;
+       unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr);
 
        down_write(&current->mm->mmap_sem);
-       map_addr = do_mmap(filep, ELF_PAGESTART(addr),
-                          eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
-                          eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+       /* mmap() will return -EINVAL if given a zero size, but a
+        * segment with zero filesize is perfectly valid */
+       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);
 }
@@ -1107,7 +1113,7 @@ out:
  * Note that some platforms still use traditional core dumps and not
  * the ELF core dump.  Each platform can select it as appropriate.
  */
-#ifdef USE_ELF_CORE_DUMP
+#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
 
 /*
  * ELF core dumper
index dfe242a21eb4cb49d00d4ee54def5c024be1ea0b..7b30695899511ca64404f8061a9d1563573db44c 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -126,6 +126,7 @@ static void bio_fs_destructor(struct bio *bio)
 inline void bio_init(struct bio *bio)
 {
        bio->bi_next = NULL;
+       bio->bi_bdev = NULL;
        bio->bi_flags = 1 << BIO_UPTODATE;
        bio->bi_rw = 0;
        bio->bi_vcnt = 0;
index 5287be18633bc7c2b6621fc20c2f5ce97fa8e561..55f0975a9b15dc61ac3815ec316a5fa4f8adf1a8 100644 (file)
@@ -153,14 +153,8 @@ int sync_blockdev(struct block_device *bdev)
 {
        int ret = 0;
 
-       if (bdev) {
-               int err;
-
-               ret = filemap_fdatawrite(bdev->bd_inode->i_mapping);
-               err = filemap_fdatawait(bdev->bd_inode->i_mapping);
-               if (!ret)
-                       ret = err;
-       }
+       if (bdev)
+               ret = filemap_write_and_wait(bdev->bd_inode->i_mapping);
        return ret;
 }
 EXPORT_SYMBOL(sync_blockdev);
@@ -1768,7 +1762,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
         * handle that here by just cleaning them.
         */
 
-       block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       block = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
        head = page_buffers(page);
        bh = head;
 
@@ -2160,11 +2154,12 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
  * truncates.  Uses prepare/commit_write to allow the filesystem to
  * deal with the hole.  
  */
-int generic_cont_expand(struct inode *inode, loff_t size)
+static int __generic_cont_expand(struct inode *inode, loff_t size,
+                                pgoff_t index, unsigned int offset)
 {
        struct address_space *mapping = inode->i_mapping;
        struct page *page;
-       unsigned long index, offset, limit;
+       unsigned long limit;
        int err;
 
        err = -EFBIG;
@@ -2176,24 +2171,24 @@ int generic_cont_expand(struct inode *inode, loff_t size)
        if (size > inode->i_sb->s_maxbytes)
                goto out;
 
-       offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */
-
-       /* ugh.  in prepare/commit_write, if from==to==start of block, we 
-       ** skip the prepare.  make sure we never send an offset for the start
-       ** of a block
-       */
-       if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) {
-               offset++;
-       }
-       index = size >> PAGE_CACHE_SHIFT;
        err = -ENOMEM;
        page = grab_cache_page(mapping, index);
        if (!page)
                goto out;
        err = mapping->a_ops->prepare_write(NULL, page, offset, offset);
-       if (!err) {
-               err = mapping->a_ops->commit_write(NULL, page, offset, offset);
+       if (err) {
+               /*
+                * ->prepare_write() may have instantiated a few blocks
+                * outside i_size.  Trim these off again.
+                */
+               unlock_page(page);
+               page_cache_release(page);
+               vmtruncate(inode, inode->i_size);
+               goto out;
        }
+
+       err = mapping->a_ops->commit_write(NULL, page, offset, offset);
+
        unlock_page(page);
        page_cache_release(page);
        if (err > 0)
@@ -2202,6 +2197,36 @@ out:
        return err;
 }
 
+int generic_cont_expand(struct inode *inode, loff_t size)
+{
+       pgoff_t index;
+       unsigned int offset;
+
+       offset = (size & (PAGE_CACHE_SIZE - 1)); /* Within page */
+
+       /* ugh.  in prepare/commit_write, if from==to==start of block, we
+       ** skip the prepare.  make sure we never send an offset for the start
+       ** of a block
+       */
+       if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) {
+               /* caller must handle this extra byte. */
+               offset++;
+       }
+       index = size >> PAGE_CACHE_SHIFT;
+
+       return __generic_cont_expand(inode, size, index, offset);
+}
+
+int generic_cont_expand_simple(struct inode *inode, loff_t size)
+{
+       loff_t pos = size - 1;
+       pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+       unsigned int offset = (pos & (PAGE_CACHE_SIZE - 1)) + 1;
+
+       /* prepare/commit_write can handle even if from==to==start of block. */
+       return __generic_cont_expand(inode, size, index, offset);
+}
+
 /*
  * For moronic filesystems that do not allow holes in file.
  * We may have to extend the file.
@@ -2610,7 +2635,7 @@ int block_truncate_page(struct address_space *mapping,
        pgoff_t index = from >> PAGE_CACHE_SHIFT;
        unsigned offset = from & (PAGE_CACHE_SIZE-1);
        unsigned blocksize;
-       pgoff_t iblock;
+       sector_t iblock;
        unsigned length, pos;
        struct inode *inode = mapping->host;
        struct page *page;
@@ -2626,7 +2651,7 @@ int block_truncate_page(struct address_space *mapping,
                return 0;
 
        length = blocksize - length;
-       iblock = index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       iblock = (sector_t)index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
        
        page = grab_cache_page(mapping, index);
        err = -ENOMEM;
@@ -3145,6 +3170,7 @@ EXPORT_SYMBOL(fsync_bdev);
 EXPORT_SYMBOL(generic_block_bmap);
 EXPORT_SYMBOL(generic_commit_write);
 EXPORT_SYMBOL(generic_cont_expand);
+EXPORT_SYMBOL(generic_cont_expand_simple);
 EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL(invalidate_bdev);
 EXPORT_SYMBOL(ll_rw_block);
index 14a1c72ced92e1cc98024494ea217b2a7413921d..5ade53d7bca89624cd6b9381d4e6ba91543517be 100644 (file)
@@ -127,8 +127,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
                if (file->f_dentry->d_inode->i_mapping) {
                /* BB no need to lock inode until after invalidate
                   since namei code should already have it locked? */
-                       filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
-                       filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
+                       filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
                }
                cFYI(1, ("invalidating remote inode since open detected it "
                         "changed"));
@@ -419,8 +418,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
                pCifsInode = CIFS_I(inode);
                if (pCifsInode) {
                        if (can_flush) {
-                               filemap_fdatawrite(inode->i_mapping);
-                               filemap_fdatawait(inode->i_mapping);
+                               filemap_write_and_wait(inode->i_mapping);
                        /* temporarily disable caching while we
                           go to server to get inode info */
                                pCifsInode->clientCanCacheAll = FALSE;
index 411c1f7f84da6074efd483e27df1221db4647df1..9558f51bca55a1bd1c12a0140075013ea02628b5 100644 (file)
@@ -1148,8 +1148,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
        /* BB check if we need to refresh inode from server now ? BB */
 
        /* need to flush data before changing file size on server */
-       filemap_fdatawrite(direntry->d_inode->i_mapping);
-       filemap_fdatawait(direntry->d_inode->i_mapping);
+       filemap_write_and_wait(direntry->d_inode->i_mapping);
 
        if (attrs->ia_valid & ATTR_SIZE) {
                /* To avoid spurious oplock breaks from server, in the case of
index 80072fd9b7faf6a6c21747d65ffc6bb2c65e8cbd..c607d923350a4ee1bb46259ddd39d9761301bb72 100644 (file)
@@ -93,7 +93,7 @@ static void coda_flag_children(struct dentry *parent, int flag)
        spin_lock(&dcache_lock);
        list_for_each(child, &parent->d_subdirs)
        {
-               de = list_entry(child, struct dentry, d_child);
+               de = list_entry(child, struct dentry, d_u.d_child);
                /* don't know what to do with negative dentries */
                if ( ! de->d_inode ) 
                        continue;
index 55ac0324aaf1649f1326994f31267ad90e542063..271b75d1597f507bacbd78b7be31227d5492dd2e 100644 (file)
@@ -494,9 +494,21 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
                ret = sys_fcntl(fd, cmd, (unsigned long)&f);
                set_fs(old_fs);
                if (cmd == F_GETLK && ret == 0) {
-                       if ((f.l_start >= COMPAT_OFF_T_MAX) ||
-                           ((f.l_start + f.l_len) > COMPAT_OFF_T_MAX))
+                       /* GETLK was successfule and we need to return the data...
+                        * but it needs to fit in the compat structure.
+                        * l_start shouldn't be too big, unless the original
+                        * start + end is greater than COMPAT_OFF_T_MAX, in which
+                        * case the app was asking for trouble, so we return
+                        * -EOVERFLOW in that case.
+                        * l_len could be too big, in which case we just truncate it,
+                        * and only allow the app to see that part of the conflicting
+                        * lock that might make sense to it anyway
+                        */
+
+                       if (f.l_start > COMPAT_OFF_T_MAX)
                                ret = -EOVERFLOW;
+                       if (f.l_len > COMPAT_OFF_T_MAX)
+                               f.l_len = COMPAT_OFF_T_MAX;
                        if (ret == 0)
                                ret = put_compat_flock(&f, compat_ptr(arg));
                }
@@ -515,9 +527,11 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
                                (unsigned long)&f);
                set_fs(old_fs);
                if (cmd == F_GETLK64 && ret == 0) {
-                       if ((f.l_start >= COMPAT_LOFF_T_MAX) ||
-                           ((f.l_start + f.l_len) > COMPAT_LOFF_T_MAX))
+                       /* need to return lock information - see above for commentary */
+                       if (f.l_start > COMPAT_LOFF_T_MAX)
                                ret = -EOVERFLOW;
+                       if (f.l_len > COMPAT_LOFF_T_MAX)
+                               f.l_len = COMPAT_LOFF_T_MAX;
                        if (ret == 0)
                                ret = put_compat_flock64(&f, compat_ptr(arg));
                }
index 43a2508ac69670d972516a0f5d2ad96f8e7bfa02..55d9a3a954cfe7fc35a5ccdc4eb7b6f1afbcff72 100644 (file)
@@ -207,244 +207,6 @@ static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
 }
 
-struct video_tuner32 {
-       compat_int_t tuner;
-       char name[32];
-       compat_ulong_t rangelow, rangehigh;
-       u32 flags;      /* It is really u32 in videodev.h */
-       u16 mode, signal;
-};
-
-static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
-       int i;
-
-       if(get_user(kp->tuner, &up->tuner))
-               return -EFAULT;
-       for(i = 0; i < 32; i++)
-               __get_user(kp->name[i], &up->name[i]);
-       __get_user(kp->rangelow, &up->rangelow);
-       __get_user(kp->rangehigh, &up->rangehigh);
-       __get_user(kp->flags, &up->flags);
-       __get_user(kp->mode, &up->mode);
-       __get_user(kp->signal, &up->signal);
-       return 0;
-}
-
-static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
-       int i;
-
-       if(put_user(kp->tuner, &up->tuner))
-               return -EFAULT;
-       for(i = 0; i < 32; i++)
-               __put_user(kp->name[i], &up->name[i]);
-       __put_user(kp->rangelow, &up->rangelow);
-       __put_user(kp->rangehigh, &up->rangehigh);
-       __put_user(kp->flags, &up->flags);
-       __put_user(kp->mode, &up->mode);
-       __put_user(kp->signal, &up->signal);
-       return 0;
-}
-
-struct video_buffer32 {
-       compat_caddr_t base;
-       compat_int_t height, width, depth, bytesperline;
-};
-
-static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
-       u32 tmp;
-
-       if (get_user(tmp, &up->base))
-               return -EFAULT;
-
-       /* This is actually a physical address stored
-        * as a void pointer.
-        */
-       kp->base = (void *)(unsigned long) tmp;
-
-       __get_user(kp->height, &up->height);
-       __get_user(kp->width, &up->width);
-       __get_user(kp->depth, &up->depth);
-       __get_user(kp->bytesperline, &up->bytesperline);
-       return 0;
-}
-
-static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
-       u32 tmp = (u32)((unsigned long)kp->base);
-
-       if(put_user(tmp, &up->base))
-               return -EFAULT;
-       __put_user(kp->height, &up->height);
-       __put_user(kp->width, &up->width);
-       __put_user(kp->depth, &up->depth);
-       __put_user(kp->bytesperline, &up->bytesperline);
-       return 0;
-}
-
-struct video_clip32 {
-       s32 x, y, width, height;        /* Its really s32 in videodev.h */
-       compat_caddr_t next;
-};
-
-struct video_window32 {
-       u32 x, y, width, height, chromakey, flags;
-       compat_caddr_t clips;
-       compat_int_t clipcount;
-};
-
-/* You get back everything except the clips... */
-static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
-{
-       if(put_user(kp->x, &up->x))
-               return -EFAULT;
-       __put_user(kp->y, &up->y);
-       __put_user(kp->width, &up->width);
-       __put_user(kp->height, &up->height);
-       __put_user(kp->chromakey, &up->chromakey);
-       __put_user(kp->flags, &up->flags);
-       __put_user(kp->clipcount, &up->clipcount);
-       return 0;
-}
-
-#define VIDIOCGTUNER32         _IOWR('v',4, struct video_tuner32)
-#define VIDIOCSTUNER32         _IOW('v',5, struct video_tuner32)
-#define VIDIOCGWIN32           _IOR('v',9, struct video_window32)
-#define VIDIOCSWIN32           _IOW('v',10, struct video_window32)
-#define VIDIOCGFBUF32          _IOR('v',11, struct video_buffer32)
-#define VIDIOCSFBUF32          _IOW('v',12, struct video_buffer32)
-#define VIDIOCGFREQ32          _IOR('v',14, u32)
-#define VIDIOCSFREQ32          _IOW('v',15, u32)
-
-enum {
-       MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
-};
-
-static int do_set_window(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-       struct video_window32 __user *up = compat_ptr(arg);
-       struct video_window __user *vw;
-       struct video_clip __user *p;
-       int nclips;
-       u32 n;
-
-       if (get_user(nclips, &up->clipcount))
-               return -EFAULT;
-
-       /* Peculiar interface... */
-       if (nclips < 0)
-               nclips = VIDEO_CLIPMAP_SIZE;
-
-       if (nclips > MaxClips)
-               return -ENOMEM;
-
-       vw = compat_alloc_user_space(sizeof(struct video_window) +
-                                   nclips * sizeof(struct video_clip));
-
-       p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
-
-       if (get_user(n, &up->x) || put_user(n, &vw->x) ||
-           get_user(n, &up->y) || put_user(n, &vw->y) ||
-           get_user(n, &up->width) || put_user(n, &vw->width) ||
-           get_user(n, &up->height) || put_user(n, &vw->height) ||
-           get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
-           get_user(n, &up->flags) || put_user(n, &vw->flags) ||
-           get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
-           get_user(n, &up->clips) || put_user(p, &vw->clips))
-               return -EFAULT;
-
-       if (nclips) {
-               struct video_clip32 __user *u = compat_ptr(n);
-               int i;
-               if (!u)
-                       return -EINVAL;
-               for (i = 0; i < nclips; i++, u++, p++) {
-                       s32 v;
-                       if (get_user(v, &u->x) ||
-                           put_user(v, &p->x) ||
-                           get_user(v, &u->y) ||
-                           put_user(v, &p->y) ||
-                           get_user(v, &u->width) ||
-                           put_user(v, &p->width) ||
-                           get_user(v, &u->height) ||
-                           put_user(v, &p->height) ||
-                           put_user(NULL, &p->next))
-                               return -EFAULT;
-               }
-       }
-
-       return sys_ioctl(fd, VIDIOCSWIN, (unsigned long)p);
-}
-
-static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-       union {
-               struct video_tuner vt;
-               struct video_buffer vb;
-               struct video_window vw;
-               unsigned long vx;
-       } karg;
-       mm_segment_t old_fs = get_fs();
-       void __user *up = compat_ptr(arg);
-       int err = 0;
-
-       /* First, convert the command. */
-       switch(cmd) {
-       case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
-       case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
-       case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
-       case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
-       case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
-       case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
-       case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
-       };
-
-       switch(cmd) {
-       case VIDIOCSTUNER:
-       case VIDIOCGTUNER:
-               err = get_video_tuner32(&karg.vt, up);
-               break;
-
-       case VIDIOCSFBUF:
-               err = get_video_buffer32(&karg.vb, up);
-               break;
-
-       case VIDIOCSFREQ:
-               err = get_user(karg.vx, (u32 __user *)up);
-               break;
-       };
-       if(err)
-               goto out;
-
-       set_fs(KERNEL_DS);
-       err = sys_ioctl(fd, cmd, (unsigned long)&karg);
-       set_fs(old_fs);
-
-       if(err == 0) {
-               switch(cmd) {
-               case VIDIOCGTUNER:
-                       err = put_video_tuner32(&karg.vt, up);
-                       break;
-
-               case VIDIOCGWIN:
-                       err = put_video_window32(&karg.vw, up);
-                       break;
-
-               case VIDIOCGFBUF:
-                       err = put_video_buffer32(&karg.vb, up);
-                       break;
-
-               case VIDIOCGFREQ:
-                       err = put_user(((u32)karg.vx), (u32 __user *)up);
-                       break;
-               };
-       }
-out:
-       return err;
-}
-
 struct compat_dmx_event {
        dmx_event_t     event;
        compat_time_t   timeStamp;
@@ -3015,14 +2777,6 @@ COMPATIBLE_IOCTL(EXT3_IOC_GROUP_ADD)
 #ifdef CONFIG_JBD_DEBUG
 HANDLE_IOCTL(EXT3_IOC32_WAIT_FOR_READONLY, do_ext3_ioctl)
 #endif
-HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSWIN32, do_set_window)
-HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl)
 /* One SMB ioctl needs translations. */
 #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)
 HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
index 17e4391386818d405ca0203123b9738f8b886cc8..1536f15c4d4c785a1ad2d49a78d03c5c4bd0067c 100644 (file)
@@ -71,7 +71,7 @@ struct dentry_stat_t dentry_stat = {
 
 static void d_callback(struct rcu_head *head)
 {
-       struct dentry * dentry = container_of(head, struct dentry, d_rcu);
+       struct dentry * dentry = container_of(head, struct dentry, d_u.d_rcu);
 
        if (dname_external(dentry))
                kfree(dentry->d_name.name);
@@ -86,7 +86,7 @@ static void d_free(struct dentry *dentry)
 {
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
-       call_rcu(&dentry->d_rcu, d_callback);
+       call_rcu(&dentry->d_u.d_rcu, d_callback);
 }
 
 /*
@@ -193,7 +193,7 @@ kill_it: {
                        list_del(&dentry->d_lru);
                        dentry_stat.nr_unused--;
                }
-               list_del(&dentry->d_child);
+               list_del(&dentry->d_u.d_child);
                dentry_stat.nr_dentry--;        /* For d_free, below */
                /*drops the locks, at that point nobody can reach this dentry */
                dentry_iput(dentry);
@@ -367,7 +367,7 @@ static inline void prune_one_dentry(struct dentry * dentry)
        struct dentry * parent;
 
        __d_drop(dentry);
-       list_del(&dentry->d_child);
+       list_del(&dentry->d_u.d_child);
        dentry_stat.nr_dentry--;        /* For d_free, below */
        dentry_iput(dentry);
        parent = dentry->d_parent;
@@ -518,7 +518,7 @@ repeat:
 resume:
        while (next != &this_parent->d_subdirs) {
                struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+               struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
                next = tmp->next;
                /* Have we found a mount point ? */
                if (d_mountpoint(dentry))
@@ -532,7 +532,7 @@ resume:
         * All done at this level ... ascend and resume the search.
         */
        if (this_parent != parent) {
-               next = this_parent->d_child.next; 
+               next = this_parent->d_u.d_child.next;
                this_parent = this_parent->d_parent;
                goto resume;
        }
@@ -569,7 +569,7 @@ repeat:
 resume:
        while (next != &this_parent->d_subdirs) {
                struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+               struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
                next = tmp->next;
 
                if (!list_empty(&dentry->d_lru)) {
@@ -610,7 +610,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, found);
         * All done at this level ... ascend and resume the search.
         */
        if (this_parent != parent) {
-               next = this_parent->d_child.next; 
+               next = this_parent->d_u.d_child.next;
                this_parent = this_parent->d_parent;
 #ifdef DCACHE_DEBUG
 printk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n",
@@ -753,12 +753,12 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
                dentry->d_parent = dget(parent);
                dentry->d_sb = parent->d_sb;
        } else {
-               INIT_LIST_HEAD(&dentry->d_child);
+               INIT_LIST_HEAD(&dentry->d_u.d_child);
        }
 
        spin_lock(&dcache_lock);
        if (parent)
-               list_add(&dentry->d_child, &parent->d_subdirs);
+               list_add(&dentry->d_u.d_child, &parent->d_subdirs);
        dentry_stat.nr_dentry++;
        spin_unlock(&dcache_lock);
 
@@ -1310,8 +1310,8 @@ already_unhashed:
        /* Unhash the target: dput() will then get rid of it */
        __d_drop(target);
 
-       list_del(&dentry->d_child);
-       list_del(&target->d_child);
+       list_del(&dentry->d_u.d_child);
+       list_del(&target->d_u.d_child);
 
        /* Switch the names.. */
        switch_names(dentry, target);
@@ -1322,15 +1322,15 @@ already_unhashed:
        if (IS_ROOT(dentry)) {
                dentry->d_parent = target->d_parent;
                target->d_parent = target;
-               INIT_LIST_HEAD(&target->d_child);
+               INIT_LIST_HEAD(&target->d_u.d_child);
        } else {
                do_switch(dentry->d_parent, target->d_parent);
 
                /* And add them back to the (new) parent lists */
-               list_add(&target->d_child, &target->d_parent->d_subdirs);
+               list_add(&target->d_u.d_child, &target->d_parent->d_subdirs);
        }
 
-       list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
+       list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
        spin_unlock(&target->d_lock);
        spin_unlock(&dentry->d_lock);
        write_sequnlock(&rename_lock);
@@ -1568,7 +1568,7 @@ repeat:
 resume:
        while (next != &this_parent->d_subdirs) {
                struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+               struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
                next = tmp->next;
                if (d_unhashed(dentry)||!dentry->d_inode)
                        continue;
@@ -1579,7 +1579,7 @@ resume:
                atomic_dec(&dentry->d_count);
        }
        if (this_parent != root) {
-               next = this_parent->d_child.next; 
+               next = this_parent->d_u.d_child.next;
                atomic_dec(&this_parent->d_count);
                this_parent = this_parent->d_parent;
                goto resume;
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
new file mode 100644 (file)
index 0000000..4e47623
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Implement the manual drop-all-pagecache function
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/writeback.h>
+#include <linux/sysctl.h>
+#include <linux/gfp.h>
+
+/* A global variable is a bit ugly, but it keeps the code simple */
+int sysctl_drop_caches;
+
+static void drop_pagecache_sb(struct super_block *sb)
+{
+       struct inode *inode;
+
+       spin_lock(&inode_lock);
+       list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
+               if (inode->i_state & (I_FREEING|I_WILL_FREE))
+                       continue;
+               invalidate_inode_pages(inode->i_mapping);
+       }
+       spin_unlock(&inode_lock);
+}
+
+void drop_pagecache(void)
+{
+       struct super_block *sb;
+
+       spin_lock(&sb_lock);
+restart:
+       list_for_each_entry(sb, &super_blocks, s_list) {
+               sb->s_count++;
+               spin_unlock(&sb_lock);
+               down_read(&sb->s_umount);
+               if (sb->s_root)
+                       drop_pagecache_sb(sb);
+               up_read(&sb->s_umount);
+               spin_lock(&sb_lock);
+               if (__put_super_and_need_restart(sb))
+                       goto restart;
+       }
+       spin_unlock(&sb_lock);
+}
+
+void drop_slab(void)
+{
+       int nr_objects;
+
+       do {
+               nr_objects = shrink_slab(1000, GFP_KERNEL, 1000);
+       } while (nr_objects > 10);
+}
+
+int drop_caches_sysctl_handler(ctl_table *table, int write,
+       struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
+{
+       proc_dointvec_minmax(table, write, file, buffer, length, ppos);
+       if (write) {
+               if (sysctl_drop_caches & 1)
+                       drop_pagecache();
+               if (sysctl_drop_caches & 2)
+                       drop_slab();
+       }
+       return 0;
+}
index e75a9548da8ef397b4cec6e1527f00d81e6fd5c4..fd02ea4a81e96b8c1d748d7aed28980843cb2c2b 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -760,7 +760,7 @@ no_thread_group:
                spin_lock(&oldsighand->siglock);
                spin_lock(&newsighand->siglock);
 
-               current->sighand = newsighand;
+               rcu_assign_pointer(current->sighand, newsighand);
                recalc_sigpending();
 
                spin_unlock(&newsighand->siglock);
@@ -768,7 +768,7 @@ no_thread_group:
                write_unlock_irq(&tasklist_lock);
 
                if (atomic_dec_and_test(&oldsighand->count))
-                       kmem_cache_free(sighand_cachep, oldsighand);
+                       sighand_free(oldsighand);
        }
 
        BUG_ON(!thread_group_leader(current));
@@ -1462,6 +1462,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
        if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
                current->signal->flags = SIGNAL_GROUP_EXIT;
                current->signal->group_exit_code = exit_code;
+               current->signal->group_stop_count = 0;
                retval = 0;
        }
        spin_unlock_irq(&current->sighand->siglock);
@@ -1477,7 +1478,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
         * Clear any false indication of pending signals that might
         * be seen by the filesystem code called to write the core file.
         */
-       current->signal->group_stop_count = 0;
        clear_thread_flag(TIF_SIGPENDING);
 
        if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
@@ -1505,7 +1505,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
                goto close_fail;
        if (!file->f_op->write)
                goto close_fail;
-       if (do_truncate(file->f_dentry, 0, file) != 0)
+       if (do_truncate(file->f_dentry, 0, 0, file) != 0)
                goto close_fail;
 
        retval = binfmt->core_dump(signr, regs, file);
index 9e4a243762109a193106024133b1a28ab55c1b18..69078079b19cc46c03921193246473923d8964c1 100644 (file)
@@ -651,7 +651,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
        /* Error cases - e2fsck has already cleaned up for us */
        if (ino > max_ino) {
                ext3_warning(sb, __FUNCTION__,
-                            "bad orphan ino %lu!  e2fsck was run?\n", ino);
+                            "bad orphan ino %lu!  e2fsck was run?", ino);
                goto out;
        }
 
@@ -660,7 +660,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
        bitmap_bh = read_inode_bitmap(sb, block_group);
        if (!bitmap_bh) {
                ext3_warning(sb, __FUNCTION__,
-                            "inode bitmap error for orphan %lu\n", ino);
+                            "inode bitmap error for orphan %lu", ino);
                goto out;
        }
 
@@ -672,7 +672,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
                        !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
                        NEXT_ORPHAN(inode) > max_ino) {
                ext3_warning(sb, __FUNCTION__,
-                            "bad orphan inode %lu!  e2fsck was run?\n", ino);
+                            "bad orphan inode %lu!  e2fsck was run?", ino);
                printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
                       bit, (unsigned long long)bitmap_bh->b_blocknr,
                       ext3_test_bit(bit, bitmap_bh->b_data));
index b3c690a3b54acc31276794835f34d2ceaa86fa4d..af193a304ee5868c6bd54db9f8018159940463bb 100644 (file)
@@ -1476,7 +1476,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
                if (levels && (dx_get_count(frames->entries) ==
                               dx_get_limit(frames->entries))) {
                        ext3_warning(sb, __FUNCTION__,
-                                    "Directory index full!\n");
+                                    "Directory index full!");
                        err = -ENOSPC;
                        goto cleanup;
                }
index 6104ad3105077ec7a14e5da4f24a261d116035a0..1041dab6de2fd92bc1eff0b9abcae86973925017 100644 (file)
@@ -31,7 +31,7 @@ static int verify_group_input(struct super_block *sb,
        unsigned start = le32_to_cpu(es->s_blocks_count);
        unsigned end = start + input->blocks_count;
        unsigned group = input->group;
-       unsigned itend = input->inode_table + EXT3_SB(sb)->s_itb_per_group;
+       unsigned itend = input->inode_table + sbi->s_itb_per_group;
        unsigned overhead = ext3_bg_has_super(sb, group) ?
                (1 + ext3_bg_num_gdb(sb, group) +
                 le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
@@ -340,7 +340,7 @@ static int verify_reserved_gdb(struct super_block *sb,
        while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
                if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){
                        ext3_warning(sb, __FUNCTION__,
-                                    "reserved GDT %ld missing grp %d (%ld)\n",
+                                    "reserved GDT %ld missing grp %d (%ld)",
                                     blk, grp,
                                     grp * EXT3_BLOCKS_PER_GROUP(sb) + blk);
                        return -EINVAL;
@@ -393,7 +393,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        if (EXT3_SB(sb)->s_sbh->b_blocknr !=
            le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) {
                ext3_warning(sb, __FUNCTION__,
-                       "won't resize using backup superblock at %llu\n",
+                       "won't resize using backup superblock at %llu",
                        (unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr);
                return -EPERM;
        }
@@ -417,7 +417,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        data = (__u32 *)dind->b_data;
        if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) {
                ext3_warning(sb, __FUNCTION__,
-                            "new group %u GDT block %lu not reserved\n",
+                            "new group %u GDT block %lu not reserved",
                             input->group, gdblock);
                err = -EINVAL;
                goto exit_dind;
@@ -540,7 +540,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
        for (res = 0; res < reserved_gdb; res++, blk++) {
                if (le32_to_cpu(*data) != blk) {
                        ext3_warning(sb, __FUNCTION__,
-                                    "reserved block %lu not at offset %ld\n",
+                                    "reserved block %lu not at offset %ld",
                                     blk, (long)(data - (__u32 *)dind->b_data));
                        err = -EINVAL;
                        goto exit_bh;
@@ -683,7 +683,7 @@ exit_err:
        if (err) {
                ext3_warning(sb, __FUNCTION__,
                             "can't update backup for group %d (err %d), "
-                            "forcing fsck on next reboot\n", group, err);
+                            "forcing fsck on next reboot", group, err);
                sbi->s_mount_state &= ~EXT3_VALID_FS;
                sbi->s_es->s_state &= ~cpu_to_le16(EXT3_VALID_FS);
                mark_buffer_dirty(sbi->s_sbh);
@@ -722,7 +722,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
        if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb,
                                        EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
                ext3_warning(sb, __FUNCTION__,
-                            "Can't resize non-sparse filesystem further\n");
+                            "Can't resize non-sparse filesystem further");
                return -EPERM;
        }
 
@@ -730,13 +730,13 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
                if (!EXT3_HAS_COMPAT_FEATURE(sb,
                                             EXT3_FEATURE_COMPAT_RESIZE_INODE)){
                        ext3_warning(sb, __FUNCTION__,
-                                    "No reserved GDT blocks, can't resize\n");
+                                    "No reserved GDT blocks, can't resize");
                        return -EPERM;
                }
                inode = iget(sb, EXT3_RESIZE_INO);
                if (!inode || is_bad_inode(inode)) {
                        ext3_warning(sb, __FUNCTION__,
-                                    "Error opening resize inode\n");
+                                    "Error opening resize inode");
                        iput(inode);
                        return -ENOENT;
                }
@@ -764,9 +764,9 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
        }
 
        lock_super(sb);
-       if (input->group != EXT3_SB(sb)->s_groups_count) {
+       if (input->group != sbi->s_groups_count) {
                ext3_warning(sb, __FUNCTION__,
-                            "multiple resizers run on filesystem!\n");
+                            "multiple resizers run on filesystem!");
                err = -EBUSY;
                goto exit_journal;
        }
@@ -799,7 +799,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
         * data.  So we need to be careful to set all of the relevant
         * group descriptor data etc. *before* we enable the group.
         *
-        * The key field here is EXT3_SB(sb)->s_groups_count: as long as
+        * The key field here is sbi->s_groups_count: as long as
         * that retains its old value, nobody is going to access the new
         * group.
         *
@@ -859,7 +859,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
        smp_wmb();
 
        /* Update the global fs size fields */
-       EXT3_SB(sb)->s_groups_count++;
+       sbi->s_groups_count++;
 
        ext3_journal_dirty_metadata(handle, primary);
 
@@ -874,7 +874,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
        percpu_counter_mod(&sbi->s_freeinodes_counter,
                           EXT3_INODES_PER_GROUP(sb));
 
-       ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
+       ext3_journal_dirty_metadata(handle, sbi->s_sbh);
        sb->s_dirt = 1;
 
 exit_journal:
@@ -937,7 +937,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
 
        if (last == 0) {
                ext3_warning(sb, __FUNCTION__,
-                            "need to use ext2online to resize further\n");
+                            "need to use ext2online to resize further");
                return -EPERM;
        }
 
@@ -973,7 +973,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
        lock_super(sb);
        if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) {
                ext3_warning(sb, __FUNCTION__,
-                            "multiple resizers run on filesystem!\n");
+                            "multiple resizers run on filesystem!");
                err = -EBUSY;
                goto exit_put;
        }
index 4e6730622d90526f67eab59f13852f124166a1c2..7c45acf94589c12833deeae5aa53d72c2947340c 100644 (file)
@@ -43,7 +43,8 @@
 #include "acl.h"
 #include "namei.h"
 
-static int ext3_load_journal(struct super_block *, struct ext3_super_block *);
+static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
+                            unsigned long journal_devnum);
 static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
                               int);
 static void ext3_commit_super (struct super_block * sb,
@@ -628,7 +629,7 @@ enum {
        Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
        Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
        Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh,
-       Opt_commit, Opt_journal_update, Opt_journal_inum,
+       Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
@@ -666,6 +667,7 @@ static match_table_t tokens = {
        {Opt_commit, "commit=%u"},
        {Opt_journal_update, "journal=update"},
        {Opt_journal_inum, "journal=%u"},
+       {Opt_journal_dev, "journal_dev=%u"},
        {Opt_abort, "abort"},
        {Opt_data_journal, "data=journal"},
        {Opt_data_ordered, "data=ordered"},
@@ -705,8 +707,9 @@ static unsigned long get_sb_block(void **data)
        return sb_block;
 }
 
-static int parse_options (char * options, struct super_block *sb,
-                         unsigned long * inum, unsigned long *n_blocks_count, int is_remount)
+static int parse_options (char *options, struct super_block *sb,
+                         unsigned long *inum, unsigned long *journal_devnum,
+                         unsigned long *n_blocks_count, int is_remount)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
        char * p;
@@ -839,6 +842,16 @@ static int parse_options (char * options, struct super_block *sb,
                                return 0;
                        *inum = option;
                        break;
+               case Opt_journal_dev:
+                       if (is_remount) {
+                               printk(KERN_ERR "EXT3-fs: cannot specify "
+                                      "journal on remount\n");
+                               return 0;
+                       }
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       *journal_devnum = option;
+                       break;
                case Opt_noload:
                        set_opt (sbi->s_mount_opt, NOLOAD);
                        break;
@@ -1331,6 +1344,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        unsigned long logic_sb_block;
        unsigned long offset = 0;
        unsigned long journal_inum = 0;
+       unsigned long journal_devnum = 0;
        unsigned long def_mount_opts;
        struct inode *root;
        int blocksize;
@@ -1411,7 +1425,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
 
        set_opt(sbi->s_mount_opt, RESERVATION);
 
-       if (!parse_options ((char *) data, sb, &journal_inum, NULL, 0))
+       if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
+                           NULL, 0))
                goto failed_mount;
 
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
@@ -1622,7 +1637,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
         */
        if (!test_opt(sb, NOLOAD) &&
            EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
-               if (ext3_load_journal(sb, es))
+               if (ext3_load_journal(sb, es, journal_devnum))
                        goto failed_mount2;
        } else if (journal_inum) {
                if (ext3_create_journal(sb, es, journal_inum))
@@ -1902,15 +1917,24 @@ out_bdev:
        return NULL;
 }
 
-static int ext3_load_journal(struct super_block * sb,
-                            struct ext3_super_block * es)
+static int ext3_load_journal(struct super_block *sb,
+                            struct ext3_super_block *es,
+                            unsigned long journal_devnum)
 {
        journal_t *journal;
        int journal_inum = le32_to_cpu(es->s_journal_inum);
-       dev_t journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
+       dev_t journal_dev;
        int err = 0;
        int really_read_only;
 
+       if (journal_devnum &&
+           journal_devnum != le32_to_cpu(es->s_journal_dev)) {
+               printk(KERN_INFO "EXT3-fs: external journal device major/minor "
+                       "numbers have changed\n");
+               journal_dev = new_decode_dev(journal_devnum);
+       } else
+               journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
+
        really_read_only = bdev_read_only(sb->s_bdev);
 
        /*
@@ -1969,6 +1993,16 @@ static int ext3_load_journal(struct super_block * sb,
 
        EXT3_SB(sb)->s_journal = journal;
        ext3_clear_journal_err(sb, es);
+
+       if (journal_devnum &&
+           journal_devnum != le32_to_cpu(es->s_journal_dev)) {
+               es->s_journal_dev = cpu_to_le32(journal_devnum);
+               sb->s_dirt = 1;
+
+               /* Make sure we flush the recovery flag to disk. */
+               ext3_commit_super(sb, es, 1);
+       }
+
        return 0;
 }
 
@@ -2197,7 +2231,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
        /*
         * Allow the "check" option to be passed as a remount option.
         */
-       if (!parse_options(data, sb, NULL, &n_blocks_count, 1)) {
+       if (!parse_options(data, sb, NULL, NULL, &n_blocks_count, 1)) {
                err = -EINVAL;
                goto restore_opts;
        }
index 77c24fcf712aefdc626781eee7a5bcbb10c62493..1acc941245fb4a4c751c972684202b19d0f2208a 100644 (file)
@@ -295,7 +295,8 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
        return dclus;
 }
 
-int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys)
+int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
+            unsigned long *mapped_blocks)
 {
        struct super_block *sb = inode->i_sb;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
@@ -303,9 +304,12 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys)
        int cluster, offset;
 
        *phys = 0;
+       *mapped_blocks = 0;
        if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) {
-               if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits))
+               if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) {
                        *phys = sector + sbi->dir_start;
+                       *mapped_blocks = 1;
+               }
                return 0;
        }
        last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1))
@@ -318,7 +322,11 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys)
        cluster = fat_bmap_cluster(inode, cluster);
        if (cluster < 0)
                return cluster;
-       else if (cluster)
+       else if (cluster) {
                *phys = fat_clus_to_blknr(sbi, cluster) + offset;
+               *mapped_blocks = sbi->sec_per_clus - offset;
+               if (*mapped_blocks > last_block - sector)
+                       *mapped_blocks = last_block - sector;
+       }
        return 0;
 }
index ba824964b9bbaf7fec4faa0cf6998675819993ba..eef1b81aa294d8a8f82686030edea5ca006ce320 100644 (file)
@@ -45,8 +45,8 @@ static inline void fat_dir_readahead(struct inode *dir, sector_t iblock,
        if ((sbi->fat_bits != 32) && (dir->i_ino == MSDOS_ROOT_INO))
                return;
 
-       bh = sb_getblk(sb, phys);
-       if (bh && !buffer_uptodate(bh)) {
+       bh = sb_find_get_block(sb, phys);
+       if (bh == NULL || !buffer_uptodate(bh)) {
                for (sec = 0; sec < sbi->sec_per_clus; sec++)
                        sb_breadahead(sb, phys + sec);
        }
@@ -68,8 +68,8 @@ static int fat__get_entry(struct inode *dir, loff_t *pos,
 {
        struct super_block *sb = dir->i_sb;
        sector_t phys, iblock;
-       int offset;
-       int err;
+       unsigned long mapped_blocks;
+       int err, offset;
 
 next:
        if (*bh)
@@ -77,7 +77,7 @@ next:
 
        *bh = NULL;
        iblock = *pos >> sb->s_blocksize_bits;
-       err = fat_bmap(dir, iblock, &phys);
+       err = fat_bmap(dir, iblock, &phys, &mapped_blocks);
        if (err || !phys)
                return -1;      /* beyond EOF or error */
 
@@ -418,7 +418,7 @@ EODir:
        return err;
 }
 
-EXPORT_SYMBOL(fat_search_long);
+EXPORT_SYMBOL_GPL(fat_search_long);
 
 struct fat_ioctl_filldir_callback {
        struct dirent __user *dirent;
@@ -780,7 +780,7 @@ int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
        return -ENOENT;
 }
 
-EXPORT_SYMBOL(fat_get_dotdot_entry);
+EXPORT_SYMBOL_GPL(fat_get_dotdot_entry);
 
 /* See if directory is empty */
 int fat_dir_empty(struct inode *dir)
@@ -803,7 +803,7 @@ int fat_dir_empty(struct inode *dir)
        return result;
 }
 
-EXPORT_SYMBOL(fat_dir_empty);
+EXPORT_SYMBOL_GPL(fat_dir_empty);
 
 /*
  * fat_subdirs counts the number of sub-directories of dir. It can be run
@@ -849,7 +849,7 @@ int fat_scan(struct inode *dir, const unsigned char *name,
        return -ENOENT;
 }
 
-EXPORT_SYMBOL(fat_scan);
+EXPORT_SYMBOL_GPL(fat_scan);
 
 static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots)
 {
@@ -936,7 +936,7 @@ int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
        return 0;
 }
 
-EXPORT_SYMBOL(fat_remove_entries);
+EXPORT_SYMBOL_GPL(fat_remove_entries);
 
 static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used,
                              struct buffer_head **bhs, int nr_bhs)
@@ -1048,7 +1048,7 @@ error:
        return err;
 }
 
-EXPORT_SYMBOL(fat_alloc_new_dir);
+EXPORT_SYMBOL_GPL(fat_alloc_new_dir);
 
 static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots,
                               int *nr_cluster, struct msdos_dir_entry **de,
@@ -1264,4 +1264,4 @@ error_remove:
        return err;
 }
 
-EXPORT_SYMBOL(fat_add_entries);
+EXPORT_SYMBOL_GPL(fat_add_entries);
index 4164cd54c4d1e6b3308ea2c7869a87f517022388..a1a9e04512175c02d21a10b1586a2bd387fd53d8 100644 (file)
@@ -476,6 +476,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
                                sbi->prev_free = entry;
                                if (sbi->free_clusters != -1)
                                        sbi->free_clusters--;
+                               sb->s_dirt = 1;
 
                                cluster[idx_clus] = entry;
                                idx_clus++;
@@ -496,6 +497,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
 
        /* Couldn't allocate the free entries */
        sbi->free_clusters = 0;
+       sb->s_dirt = 1;
        err = -ENOSPC;
 
 out:
@@ -509,7 +511,6 @@ out:
        }
        for (i = 0; i < nr_bhs; i++)
                brelse(bhs[i]);
-       fat_clusters_flush(sb);
 
        if (err && idx_clus)
                fat_free_clusters(inode, cluster[0]);
@@ -542,8 +543,10 @@ int fat_free_clusters(struct inode *inode, int cluster)
                }
 
                ops->ent_put(&fatent, FAT_ENT_FREE);
-               if (sbi->free_clusters != -1)
+               if (sbi->free_clusters != -1) {
                        sbi->free_clusters++;
+                       sb->s_dirt = 1;
+               }
 
                if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) {
                        if (sb->s_flags & MS_SYNCHRONOUS) {
@@ -578,7 +581,7 @@ error:
        return err;
 }
 
-EXPORT_SYMBOL(fat_free_clusters);
+EXPORT_SYMBOL_GPL(fat_free_clusters);
 
 int fat_count_free_clusters(struct super_block *sb)
 {
@@ -605,6 +608,7 @@ int fat_count_free_clusters(struct super_block *sb)
                } while (fat_ent_next(sbi, &fatent));
        }
        sbi->free_clusters = free;
+       sb->s_dirt = 1;
        fatent_brelse(&fatent);
 out:
        unlock_fat(sbi);
index 7134403d5be25546b57d5c8880b96873754b1283..9b07c328a6fca012ea16b192966ae8a2d409cda2 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/msdos_fs.h>
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
+#include <linux/writeback.h>
 
 int fat_generic_ioctl(struct inode *inode, struct file *filp,
                      unsigned int cmd, unsigned long arg)
@@ -124,6 +125,24 @@ struct file_operations fat_file_operations = {
        .sendfile       = generic_file_sendfile,
 };
 
+static int fat_cont_expand(struct inode *inode, loff_t size)
+{
+       struct address_space *mapping = inode->i_mapping;
+       loff_t start = inode->i_size, count = size - inode->i_size;
+       int err;
+
+       err = generic_cont_expand_simple(inode, size);
+       if (err)
+               goto out;
+
+       inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+       mark_inode_dirty(inode);
+       if (IS_SYNC(inode))
+               err = sync_page_range_nolock(inode, mapping, start, count);
+out:
+       return err;
+}
+
 int fat_notify_change(struct dentry *dentry, struct iattr *attr)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -132,11 +151,17 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
 
        lock_kernel();
 
-       /* FAT cannot truncate to a longer file */
+       /*
+        * Expand the file. Since inode_setattr() updates ->i_size
+        * before calling the ->truncate(), but FAT needs to fill the
+        * hole before it.
+        */
        if (attr->ia_valid & ATTR_SIZE) {
                if (attr->ia_size > inode->i_size) {
-                       error = -EPERM;
-                       goto out;
+                       error = fat_cont_expand(inode, attr->ia_size);
+                       if (error || attr->ia_valid == ATTR_SIZE)
+                               goto out;
+                       attr->ia_valid &= ~ATTR_SIZE;
                }
        }
 
@@ -173,7 +198,7 @@ out:
        return error;
 }
 
-EXPORT_SYMBOL(fat_notify_change);
+EXPORT_SYMBOL_GPL(fat_notify_change);
 
 /* Free all clusters after the skip'th cluster. */
 static int fat_free(struct inode *inode, int skip)
index a0f9b9fe1307addd7ba1bef750ab1fac49abfea7..e7f4aa7fc6864be095def4db3ac8078f7f218052 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/msdos_fs.h>
 #include <linux/pagemap.h>
+#include <linux/mpage.h>
 #include <linux/buffer_head.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
 #include <linux/parser.h>
+#include <linux/uio.h>
 #include <asm/unaligned.h>
 
 #ifndef CONFIG_FAT_DEFAULT_IOCHARSET
@@ -48,51 +50,97 @@ static int fat_add_cluster(struct inode *inode)
        return err;
 }
 
-static int fat_get_block(struct inode *inode, sector_t iblock,
-                        struct buffer_head *bh_result, int create)
+static int __fat_get_blocks(struct inode *inode, sector_t iblock,
+                           unsigned long *max_blocks,
+                           struct buffer_head *bh_result, int create)
 {
        struct super_block *sb = inode->i_sb;
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
        sector_t phys;
-       int err;
+       unsigned long mapped_blocks;
+       int err, offset;
 
-       err = fat_bmap(inode, iblock, &phys);
+       err = fat_bmap(inode, iblock, &phys, &mapped_blocks);
        if (err)
                return err;
        if (phys) {
                map_bh(bh_result, sb, phys);
+               *max_blocks = min(mapped_blocks, *max_blocks);
                return 0;
        }
        if (!create)
                return 0;
+
        if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
                fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",
                             MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
                return -EIO;
        }
-       if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) {
+
+       offset = (unsigned long)iblock & (sbi->sec_per_clus - 1);
+       if (!offset) {
+               /* TODO: multiple cluster allocation would be desirable. */
                err = fat_add_cluster(inode);
                if (err)
                        return err;
        }
-       MSDOS_I(inode)->mmu_private += sb->s_blocksize;
-       err = fat_bmap(inode, iblock, &phys);
+       /* available blocks on this cluster */
+       mapped_blocks = sbi->sec_per_clus - offset;
+
+       *max_blocks = min(mapped_blocks, *max_blocks);
+       MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;
+
+       err = fat_bmap(inode, iblock, &phys, &mapped_blocks);
        if (err)
                return err;
-       if (!phys)
-               BUG();
+       BUG_ON(!phys);
+       BUG_ON(*max_blocks != mapped_blocks);
        set_buffer_new(bh_result);
        map_bh(bh_result, sb, phys);
        return 0;
 }
 
+static int fat_get_blocks(struct inode *inode, sector_t iblock,
+                         unsigned long max_blocks,
+                         struct buffer_head *bh_result, int create)
+{
+       struct super_block *sb = inode->i_sb;
+       int err;
+
+       err = __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create);
+       if (err)
+               return err;
+       bh_result->b_size = max_blocks << sb->s_blocksize_bits;
+       return 0;
+}
+
+static int fat_get_block(struct inode *inode, sector_t iblock,
+                        struct buffer_head *bh_result, int create)
+{
+       unsigned long max_blocks = 1;
+       return __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create);
+}
+
 static int fat_writepage(struct page *page, struct writeback_control *wbc)
 {
        return block_write_full_page(page, fat_get_block, wbc);
 }
 
+static int fat_writepages(struct address_space *mapping,
+                         struct writeback_control *wbc)
+{
+       return mpage_writepages(mapping, wbc, fat_get_block);
+}
+
 static int fat_readpage(struct file *file, struct page *page)
 {
-       return block_read_full_page(page, fat_get_block);
+       return mpage_readpage(page, fat_get_block);
+}
+
+static int fat_readpages(struct file *file, struct address_space *mapping,
+                        struct list_head *pages, unsigned nr_pages)
+{
+       return mpage_readpages(mapping, pages, nr_pages, fat_get_block);
 }
 
 static int fat_prepare_write(struct file *file, struct page *page,
@@ -115,6 +163,34 @@ static int fat_commit_write(struct file *file, struct page *page,
        return err;
 }
 
+static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
+                            const struct iovec *iov,
+                            loff_t offset, unsigned long nr_segs)
+{
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file->f_mapping->host;
+
+       if (rw == WRITE) {
+               /*
+                * FIXME: blockdev_direct_IO() doesn't use ->prepare_write(),
+                * so we need to update the ->mmu_private to block boundary.
+                *
+                * But we must fill the remaining area or hole by nul for
+                * updating ->mmu_private.
+                */
+               loff_t size = offset + iov_length(iov, nr_segs);
+               if (MSDOS_I(inode)->mmu_private < size)
+                       return -EINVAL;
+       }
+
+       /*
+        * FAT need to use the DIO_LOCKING for avoiding the race
+        * condition of fat_get_block() and ->truncate().
+        */
+       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+                                 offset, nr_segs, fat_get_blocks, NULL);
+}
+
 static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping, block, fat_get_block);
@@ -122,10 +198,13 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
 
 static struct address_space_operations fat_aops = {
        .readpage       = fat_readpage,
+       .readpages      = fat_readpages,
        .writepage      = fat_writepage,
+       .writepages     = fat_writepages,
        .sync_page      = block_sync_page,
        .prepare_write  = fat_prepare_write,
        .commit_write   = fat_commit_write,
+       .direct_IO      = fat_direct_IO,
        .bmap           = _fat_bmap
 };
 
@@ -182,7 +261,7 @@ void fat_attach(struct inode *inode, loff_t i_pos)
        spin_unlock(&sbi->inode_hash_lock);
 }
 
-EXPORT_SYMBOL(fat_attach);
+EXPORT_SYMBOL_GPL(fat_attach);
 
 void fat_detach(struct inode *inode)
 {
@@ -193,7 +272,7 @@ void fat_detach(struct inode *inode)
        spin_unlock(&sbi->inode_hash_lock);
 }
 
-EXPORT_SYMBOL(fat_detach);
+EXPORT_SYMBOL_GPL(fat_detach);
 
 struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
 {
@@ -347,7 +426,7 @@ out:
        return inode;
 }
 
-EXPORT_SYMBOL(fat_build_inode);
+EXPORT_SYMBOL_GPL(fat_build_inode);
 
 static void fat_delete_inode(struct inode *inode)
 {
@@ -374,12 +453,17 @@ static void fat_clear_inode(struct inode *inode)
        unlock_kernel();
 }
 
-static void fat_put_super(struct super_block *sb)
+static void fat_write_super(struct super_block *sb)
 {
-       struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       sb->s_dirt = 0;
 
        if (!(sb->s_flags & MS_RDONLY))
                fat_clusters_flush(sb);
+}
+
+static void fat_put_super(struct super_block *sb)
+{
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
        if (sbi->nls_disk) {
                unload_nls(sbi->nls_disk);
@@ -537,7 +621,7 @@ int fat_sync_inode(struct inode *inode)
        return fat_write_inode(inode, 1);
 }
 
-EXPORT_SYMBOL(fat_sync_inode);
+EXPORT_SYMBOL_GPL(fat_sync_inode);
 
 static int fat_show_options(struct seq_file *m, struct vfsmount *mnt);
 static struct super_operations fat_sops = {
@@ -546,6 +630,7 @@ static struct super_operations fat_sops = {
        .write_inode    = fat_write_inode,
        .delete_inode   = fat_delete_inode,
        .put_super      = fat_put_super,
+       .write_super    = fat_write_super,
        .statfs         = fat_statfs,
        .clear_inode    = fat_clear_inode,
        .remount_fs     = fat_remount,
@@ -1347,7 +1432,7 @@ out_fail:
        return error;
 }
 
-EXPORT_SYMBOL(fat_fill_super);
+EXPORT_SYMBOL_GPL(fat_fill_super);
 
 int __init fat_cache_init(void);
 void fat_cache_destroy(void);
index 2a0df2122f5d3d8294a943c6f0cb16bd4a83f50c..32fb0a3f1da46b712ab514037ed0d8fbe0233808 100644 (file)
@@ -33,7 +33,7 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...)
        }
 }
 
-EXPORT_SYMBOL(fat_fs_panic);
+EXPORT_SYMBOL_GPL(fat_fs_panic);
 
 /* Flushes the number of free clusters on FAT32 */
 /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
@@ -67,8 +67,6 @@ void fat_clusters_flush(struct super_block *sb)
                if (sbi->prev_free != -1)
                        fsinfo->next_cluster = cpu_to_le32(sbi->prev_free);
                mark_buffer_dirty(bh);
-               if (sb->s_flags & MS_SYNCHRONOUS)
-                       sync_dirty_buffer(bh);
        }
        brelse(bh);
 }
@@ -194,7 +192,7 @@ void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
        *date = cpu_to_le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9));
 }
 
-EXPORT_SYMBOL(fat_date_unix2dos);
+EXPORT_SYMBOL_GPL(fat_date_unix2dos);
 
 int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
 {
@@ -222,4 +220,4 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
        return err;
 }
 
-EXPORT_SYMBOL(fat_sync_bhs);
+EXPORT_SYMBOL_GPL(fat_sync_bhs);
index 863b46e0d78a6594371a744358104faae657c307..9903bde475f2ec4877bd0f0f32e76b2939ebf81f 100644 (file)
@@ -457,11 +457,11 @@ static void send_sigio_to_task(struct task_struct *p,
                        else
                                si.si_band = band_table[reason - POLL_IN];
                        si.si_fd    = fd;
-                       if (!send_group_sig_info(fown->signum, &si, p))
+                       if (!group_send_sig_info(fown->signum, &si, p))
                                break;
                /* fall-through: fall back on the old plain SIGIO signal */
                case 0:
-                       send_group_sig_info(SIGIO, SEND_SIG_PRIV, p);
+                       group_send_sig_info(SIGIO, SEND_SIG_PRIV, p);
        }
 }
 
@@ -495,7 +495,7 @@ static void send_sigurg_to_task(struct task_struct *p,
                                 struct fown_struct *fown)
 {
        if (sigio_perm(p, fown, SIGURG))
-               send_group_sig_info(SIGURG, SEND_SIG_PRIV, p);
+               group_send_sig_info(SIGURG, SEND_SIG_PRIV, p);
 }
 
 int send_sigurg(struct fown_struct *fown)
index c3a5e2fd663b772d7eeb997171d6b052b82d680c..6142250104a6dbdc2acd0a5eca5ad7263105785b 100644 (file)
@@ -117,7 +117,7 @@ EXPORT_SYMBOL(get_empty_filp);
 
 void fastcall fput(struct file *file)
 {
-       if (rcuref_dec_and_test(&file->f_count))
+       if (atomic_dec_and_test(&file->f_count))
                __fput(file);
 }
 
@@ -166,7 +166,7 @@ struct file fastcall *fget(unsigned int fd)
        rcu_read_lock();
        file = fcheck_files(files, fd);
        if (file) {
-               if (!rcuref_inc_lf(&file->f_count)) {
+               if (!atomic_inc_not_zero(&file->f_count)) {
                        /* File object ref couldn't be taken */
                        rcu_read_unlock();
                        return NULL;
@@ -198,7 +198,7 @@ struct file fastcall *fget_light(unsigned int fd, int *fput_needed)
                rcu_read_lock();
                file = fcheck_files(files, fd);
                if (file) {
-                       if (rcuref_inc_lf(&file->f_count))
+                       if (atomic_inc_not_zero(&file->f_count))
                                *fput_needed = 1;
                        else
                                /* Didn't get the reference, someone's freed */
@@ -213,7 +213,7 @@ struct file fastcall *fget_light(unsigned int fd, int *fput_needed)
 
 void put_filp(struct file *file)
 {
-       if (rcuref_dec_and_test(&file->f_count)) {
+       if (atomic_dec_and_test(&file->f_count)) {
                security_file_free(file);
                file_kill(file);
                file_free(file);
index d0401dc68d41306cef3781de18e9ac18ef7ad306..6f5df1700e9506b230d973ec0b88b546bd98805b 100644 (file)
@@ -99,8 +99,8 @@ static int
 vxfs_immed_readpage(struct file *fp, struct page *pp)
 {
        struct vxfs_inode_info  *vip = VXFS_INO(pp->mapping->host);
-       u_int64_t               offset = pp->index << PAGE_CACHE_SHIFT;
-       caddr_t                 kaddr;
+       u_int64_t       offset = (u_int64_t)pp->index << PAGE_CACHE_SHIFT;
+       caddr_t         kaddr;
 
        kaddr = kmap(pp);
        memcpy(kaddr, vip->vii_immed.vi_immed + offset, PAGE_CACHE_SIZE);
index d8d04bd72b59514dc39fc9eab62a7c3f54f50f1e..fd568caf7f74f8866e518008d6defa8500e159e5 100644 (file)
@@ -770,7 +770,7 @@ EXPORT_SYMBOL(igrab);
  *
  * Note, @test is called with the inode_lock held, so can't sleep.
  */
-static inline struct inode *ifind(struct super_block *sb,
+static struct inode *ifind(struct super_block *sb,
                struct hlist_head *head, int (*test)(struct inode *, void *),
                void *data, const int wait)
 {
@@ -804,7 +804,7 @@ static inline struct inode *ifind(struct super_block *sb,
  *
  * Otherwise NULL is returned.
  */
-static inline struct inode *ifind_fast(struct super_block *sb,
+static struct inode *ifind_fast(struct super_block *sb,
                struct hlist_head *head, unsigned long ino)
 {
        struct inode *inode;
index 3dcc6d2162cb812f4d3392c8a40a8cc1aea326b7..2559ee10beda195647d8f307c6050ed1fc6a1c12 100644 (file)
@@ -757,7 +757,7 @@ jffs_do_readpage_nolock(struct file *file, struct page *page)
 
        read_len = 0;
        result = 0;
-       offset = page->index << PAGE_CACHE_SHIFT;
+       offset = page_offset(page);
 
        kmap(page);
        buf = page_address(page);
@@ -1545,7 +1545,7 @@ jffs_commit_write(struct file *filp, struct page *page,
 {
        void *addr = page_address(page) + from;
        /* XXX: PAGE_CACHE_SHIFT or PAGE_SHIFT */
-       loff_t pos = (page->index<<PAGE_CACHE_SHIFT) + from;
+       loff_t pos = page_offset(page) + from;
 
        return jffs_file_write(filp, addr, to-from, &pos);
 } /* jffs_commit_write() */
index 68000a50ceb60610e796e184ba6384af47e1cb7e..2967b73934151f2291b2d0123dacb2f125239020 100644 (file)
@@ -302,8 +302,7 @@ int dbSync(struct inode *ipbmap)
        /*
         * write out dirty pages of bmap
         */
-       filemap_fdatawrite(ipbmap->i_mapping);
-       filemap_fdatawait(ipbmap->i_mapping);
+       filemap_write_and_wait(ipbmap->i_mapping);
 
        diWriteSpecial(ipbmap, 0);
 
index 28201b194f531ba10aa819abccb030bc7ea88cd0..31b4aa13dd4b988e9a6d8bb9ee071f56e5d524aa 100644 (file)
@@ -265,8 +265,7 @@ int diSync(struct inode *ipimap)
        /*
         * write out dirty pages of imap
         */
-       filemap_fdatawrite(ipimap->i_mapping);
-       filemap_fdatawait(ipimap->i_mapping);
+       filemap_write_and_wait(ipimap->i_mapping);
 
        diWriteSpecial(ipimap, 0);
 
@@ -565,8 +564,7 @@ void diFreeSpecial(struct inode *ip)
                jfs_err("diFreeSpecial called with NULL ip!");
                return;
        }
-       filemap_fdatawrite(ip->i_mapping);
-       filemap_fdatawait(ip->i_mapping);
+       filemap_write_and_wait(ip->i_mapping);
        truncate_inode_pages(ip->i_mapping, 0);
        iput(ip);
 }
index b660c93c92deaf112c7b7955743c41e6a39c929a..2ddb6b892bcf17b80d75b2fb20b8d573fafb30b0 100644 (file)
@@ -1231,10 +1231,8 @@ int txCommit(tid_t tid,          /* transaction identifier */
                 * when we don't need to worry about it at all.
                 *
                 * if ((!S_ISDIR(ip->i_mode))
-                *    && (tblk->flag & COMMIT_DELETE) == 0) {
-                *      filemap_fdatawrite(ip->i_mapping);
-                *      filemap_fdatawait(ip->i_mapping);
-                * }
+                *    && (tblk->flag & COMMIT_DELETE) == 0)
+                *      filemap_write_and_wait(ip->i_mapping);
                 */
 
                /*
index 5cf91785b5416be6016ab720871cd0b3bcc9477c..21eaf7ac0fcb6c46ebfc784bc9a9a24a32e18339 100644 (file)
@@ -108,8 +108,7 @@ int jfs_umount(struct super_block *sb)
         * Make sure all metadata makes it to disk before we mark
         * the superblock as clean
         */
-       filemap_fdatawrite(sbi->direct_inode->i_mapping);
-       filemap_fdatawait(sbi->direct_inode->i_mapping);
+       filemap_write_and_wait(sbi->direct_inode->i_mapping);
 
        /*
         * ensure all file system file pages are propagated to their
@@ -161,8 +160,7 @@ int jfs_umount_rw(struct super_block *sb)
         * mark the superblock clean before everything is flushed to
         * disk.
         */
-       filemap_fdatawrite(sbi->direct_inode->i_mapping);
-       filemap_fdatawait(sbi->direct_inode->i_mapping);
+       filemap_write_and_wait(sbi->direct_inode->i_mapping);
 
        updateSuper(sb, FM_CLEAN);
 
index c6dc254d325325ba247142e39d75abfb072b7a58..45180361871c9a98e04db73506a973e0c0dce0c1 100644 (file)
@@ -376,8 +376,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
         * by txCommit();
         */
        filemap_fdatawait(ipbmap->i_mapping);
-       filemap_fdatawrite(ipbmap->i_mapping);
-       filemap_fdatawait(ipbmap->i_mapping);
+       filemap_write_and_wait(ipbmap->i_mapping);
        diWriteSpecial(ipbmap, 0);
 
        newPage = nPages;       /* first new page number */
index 4226af3ea91bc18dbdf414f63738101babca9cf8..8d31f1336431a916e7947f0381ec439d61705bbb 100644 (file)
@@ -502,8 +502,7 @@ out_no_rw:
                jfs_err("jfs_umount failed with return code %d", rc);
        }
 out_mount_failed:
-       filemap_fdatawrite(sbi->direct_inode->i_mapping);
-       filemap_fdatawait(sbi->direct_inode->i_mapping);
+       filemap_write_and_wait(sbi->direct_inode->i_mapping);
        truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
        make_bad_inode(sbi->direct_inode);
        iput(sbi->direct_inode);
index 58101dff2c66de94fc4fa82bf13696e9d9b8d665..9c50523382e7eced4a45a44ce64e07ebaca5d9c5 100644 (file)
@@ -93,16 +93,16 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
                        loff_t n = file->f_pos - 2;
 
                        spin_lock(&dcache_lock);
-                       list_del(&cursor->d_child);
+                       list_del(&cursor->d_u.d_child);
                        p = file->f_dentry->d_subdirs.next;
                        while (n && p != &file->f_dentry->d_subdirs) {
                                struct dentry *next;
-                               next = list_entry(p, struct dentry, d_child);
+                               next = list_entry(p, struct dentry, d_u.d_child);
                                if (!d_unhashed(next) && next->d_inode)
                                        n--;
                                p = p->next;
                        }
-                       list_add_tail(&cursor->d_child, p);
+                       list_add_tail(&cursor->d_u.d_child, p);
                        spin_unlock(&dcache_lock);
                }
        }
@@ -126,7 +126,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
        struct dentry *dentry = filp->f_dentry;
        struct dentry *cursor = filp->private_data;
-       struct list_head *p, *q = &cursor->d_child;
+       struct list_head *p, *q = &cursor->d_u.d_child;
        ino_t ino;
        int i = filp->f_pos;
 
@@ -153,7 +153,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
                        }
                        for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
                                struct dentry *next;
-                               next = list_entry(p, struct dentry, d_child);
+                               next = list_entry(p, struct dentry, d_u.d_child);
                                if (d_unhashed(next) || !next->d_inode)
                                        continue;
 
@@ -261,7 +261,7 @@ int simple_empty(struct dentry *dentry)
        int ret = 0;
 
        spin_lock(&dcache_lock);
-       list_for_each_entry(child, &dentry->d_subdirs, d_child)
+       list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child)
                if (simple_positive(child))
                        goto out;
        ret = 1;
index fb32d6218e213e3e31c5fe000dcb5ef362b3f176..909eab8fb1d09ba157f578a4817fefb7d0937c36 100644 (file)
@@ -154,7 +154,7 @@ static struct file_lock *locks_alloc_lock(void)
 }
 
 /* Free a lock which is not in use. */
-static inline void locks_free_lock(struct file_lock *fl)
+static void locks_free_lock(struct file_lock *fl)
 {
        if (fl == NULL) {
                BUG();
@@ -475,8 +475,7 @@ static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
 /*
  * Check whether two locks have the same owner.
  */
-static inline int
-posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
+static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
 {
        if (fl1->fl_lmops && fl1->fl_lmops->fl_compare_owner)
                return fl2->fl_lmops == fl1->fl_lmops &&
@@ -487,7 +486,7 @@ posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
 /* Remove waiter from blocker's block list.
  * When blocker ends up pointing to itself then the list is empty.
  */
-static inline void __locks_delete_block(struct file_lock *waiter)
+static void __locks_delete_block(struct file_lock *waiter)
 {
        list_del_init(&waiter->fl_block);
        list_del_init(&waiter->fl_link);
index f1d2d02bd4c81ebeb0ccde0c2d66d6c4a980d3d3..e431cb3878d699561e668d9378009815cfb4256a 100644 (file)
@@ -184,7 +184,7 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
        if (page_has_buffers(page))
                goto confused;
 
-       block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);
+       block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits);
        last_block = (i_size_read(inode) + blocksize - 1) >> blkbits;
 
        bh.b_page = page;
@@ -466,7 +466,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
         * The page has no buffers: map it to disk
         */
        BUG_ON(!PageUptodate(page));
-       block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);
+       block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits);
        last_block = (i_size - 1) >> blkbits;
        map_bh.b_page = page;
        for (page_block = 0; page_block < blocks_per_page; ) {
index 6dbbd42d8b95fb933ed7a4f3e0183baff73fe3fb..300eae088d5f8c2969edca1c4e2cb3599abccc7a 100644 (file)
@@ -1491,7 +1491,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
                if (!error) {
                        DQUOT_INIT(inode);
                        
-                       error = do_truncate(dentry, 0, NULL);
+                       error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL);
                }
                put_write_access(inode);
                if (error)
index 2019899f2ab822caec7dd235e8c610096549a93b..3e8fb61ad597cfd90164bf40aefdf0a761a02a13 100644 (file)
@@ -451,7 +451,7 @@ EXPORT_SYMBOL(may_umount);
 void release_mounts(struct list_head *head)
 {
        struct vfsmount *mnt;
-       while(!list_empty(head)) {
+       while (!list_empty(head)) {
                mnt = list_entry(head->next, struct vfsmount, mnt_hash);
                list_del_init(&mnt->mnt_hash);
                if (mnt->mnt_parent != mnt) {
@@ -1526,6 +1526,10 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd)
  * pointed to by put_old must yield the same directory as new_root. No other
  * file system may be mounted on put_old. After all, new_root is a mountpoint.
  *
+ * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem.
+ * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives
+ * in this situation.
+ *
  * Notes:
  *  - we don't move root/cwd if they are not at the root (reason: if something
  *    cared enough to change them, it's probably wrong to force them elsewhere)
index a9f7a8ab1d595d30fcb656eea4a1349a7f324d43..cfd76f431dc0ecba78d8e8bb96c668c402979cc5 100644 (file)
@@ -365,7 +365,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
        spin_lock(&dcache_lock);
        next = parent->d_subdirs.next;
        while (next != &parent->d_subdirs) {
-               dent = list_entry(next, struct dentry, d_child);
+               dent = list_entry(next, struct dentry, d_u.d_child);
                if ((unsigned long)dent->d_fsdata == fpos) {
                        if (dent->d_inode)
                                dget_locked(dent);
index 9e4dc30c2435c207ddce4d2c67311db24429d457..799e5c2bec55bf7d1f401e2b207d2c1e96e5d312 100644 (file)
@@ -196,7 +196,7 @@ ncp_renew_dentries(struct dentry *parent)
        spin_lock(&dcache_lock);
        next = parent->d_subdirs.next;
        while (next != &parent->d_subdirs) {
-               dentry = list_entry(next, struct dentry, d_child);
+               dentry = list_entry(next, struct dentry, d_u.d_child);
 
                if (dentry->d_fsdata == NULL)
                        ncp_age_dentry(server, dentry);
@@ -218,7 +218,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent)
        spin_lock(&dcache_lock);
        next = parent->d_subdirs.next;
        while (next != &parent->d_subdirs) {
-               dentry = list_entry(next, struct dentry, d_child);
+               dentry = list_entry(next, struct dentry, d_u.d_child);
                dentry->d_fsdata = NULL;
                ncp_age_dentry(server, dentry);
                next = next->next;
index e7bd0d92600f6e34e65574bb464f03c45a17a033..3e4ba9cb7f806c7ee8681e97398f51001a288b69 100644 (file)
@@ -644,10 +644,7 @@ int nfs_sync_mapping(struct address_space *mapping)
        if (mapping->nrpages == 0)
                return 0;
        unmap_mapping_range(mapping, 0, 0, 0);
-       ret = filemap_fdatawrite(mapping);
-       if (ret != 0)
-               goto out;
-       ret = filemap_fdatawait(mapping);
+       ret = filemap_write_and_wait(mapping);
        if (ret != 0)
                goto out;
        ret = nfs_wb_all(mapping->host);
@@ -864,8 +861,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
        nfs_begin_data_update(inode);
        /* Write all dirty data if we're changing file permissions or size */
        if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) {
-               if (filemap_fdatawrite(inode->i_mapping) == 0)
-                       filemap_fdatawait(inode->i_mapping);
+               filemap_write_and_wait(inode->i_mapping);
                nfs_wb_all(inode);
        }
        /*
index 985cc53b8dd5b3a49960a7642a48f4f251e9ac99..e897e00c2c9d3c49eb6c1c954df11cceefce392c 100644 (file)
@@ -275,7 +275,9 @@ static int __init root_nfs_parse(char *name, char *buf)
                        case Opt_noacl:
                                nfs_data.flags |= NFS_MOUNT_NOACL;
                                break;
-                       default : 
+                       default:
+                               printk(KERN_WARNING "Root-NFS: unknown "
+                                       "option: %s\n", p);
                                return 0;
                }
        }
index f5ef5ea61a05afdc4c8583e24f9d82e42fe55b64..e8c56a3d9c646d465f8bc0af757c4d47bc3d003c 100644 (file)
@@ -212,11 +212,10 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits;
        mlog(ML_ENTRY, "ENTRY:\n");                                     \
 } while (0)
 
-/* We disable this for old compilers since they don't have support for
- * __builtin_types_compatible_p.
+/*
+ * We disable this for sparse.
  */
-#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) && \
-    !defined(__CHECKER__)
+#if !defined(__CHECKER__)
 #define mlog_exit(st) do {                                                  \
        if (__builtin_types_compatible_p(typeof(st), unsigned long))         \
                mlog(ML_EXIT, "EXIT: %lu\n", (unsigned long) (st));          \
index f53a5b9ffb7dce308f6e0e05d4982d343261564c..75f3329e8a67885036e06ee76e570073cb5e106f 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -194,7 +194,8 @@ out:
        return error;
 }
 
-int do_truncate(struct dentry *dentry, loff_t length, struct file *filp)
+int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
+       struct file *filp)
 {
        int err;
        struct iattr newattrs;
@@ -204,7 +205,7 @@ int do_truncate(struct dentry *dentry, loff_t length, struct file *filp)
                return -EINVAL;
 
        newattrs.ia_size = length;
-       newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+       newattrs.ia_valid = ATTR_SIZE | time_attrs;
        if (filp) {
                newattrs.ia_file = filp;
                newattrs.ia_valid |= ATTR_FILE;
@@ -216,7 +217,7 @@ int do_truncate(struct dentry *dentry, loff_t length, struct file *filp)
        return err;
 }
 
-static inline long do_sys_truncate(const char __user * path, loff_t length)
+static long do_sys_truncate(const char __user * path, loff_t length)
 {
        struct nameidata nd;
        struct inode * inode;
@@ -266,7 +267,7 @@ static inline long do_sys_truncate(const char __user * path, loff_t length)
        error = locks_verify_truncate(inode, NULL, length);
        if (!error) {
                DQUOT_INIT(inode);
-               error = do_truncate(nd.dentry, length, NULL);
+               error = do_truncate(nd.dentry, length, 0, NULL);
        }
        put_write_access(inode);
 
@@ -282,7 +283,7 @@ asmlinkage long sys_truncate(const char __user * path, unsigned long length)
        return do_sys_truncate(path, (long)length);
 }
 
-static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
+static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
 {
        struct inode * inode;
        struct dentry *dentry;
@@ -318,7 +319,7 @@ static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
 
        error = locks_verify_truncate(inode, file, length);
        if (!error)
-               error = do_truncate(dentry, length, file);
+               error = do_truncate(dentry, length, 0, file);
 out_putf:
        fput(file);
 out:
@@ -970,7 +971,7 @@ out:
 
 EXPORT_SYMBOL(get_unused_fd);
 
-static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
+static void __put_unused_fd(struct files_struct *files, unsigned int fd)
 {
        struct fdtable *fdt = files_fdtable(files);
        __FD_CLR(fd, fdt->open_fds);
index aeeec8ba8dd28b9ac4a77ee513fb23423b55d458..f1871f773f642c8f39045431f5e42134e93ea80f 100644 (file)
@@ -103,7 +103,7 @@ static struct vfsmount *propagation_next(struct vfsmount *m,
                struct vfsmount *next;
                struct vfsmount *master = m->mnt_master;
 
-               if ( master == origin->mnt_master ) {
+               if (master == origin->mnt_master) {
                        next = next_peer(m);
                        return ((next == origin) ? NULL : next);
                } else if (m->mnt_slave.next != &master->mnt_slave_list)
index 72b431d0a0a4124d0dbbc52fae842d622bffc3fc..20e5c4509a43896255af91cc4a50a50426069828 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/bitops.h>
 #include <asm/uaccess.h>
 
+#include "internal.h"
+
 static ssize_t proc_file_read(struct file *file, char __user *buf,
                              size_t nbytes, loff_t *ppos);
 static ssize_t proc_file_write(struct file *file, const char __user *buffer,
index e6a818a93f3d75ad0f33f808cd143f068249cf9c..6573f31f1fd9a1efa1747a1f97a768738c88c07f 100644 (file)
@@ -19,7 +19,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-extern void free_proc_entry(struct proc_dir_entry *);
+#include "internal.h"
 
 static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
 {
index 3e55198f980628558cb0465280a6f7d46798dcaa..95a1cf32b838e162bb3e41fe3afd2356bd7b4b22 100644 (file)
@@ -37,6 +37,10 @@ extern int proc_tgid_stat(struct task_struct *, char *);
 extern int proc_pid_status(struct task_struct *, char *);
 extern int proc_pid_statm(struct task_struct *, char *);
 
+void free_proc_entry(struct proc_dir_entry *de);
+
+int proc_init_inodecache(void);
+
 static inline struct task_struct *proc_task(struct inode *inode)
 {
        return PROC_I(inode)->task;
index 5b6b0b6038a7bcaf0e1c2f65ff6faf422278db83..63bf6c00fa0ccc736a2aada6e2c93d9a1e806abe 100644 (file)
@@ -323,6 +323,7 @@ static struct file_operations proc_modules_operations = {
 };
 #endif
 
+#ifdef CONFIG_SLAB
 extern struct seq_operations slabinfo_op;
 extern ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
 static int slabinfo_open(struct inode *inode, struct file *file)
@@ -336,6 +337,7 @@ static struct file_operations proc_slabinfo_operations = {
        .llseek         = seq_lseek,
        .release        = seq_release,
 };
+#endif
 
 static int show_stat(struct seq_file *p, void *v)
 {
@@ -600,7 +602,9 @@ void __init proc_misc_init(void)
        create_seq_entry("partitions", 0, &proc_partitions_operations);
        create_seq_entry("stat", 0, &proc_stat_operations);
        create_seq_entry("interrupts", 0, &proc_interrupts_operations);
+#ifdef CONFIG_SLAB
        create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
+#endif
        create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
        create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
        create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations);
index aef148f099a2892a2826f45ef5182feed2eb327b..68896283c8ae54d79f1e87277322aa2ce83846bc 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/bitops.h>
 #include <linux/smp_lock.h>
 
+#include "internal.h"
+
 struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver;
 
 #ifdef CONFIG_SYSCTL
@@ -36,7 +38,6 @@ static struct file_system_type proc_fs_type = {
        .kill_sb        = kill_anon_super,
 };
 
-extern int __init proc_init_inodecache(void);
 void __init proc_root_init(void)
 {
        int err = proc_init_inodecache();
index 50bd5a8f0446d902cc6161032fde8ac5fcadd7a6..0eaad41f4658f3f4eaaf526078dafa24e1ec0094 100644 (file)
@@ -390,129 +390,12 @@ struct seq_operations proc_pid_smaps_op = {
 };
 
 #ifdef CONFIG_NUMA
-
-struct numa_maps {
-       unsigned long pages;
-       unsigned long anon;
-       unsigned long mapped;
-       unsigned long mapcount_max;
-       unsigned long node[MAX_NUMNODES];
-};
-
-/*
- * Calculate numa node maps for a vma
- */
-static struct numa_maps *get_numa_maps(struct vm_area_struct *vma)
-{
-       int i;
-       struct page *page;
-       unsigned long vaddr;
-       struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL);
-
-       if (!md)
-               return NULL;
-       md->pages = 0;
-       md->anon = 0;
-       md->mapped = 0;
-       md->mapcount_max = 0;
-       for_each_node(i)
-               md->node[i] =0;
-
-       for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) {
-               page = follow_page(vma, vaddr, 0);
-               if (page) {
-                       int count = page_mapcount(page);
-
-                       if (count)
-                               md->mapped++;
-                       if (count > md->mapcount_max)
-                               md->mapcount_max = count;
-                       md->pages++;
-                       if (PageAnon(page))
-                               md->anon++;
-                       md->node[page_to_nid(page)]++;
-               }
-               cond_resched();
-       }
-       return md;
-}
-
-static int show_numa_map(struct seq_file *m, void *v)
-{
-       struct task_struct *task = m->private;
-       struct vm_area_struct *vma = v;
-       struct mempolicy *pol;
-       struct numa_maps *md;
-       struct zone **z;
-       int n;
-       int first;
-
-       if (!vma->vm_mm)
-               return 0;
-
-       md = get_numa_maps(vma);
-       if (!md)
-               return 0;
-
-       seq_printf(m, "%08lx", vma->vm_start);
-       pol = get_vma_policy(task, vma, vma->vm_start);
-       /* Print policy */
-       switch (pol->policy) {
-       case MPOL_PREFERRED:
-               seq_printf(m, " prefer=%d", pol->v.preferred_node);
-               break;
-       case MPOL_BIND:
-               seq_printf(m, " bind={");
-               first = 1;
-               for (z = pol->v.zonelist->zones; *z; z++) {
-
-                       if (!first)
-                               seq_putc(m, ',');
-                       else
-                               first = 0;
-                       seq_printf(m, "%d/%s", (*z)->zone_pgdat->node_id,
-                                       (*z)->name);
-               }
-               seq_putc(m, '}');
-               break;
-       case MPOL_INTERLEAVE:
-               seq_printf(m, " interleave={");
-               first = 1;
-               for_each_node(n) {
-                       if (node_isset(n, pol->v.nodes)) {
-                               if (!first)
-                                       seq_putc(m,',');
-                               else
-                                       first = 0;
-                               seq_printf(m, "%d",n);
-                       }
-               }
-               seq_putc(m, '}');
-               break;
-       default:
-               seq_printf(m," default");
-               break;
-       }
-       seq_printf(m, " MaxRef=%lu Pages=%lu Mapped=%lu",
-                       md->mapcount_max, md->pages, md->mapped);
-       if (md->anon)
-               seq_printf(m," Anon=%lu",md->anon);
-
-       for_each_online_node(n) {
-               if (md->node[n])
-                       seq_printf(m, " N%d=%lu", n, md->node[n]);
-       }
-       seq_putc(m, '\n');
-       kfree(md);
-       if (m->count < m->size)  /* vma is copied successfully */
-               m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0;
-       return 0;
-}
+extern int show_numa_map(struct seq_file *m, void *v);
 
 struct seq_operations proc_pid_numa_maps_op = {
-       .start  = m_start,
-       .next   = m_next,
-       .stop   = m_stop,
-       .show   = show_numa_map
+        .start  = m_start,
+        .next   = m_next,
+        .stop   = m_stop,
+        .show   = show_numa_map
 };
 #endif
index 84e21ffa5ca8e8e695dcfcad6fa5a3eb3bb9e7cc..10187812771ef54960d8038046e5a6e60952ee42 100644 (file)
@@ -185,5 +185,6 @@ void relay_destroy_buf(struct rchan_buf *buf)
 void relay_remove_buf(struct kref *kref)
 {
        struct rchan_buf *buf = container_of(kref, struct rchan_buf, kref);
-       relayfs_remove(buf->dentry);
+       buf->chan->cb->remove_buf_file(buf->dentry);
+       relay_destroy_buf(buf);
 }
index 0f7f88d067adad67b0d846fc9ebfb2f7109f3202..7b7f2cb5f0e1da3d4e05566e1e7890de09e185d8 100644 (file)
 
 static struct vfsmount *               relayfs_mount;
 static int                             relayfs_mount_count;
-static kmem_cache_t *                  relayfs_inode_cachep;
 
 static struct backing_dev_info         relayfs_backing_dev_info = {
        .ra_pages       = 0,    /* No readahead */
        .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 };
 
-static struct inode *relayfs_get_inode(struct super_block *sb, int mode,
-                                      struct rchan *chan)
+static struct inode *relayfs_get_inode(struct super_block *sb,
+                                      int mode,
+                                      struct file_operations *fops,
+                                      void *data)
 {
-       struct rchan_buf *buf = NULL;
        struct inode *inode;
 
-       if (S_ISREG(mode)) {
-               BUG_ON(!chan);
-               buf = relay_create_buf(chan);
-               if (!buf)
-                       return NULL;
-       }
-
        inode = new_inode(sb);
-       if (!inode) {
-               relay_destroy_buf(buf);
+       if (!inode)
                return NULL;
-       }
 
        inode->i_mode = mode;
        inode->i_uid = 0;
@@ -61,8 +52,9 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode,
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        switch (mode & S_IFMT) {
        case S_IFREG:
-               inode->i_fop = &relayfs_file_operations;
-               RELAYFS_I(inode)->buf = buf;
+               inode->i_fop = fops;
+               if (data)
+                       inode->u.generic_ip = data;
                break;
        case S_IFDIR:
                inode->i_op = &simple_dir_inode_operations;
@@ -83,7 +75,8 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode,
  *     @name: the name of the file to create
  *     @parent: parent directory
  *     @mode: mode
- *     @chan: relay channel associated with the file
+ *     @fops: file operations to use for the file
+ *     @data: user-associated data for this file
  *
  *     Returns the new dentry, NULL on failure
  *
@@ -92,7 +85,8 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode,
 static struct dentry *relayfs_create_entry(const char *name,
                                           struct dentry *parent,
                                           int mode,
-                                          struct rchan *chan)
+                                          struct file_operations *fops,
+                                          void *data)
 {
        struct dentry *d;
        struct inode *inode;
@@ -127,7 +121,7 @@ static struct dentry *relayfs_create_entry(const char *name,
                goto release_mount;
        }
 
-       inode = relayfs_get_inode(parent->d_inode->i_sb, mode, chan);
+       inode = relayfs_get_inode(parent->d_inode->i_sb, mode, fops, data);
        if (!inode) {
                d = NULL;
                goto release_mount;
@@ -155,20 +149,26 @@ exit:
  *     @name: the name of the file to create
  *     @parent: parent directory
  *     @mode: mode, if not specied the default perms are used
- *     @chan: channel associated with the file
+ *     @fops: file operations to use for the file
+ *     @data: user-associated data for this file
  *
  *     Returns file dentry if successful, NULL otherwise.
  *
  *     The file will be created user r on behalf of current user.
  */
-struct dentry *relayfs_create_file(const char *name, struct dentry *parent,
-                                  int mode, struct rchan *chan)
+struct dentry *relayfs_create_file(const char *name,
+                                  struct dentry *parent,
+                                  int mode,
+                                  struct file_operations *fops,
+                                  void *data)
 {
+       BUG_ON(!fops);
+
        if (!mode)
                mode = S_IRUSR;
        mode = (mode & S_IALLUGO) | S_IFREG;
 
-       return relayfs_create_entry(name, parent, mode, chan);
+       return relayfs_create_entry(name, parent, mode, fops, data);
 }
 
 /**
@@ -183,7 +183,7 @@ struct dentry *relayfs_create_file(const char *name, struct dentry *parent,
 struct dentry *relayfs_create_dir(const char *name, struct dentry *parent)
 {
        int mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
-       return relayfs_create_entry(name, parent, mode, NULL);
+       return relayfs_create_entry(name, parent, mode, NULL, NULL);
 }
 
 /**
@@ -224,6 +224,17 @@ int relayfs_remove(struct dentry *dentry)
        return error;
 }
 
+/**
+ *     relayfs_remove_file - remove a file from relay filesystem
+ *     @dentry: directory dentry
+ *
+ *     Returns 0 if successful, negative otherwise.
+ */
+int relayfs_remove_file(struct dentry *dentry)
+{
+       return relayfs_remove(dentry);
+}
+
 /**
  *     relayfs_remove_dir - remove a directory in the relay filesystem
  *     @dentry: directory dentry
@@ -236,45 +247,45 @@ int relayfs_remove_dir(struct dentry *dentry)
 }
 
 /**
- *     relayfs_open - open file op for relayfs files
+ *     relay_file_open - open file op for relay files
  *     @inode: the inode
  *     @filp: the file
  *
  *     Increments the channel buffer refcount.
  */
-static int relayfs_open(struct inode *inode, struct file *filp)
+static int relay_file_open(struct inode *inode, struct file *filp)
 {
-       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+       struct rchan_buf *buf = inode->u.generic_ip;
        kref_get(&buf->kref);
+       filp->private_data = buf;
 
        return 0;
 }
 
 /**
- *     relayfs_mmap - mmap file op for relayfs files
+ *     relay_file_mmap - mmap file op for relay files
  *     @filp: the file
  *     @vma: the vma describing what to map
  *
  *     Calls upon relay_mmap_buf to map the file into user space.
  */
-static int relayfs_mmap(struct file *filp, struct vm_area_struct *vma)
+static int relay_file_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-       struct inode *inode = filp->f_dentry->d_inode;
-       return relay_mmap_buf(RELAYFS_I(inode)->buf, vma);
+       struct rchan_buf *buf = filp->private_data;
+       return relay_mmap_buf(buf, vma);
 }
 
 /**
- *     relayfs_poll - poll file op for relayfs files
+ *     relay_file_poll - poll file op for relay files
  *     @filp: the file
  *     @wait: poll table
  *
  *     Poll implemention.
  */
-static unsigned int relayfs_poll(struct file *filp, poll_table *wait)
+static unsigned int relay_file_poll(struct file *filp, poll_table *wait)
 {
        unsigned int mask = 0;
-       struct inode *inode = filp->f_dentry->d_inode;
-       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+       struct rchan_buf *buf = filp->private_data;
 
        if (buf->finalized)
                return POLLERR;
@@ -289,27 +300,27 @@ static unsigned int relayfs_poll(struct file *filp, poll_table *wait)
 }
 
 /**
- *     relayfs_release - release file op for relayfs files
+ *     relay_file_release - release file op for relay files
  *     @inode: the inode
  *     @filp: the file
  *
  *     Decrements the channel refcount, as the filesystem is
  *     no longer using it.
  */
-static int relayfs_release(struct inode *inode, struct file *filp)
+static int relay_file_release(struct inode *inode, struct file *filp)
 {
-       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+       struct rchan_buf *buf = filp->private_data;
        kref_put(&buf->kref, relay_remove_buf);
 
        return 0;
 }
 
 /**
- *     relayfs_read_consume - update the consumed count for the buffer
+ *     relay_file_read_consume - update the consumed count for the buffer
  */
-static void relayfs_read_consume(struct rchan_buf *buf,
-                                size_t read_pos,
-                                size_t bytes_consumed)
+static void relay_file_read_consume(struct rchan_buf *buf,
+                                   size_t read_pos,
+                                   size_t bytes_consumed)
 {
        size_t subbuf_size = buf->chan->subbuf_size;
        size_t n_subbufs = buf->chan->n_subbufs;
@@ -332,9 +343,9 @@ static void relayfs_read_consume(struct rchan_buf *buf,
 }
 
 /**
- *     relayfs_read_avail - boolean, are there unconsumed bytes available?
+ *     relay_file_read_avail - boolean, are there unconsumed bytes available?
  */
-static int relayfs_read_avail(struct rchan_buf *buf, size_t read_pos)
+static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos)
 {
        size_t bytes_produced, bytes_consumed, write_offset;
        size_t subbuf_size = buf->chan->subbuf_size;
@@ -365,16 +376,16 @@ static int relayfs_read_avail(struct rchan_buf *buf, size_t read_pos)
        if (bytes_produced == bytes_consumed)
                return 0;
 
-       relayfs_read_consume(buf, read_pos, 0);
+       relay_file_read_consume(buf, read_pos, 0);
 
        return 1;
 }
 
 /**
- *     relayfs_read_subbuf_avail - return bytes available in sub-buffer
+ *     relay_file_read_subbuf_avail - return bytes available in sub-buffer
  */
-static size_t relayfs_read_subbuf_avail(size_t read_pos,
-                                       struct rchan_buf *buf)
+static size_t relay_file_read_subbuf_avail(size_t read_pos,
+                                          struct rchan_buf *buf)
 {
        size_t padding, avail = 0;
        size_t read_subbuf, read_offset, write_subbuf, write_offset;
@@ -396,14 +407,14 @@ static size_t relayfs_read_subbuf_avail(size_t read_pos,
 }
 
 /**
- *     relayfs_read_start_pos - find the first available byte to read
+ *     relay_file_read_start_pos - find the first available byte to read
  *
  *     If the read_pos is in the middle of padding, return the
  *     position of the first actually available byte, otherwise
  *     return the original value.
  */
-static size_t relayfs_read_start_pos(size_t read_pos,
-                                    struct rchan_buf *buf)
+static size_t relay_file_read_start_pos(size_t read_pos,
+                                       struct rchan_buf *buf)
 {
        size_t read_subbuf, padding, padding_start, padding_end;
        size_t subbuf_size = buf->chan->subbuf_size;
@@ -422,11 +433,11 @@ static size_t relayfs_read_start_pos(size_t read_pos,
 }
 
 /**
- *     relayfs_read_end_pos - return the new read position
+ *     relay_file_read_end_pos - return the new read position
  */
-static size_t relayfs_read_end_pos(struct rchan_buf *buf,
-                                  size_t read_pos,
-                                  size_t count)
+static size_t relay_file_read_end_pos(struct rchan_buf *buf,
+                                     size_t read_pos,
+                                     size_t count)
 {
        size_t read_subbuf, padding, end_pos;
        size_t subbuf_size = buf->chan->subbuf_size;
@@ -445,7 +456,7 @@ static size_t relayfs_read_end_pos(struct rchan_buf *buf,
 }
 
 /**
- *     relayfs_read - read file op for relayfs files
+ *     relay_file_read - read file op for relay files
  *     @filp: the file
  *     @buffer: the userspace buffer
  *     @count: number of bytes to read
@@ -454,23 +465,23 @@ static size_t relayfs_read_end_pos(struct rchan_buf *buf,
  *     Reads count bytes or the number of bytes available in the
  *     current sub-buffer being read, whichever is smaller.
  */
-static ssize_t relayfs_read(struct file *filp,
-                           char __user *buffer,
-                           size_t count,
-                           loff_t *ppos)
+static ssize_t relay_file_read(struct file *filp,
+                              char __user *buffer,
+                              size_t count,
+                              loff_t *ppos)
 {
+       struct rchan_buf *buf = filp->private_data;
        struct inode *inode = filp->f_dentry->d_inode;
-       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
        size_t read_start, avail;
        ssize_t ret = 0;
        void *from;
 
        down(&inode->i_sem);
-       if(!relayfs_read_avail(buf, *ppos))
+       if(!relay_file_read_avail(buf, *ppos))
                goto out;
 
-       read_start = relayfs_read_start_pos(*ppos, buf);
-       avail = relayfs_read_subbuf_avail(read_start, buf);
+       read_start = relay_file_read_start_pos(*ppos, buf);
+       avail = relay_file_read_subbuf_avail(read_start, buf);
        if (!avail)
                goto out;
 
@@ -480,58 +491,25 @@ static ssize_t relayfs_read(struct file *filp,
                ret = -EFAULT;
                goto out;
        }
-       relayfs_read_consume(buf, read_start, count);
-       *ppos = relayfs_read_end_pos(buf, read_start, count);
+       relay_file_read_consume(buf, read_start, count);
+       *ppos = relay_file_read_end_pos(buf, read_start, count);
 out:
        up(&inode->i_sem);
        return ret;
 }
 
-/**
- *     relayfs alloc_inode() implementation
- */
-static struct inode *relayfs_alloc_inode(struct super_block *sb)
-{
-       struct relayfs_inode_info *p = kmem_cache_alloc(relayfs_inode_cachep, SLAB_KERNEL);
-       if (!p)
-               return NULL;
-       p->buf = NULL;
-
-       return &p->vfs_inode;
-}
-
-/**
- *     relayfs destroy_inode() implementation
- */
-static void relayfs_destroy_inode(struct inode *inode)
-{
-       if (RELAYFS_I(inode)->buf)
-               relay_destroy_buf(RELAYFS_I(inode)->buf);
-
-       kmem_cache_free(relayfs_inode_cachep, RELAYFS_I(inode));
-}
-
-static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
-{
-       struct relayfs_inode_info *i = p;
-       if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
-               inode_init_once(&i->vfs_inode);
-}
-
-struct file_operations relayfs_file_operations = {
-       .open           = relayfs_open,
-       .poll           = relayfs_poll,
-       .mmap           = relayfs_mmap,
-       .read           = relayfs_read,
+struct file_operations relay_file_operations = {
+       .open           = relay_file_open,
+       .poll           = relay_file_poll,
+       .mmap           = relay_file_mmap,
+       .read           = relay_file_read,
        .llseek         = no_llseek,
-       .release        = relayfs_release,
+       .release        = relay_file_release,
 };
 
 static struct super_operations relayfs_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
-       .alloc_inode    = relayfs_alloc_inode,
-       .destroy_inode  = relayfs_destroy_inode,
 };
 
 static int relayfs_fill_super(struct super_block * sb, void * data, int silent)
@@ -544,7 +522,7 @@ static int relayfs_fill_super(struct super_block * sb, void * data, int silent)
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
        sb->s_magic = RELAYFS_MAGIC;
        sb->s_op = &relayfs_ops;
-       inode = relayfs_get_inode(sb, mode, NULL);
+       inode = relayfs_get_inode(sb, mode, NULL, NULL);
 
        if (!inode)
                return -ENOMEM;
@@ -575,33 +553,27 @@ static struct file_system_type relayfs_fs_type = {
 
 static int __init init_relayfs_fs(void)
 {
-       int err;
-
-       relayfs_inode_cachep = kmem_cache_create("relayfs_inode_cache",
-                               sizeof(struct relayfs_inode_info), 0,
-                               0, init_once, NULL);
-       if (!relayfs_inode_cachep)
-               return -ENOMEM;
-
-       err = register_filesystem(&relayfs_fs_type);
-       if (err)
-               kmem_cache_destroy(relayfs_inode_cachep);
-
-       return err;
+       return register_filesystem(&relayfs_fs_type);
 }
 
 static void __exit exit_relayfs_fs(void)
 {
+
+
+
+
+
        unregister_filesystem(&relayfs_fs_type);
-       kmem_cache_destroy(relayfs_inode_cachep);
 }
 
 module_init(init_relayfs_fs)
 module_exit(exit_relayfs_fs)
 
-EXPORT_SYMBOL_GPL(relayfs_file_operations);
+EXPORT_SYMBOL_GPL(relay_file_operations);
 EXPORT_SYMBOL_GPL(relayfs_create_dir);
 EXPORT_SYMBOL_GPL(relayfs_remove_dir);
+EXPORT_SYMBOL_GPL(relayfs_create_file);
+EXPORT_SYMBOL_GPL(relayfs_remove_file);
 
 MODULE_AUTHOR("Tom Zanussi <zanussi@us.ibm.com> and Karim Yaghmour <karim@opersys.com>");
 MODULE_DESCRIPTION("Relay Filesystem");
index 2a6f7f12b7f9458a96f19be651f1d05bbef4f601..abf3ceaace4916822cbd91ba233c2709d43cae91 100644 (file)
@@ -80,11 +80,34 @@ static void buf_unmapped_default_callback(struct rchan_buf *buf,
 {
 }
 
+/*
+ * create_buf_file_create() default callback.  Creates file to represent buf.
+ */
+static struct dentry *create_buf_file_default_callback(const char *filename,
+                                                      struct dentry *parent,
+                                                      int mode,
+                                                      struct rchan_buf *buf,
+                                                      int *is_global)
+{
+       return relayfs_create_file(filename, parent, mode,
+                                  &relay_file_operations, buf);
+}
+
+/*
+ * remove_buf_file() default callback.  Removes file representing relay buffer.
+ */
+static int remove_buf_file_default_callback(struct dentry *dentry)
+{
+       return relayfs_remove(dentry);
+}
+
 /* relay channel default callbacks */
 static struct rchan_callbacks default_channel_callbacks = {
        .subbuf_start = subbuf_start_default_callback,
        .buf_mapped = buf_mapped_default_callback,
        .buf_unmapped = buf_unmapped_default_callback,
+       .create_buf_file = create_buf_file_default_callback,
+       .remove_buf_file = remove_buf_file_default_callback,
 };
 
 /**
@@ -148,14 +171,16 @@ static inline void __relay_reset(struct rchan_buf *buf, unsigned int init)
 void relay_reset(struct rchan *chan)
 {
        unsigned int i;
+       struct rchan_buf *prev = NULL;
 
        if (!chan)
                return;
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (!chan->buf[i])
-                       continue;
+               if (!chan->buf[i] || chan->buf[i] == prev)
+                       break;
                __relay_reset(chan->buf[i], 0);
+               prev = chan->buf[i];
        }
 }
 
@@ -166,17 +191,27 @@ void relay_reset(struct rchan *chan)
  */
 static struct rchan_buf *relay_open_buf(struct rchan *chan,
                                        const char *filename,
-                                       struct dentry *parent)
+                                       struct dentry *parent,
+                                       int *is_global)
 {
        struct rchan_buf *buf;
        struct dentry *dentry;
 
+       if (*is_global)
+               return chan->buf[0];
+
+       buf = relay_create_buf(chan);
+       if (!buf)
+               return NULL;
+
        /* Create file in fs */
-       dentry = relayfs_create_file(filename, parent, S_IRUSR, chan);
-       if (!dentry)
+       dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR,
+                                          buf, is_global);
+       if (!dentry) {
+               relay_destroy_buf(buf);
                return NULL;
+       }
 
-       buf = RELAYFS_I(dentry->d_inode)->buf;
        buf->dentry = dentry;
        __relay_reset(buf, 1);
 
@@ -214,6 +249,10 @@ static inline void setup_callbacks(struct rchan *chan,
                cb->buf_mapped = buf_mapped_default_callback;
        if (!cb->buf_unmapped)
                cb->buf_unmapped = buf_unmapped_default_callback;
+       if (!cb->create_buf_file)
+               cb->create_buf_file = create_buf_file_default_callback;
+       if (!cb->remove_buf_file)
+               cb->remove_buf_file = remove_buf_file_default_callback;
        chan->cb = cb;
 }
 
@@ -241,6 +280,7 @@ struct rchan *relay_open(const char *base_filename,
        unsigned int i;
        struct rchan *chan;
        char *tmpname;
+       int is_global = 0;
 
        if (!base_filename)
                return NULL;
@@ -265,7 +305,8 @@ struct rchan *relay_open(const char *base_filename,
 
        for_each_online_cpu(i) {
                sprintf(tmpname, "%s%d", base_filename, i);
-               chan->buf[i] = relay_open_buf(chan, tmpname, parent);
+               chan->buf[i] = relay_open_buf(chan, tmpname, parent,
+                                             &is_global);
                chan->buf[i]->cpu = i;
                if (!chan->buf[i])
                        goto free_bufs;
@@ -279,6 +320,8 @@ free_bufs:
                if (!chan->buf[i])
                        break;
                relay_close_buf(chan->buf[i]);
+               if (is_global)
+                       break;
        }
        kfree(tmpname);
 
@@ -388,14 +431,16 @@ void relay_destroy_channel(struct kref *kref)
 void relay_close(struct rchan *chan)
 {
        unsigned int i;
+       struct rchan_buf *prev = NULL;
 
        if (!chan)
                return;
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (!chan->buf[i])
-                       continue;
+               if (!chan->buf[i] || chan->buf[i] == prev)
+                       break;
                relay_close_buf(chan->buf[i]);
+               prev = chan->buf[i];
        }
 
        if (chan->last_toobig)
@@ -415,14 +460,16 @@ void relay_close(struct rchan *chan)
 void relay_flush(struct rchan *chan)
 {
        unsigned int i;
+       struct rchan_buf *prev = NULL;
 
        if (!chan)
                return;
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (!chan->buf[i])
-                       continue;
+               if (!chan->buf[i] || chan->buf[i] == prev)
+                       break;
                relay_switch_subbuf(chan->buf[i], 0);
+               prev = chan->buf[i];
        }
 }
 
index 703503fa22b6f3fce22b43837b5abf5bc987e99d..0993d3e5753b59d172ddb2f8f67838d5766297ef 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef _RELAY_H
 #define _RELAY_H
 
-struct dentry *relayfs_create_file(const char *name,
-                                  struct dentry *parent,
-                                  int mode,
-                                  struct rchan *chan);
 extern int relayfs_remove(struct dentry *dentry);
 extern int relay_buf_empty(struct rchan_buf *buf);
 extern void relay_destroy_channel(struct kref *kref);
index c74f382dabba2782af852cb15d67782f1ab10335..0a13859fd57bc0cb8d5302e2fc933bd3a943f88d 100644 (file)
@@ -418,7 +418,7 @@ static int
 romfs_readpage(struct file *file, struct page * page)
 {
        struct inode *inode = page->mapping->host;
-       unsigned long offset, avail, readlen;
+       loff_t offset, avail, readlen;
        void *buf;
        int result = -EIO;
 
@@ -429,8 +429,8 @@ romfs_readpage(struct file *file, struct page * page)
                goto err_out;
 
        /* 32 bit warning -- but not for us :) */
-       offset = page->index << PAGE_CACHE_SHIFT;
-       if (offset < inode->i_size) {
+       offset = page_offset(page);
+       if (offset < i_size_read(inode)) {
                avail = inode->i_size-offset;
                readlen = min_t(unsigned long, avail, PAGE_SIZE);
                if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) {
index f3e6b81288abf4b407daa02debcb45b10f35be2a..74b86d9725a63cce6a65ad53514cecc3d9437a82 100644 (file)
@@ -66,7 +66,7 @@ smb_invalidate_dircache_entries(struct dentry *parent)
        spin_lock(&dcache_lock);
        next = parent->d_subdirs.next;
        while (next != &parent->d_subdirs) {
-               dentry = list_entry(next, struct dentry, d_child);
+               dentry = list_entry(next, struct dentry, d_u.d_child);
                dentry->d_fsdata = NULL;
                smb_age_dentry(server, dentry);
                next = next->next;
@@ -100,7 +100,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
        spin_lock(&dcache_lock);
        next = parent->d_subdirs.next;
        while (next != &parent->d_subdirs) {
-               dent = list_entry(next, struct dentry, d_child);
+               dent = list_entry(next, struct dentry, d_u.d_child);
                if ((unsigned long)dent->d_fsdata == fpos) {
                        if (dent->d_inode)
                                dget_locked(dent);
index b4fcfa8b55a149d3e16e995cab6cae0342fb3bf5..7042e62726a419eef23cd42750a86677d20d9d71 100644 (file)
@@ -209,8 +209,8 @@ smb_updatepage(struct file *file, struct page *page, unsigned long offset,
 {
        struct dentry *dentry = file->f_dentry;
 
-       DEBUG1("(%s/%s %d@%ld)\n", DENTRY_PATH(dentry), 
-              count, (page->index << PAGE_CACHE_SHIFT)+offset);
+       DEBUG1("(%s/%s %d@%lld)\n", DENTRY_PATH(dentry), count,
+               ((unsigned long long)page->index << PAGE_CACHE_SHIFT) + offset);
 
        return smb_writepage_sync(dentry->d_inode, page, offset, count);
 }
@@ -374,8 +374,7 @@ smb_file_release(struct inode *inode, struct file * file)
                /* We must flush any dirty pages now as we won't be able to
                   write anything after close. mmap can trigger this.
                   "openers" should perhaps include mmap'ers ... */
-               filemap_fdatawrite(inode->i_mapping);
-               filemap_fdatawait(inode->i_mapping);
+               filemap_write_and_wait(inode->i_mapping);
                smb_close(inode);
        }
        unlock_kernel();
index 10b994428fef29e6c43747ed2ae5345d264f8bbb..6ec88bf59b2def7aa402d060c0fd84dc770741a6 100644 (file)
@@ -697,8 +697,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr)
                        DENTRY_PATH(dentry),
                        (long) inode->i_size, (long) attr->ia_size);
 
-               filemap_fdatawrite(inode->i_mapping);
-               filemap_fdatawait(inode->i_mapping);
+               filemap_write_and_wait(inode->i_mapping);
 
                error = smb_open(dentry, O_WRONLY);
                if (error)
index 38ab558835c4ba1348dad8738bcc1df7997df598..d6baec0f24ad5fb28f3bb34ba65e11428c186989 100644 (file)
@@ -3113,7 +3113,7 @@ smb_proc_setattr_unix(struct dentry *d, struct iattr *attr,
        LSET(data, 32, SMB_TIME_NO_CHANGE);
        LSET(data, 40, SMB_UID_NO_CHANGE);
        LSET(data, 48, SMB_GID_NO_CHANGE);
-       LSET(data, 56, smb_filetype_from_mode(attr->ia_mode));
+       DSET(data, 56, smb_filetype_from_mode(attr->ia_mode));
        LSET(data, 60, major);
        LSET(data, 68, minor);
        LSET(data, 76, 0);
index 5a347a4f673a4aa19294b8436a25adc71ba07a38..0a30e51692cf69579bf51670bb2a6f8cb56f0626 100644 (file)
@@ -700,8 +700,7 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
 
                s->s_flags = flags;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
-               s->s_old_blocksize = block_size(bdev);
-               sb_set_blocksize(s, s->s_old_blocksize);
+               sb_set_blocksize(s, block_size(bdev));
                error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
                if (error) {
                        up_write(&s->s_umount);
index 69a085abad6f8b12ffece70c95b1db0c5b5502ba..cce8b05cba5a03da1068a462aec9b4228e6a2986 100644 (file)
@@ -103,7 +103,7 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
                        offset = (char *)de - kaddr;
 
                        over = filldir(dirent, name, strnlen(name,SYSV_NAMELEN),
-                                       (n<<PAGE_CACHE_SHIFT) | offset,
+                                       ((loff_t)n<<PAGE_CACHE_SHIFT) | offset,
                                        fs16_to_cpu(SYSV_SB(sb), de->inode),
                                        DT_UNKNOWN);
                        if (over) {
@@ -115,7 +115,7 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
        }
 
 done:
-       filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
+       filp->f_pos = ((loff_t)n << PAGE_CACHE_SHIFT) | offset;
        unlock_kernel();
        return 0;
 }
index 6598a5037ac80c915bcdbf08269e7a855d051686..4fae57d9d1151008fa690a889c98ee4e0c737ecd 100644 (file)
@@ -41,7 +41,7 @@
 #define uint(x) xuint(x)
 #define xuint(x) __le ## x
 
-extern 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);
index 4014f17d382e70ddc3662521515347748af01910..395e582ee5425cab1ad65177d5f8c02bedc9e932 100644 (file)
@@ -1957,11 +1957,6 @@ int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t
                printk(KERN_ERR "udf: inode_bmap: block < 0\n");
                return -1;
        }
-       if (!inode)
-       {
-               printk(KERN_ERR "udf: inode_bmap: NULL inode\n");
-               return -1;
-       }
 
        *extoffset = 0;
        *elen = 0;
index 54828ebcf1bacda4d1c94dc4461cd99d8264234d..2ba11a9aa995964721b9edd08ee1a0b1b3c0f688 100644 (file)
@@ -1296,8 +1296,10 @@ static ssize_t ufs_quota_write(struct super_block *sb, int type,
                blk++;
        }
 out:
-       if (len == towrite)
+       if (len == towrite) {
+               up(&inode->i_sem);
                return err;
+       }
        if (inode->i_size < off+len-towrite)
                i_size_write(inode, off+len-towrite);
        inode->i_version++;
index f89340c61bf289ddc1dd81ce9580e3b97a36ef41..4fa4b1a5187e095fbe9a3dfb9d324d9aad9c4d5b 100644 (file)
@@ -79,8 +79,7 @@ fs_flushinval_pages(
        struct inode    *ip = LINVFS_GET_IP(vp);
 
        if (VN_CACHED(vp)) {
-               filemap_fdatawrite(ip->i_mapping);
-               filemap_fdatawait(ip->i_mapping);
+               filemap_write_and_wait(ip->i_mapping);
 
                truncate_inode_pages(ip->i_mapping, first);
        }
index 158829ca56f699deb90bd6733f2b9040683322e0..f40d4391fcfcc0f89cdd2a5f658906f88b5fbca4 100644 (file)
  * By comparing each compnent, we don't have to worry about extra
  * endian issues in treating two 32 bit numbers as one 64 bit number
  */
-static
-#if defined(__GNUC__) && (__GNUC__ == 2) && ( (__GNUC_MINOR__ == 95) || (__GNUC_MINOR__ == 96))
-__attribute__((unused))        /* gcc 2.95, 2.96 miscompile this when inlined */
-#else
-__inline__
-#endif
-xfs_lsn_t      _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
+static inline xfs_lsn_t        _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
 {
        if (CYCLE_LSN(lsn1) != CYCLE_LSN(lsn2))
                return (CYCLE_LSN(lsn1)<CYCLE_LSN(lsn2))? -999 : 999;
index e69b29501a5f2c5d477f6b375b6c0b6f69f9ea6e..e6d4d1695e256cdccce5a74d1b87edc8e99b8542 100644 (file)
@@ -20,6 +20,5 @@
 
 #define L1_CACHE_ALIGN(x)  (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 #define SMP_CACHE_BYTES    L1_CACHE_BYTES
-#define L1_CACHE_SHIFT_MAX L1_CACHE_SHIFT
 
 #endif
index 0a4a8b40dfcd7a623e6ad0f95c3c3d4a7e969a76..00c6f57ad9a7a43ea189fb4b14a07f6218277872 100644 (file)
@@ -98,9 +98,7 @@
 #undef inline
 #undef __inline__
 #undef __inline
-#if __GNUC__ == 3 && __GNUC_MINOR__ >= 1 || __GNUC__ > 3
 #undef __always_inline
 #define __always_inline                inline __attribute__((always_inline))
-#endif
 
 #endif /* __ALPHA_COMPILER_H */
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 059780a7d3d7898b750a9f6f7265a0cb2687d2fd..bb1a7a3abb8b55ac2c80aa10d608299eac295ad0 100644 (file)
@@ -77,7 +77,6 @@ unsigned long get_wchan(struct task_struct *p);
 #define spin_lock_prefetch(lock)       do { } while (0)
 #endif
 
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
 extern inline void prefetch(const void *ptr)  
 { 
        __builtin_prefetch(ptr, 0, 3);
@@ -95,24 +94,4 @@ extern inline void spin_lock_prefetch(const void *ptr)
 }
 #endif
 
-#else
-extern inline void prefetch(const void *ptr)  
-{ 
-       __asm__ ("ldl $31,%0" : : "m"(*(char *)ptr)); 
-}
-
-extern inline void prefetchw(const void *ptr)  
-{
-       __asm__ ("ldq $31,%0" : : "m"(*(char *)ptr)); 
-}
-
-#ifdef CONFIG_SMP
-extern inline void spin_lock_prefetch(const void *ptr)  
-{
-       __asm__ ("ldq $31,%0" : : "m"(*(char *)ptr)); 
-}
-#endif
-
-#endif /* GCC 3.1 */
-
 #endif /* __ASM_ALPHA_PROCESSOR_H */
index 8d161f7c87ff7a059d26c119ece799f4675403dd..31332c8ac04ea0a21d184ff61db9044a094506a7 100644 (file)
@@ -7,9 +7,4 @@
 #define L1_CACHE_SHIFT         5
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
-/*
- * largest L1 which this arch supports
- */
-#define L1_CACHE_SHIFT_MAX     5
-
 #endif
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 59975ee43cf139138503288801c7d8758dada859..7772432d3fd7750506943eaf88ea7eda9e720a7d 100644 (file)
@@ -25,10 +25,14 @@ extern void disable_irq_nosync(unsigned int);
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
-#define __IRQT_FALEDGE (1 << 0)
-#define __IRQT_RISEDGE (1 << 1)
-#define __IRQT_LOWLVL  (1 << 2)
-#define __IRQT_HIGHLVL (1 << 3)
+/*
+ * These correspond with the SA_TRIGGER_* defines, and therefore the
+ * IRQRESOURCE_IRQ_* defines.
+ */
+#define __IRQT_RISEDGE (1 << 0)
+#define __IRQT_FALEDGE (1 << 1)
+#define __IRQT_HIGHLVL (1 << 2)
+#define __IRQT_LOWLVL  (1 << 3)
 
 #define IRQT_NOEDGE    (0)
 #define IRQT_RISING    (__IRQT_RISEDGE)
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 1d1d1ba65b1ae6c258b7b055b1b5ae5e686dc39a..aea27184d2d26645a14bda4e75e58bd2aeaaf7db 100644 (file)
@@ -4,6 +4,5 @@
 /* Etrax 100LX have 32-byte cache-lines. */
 #define L1_CACHE_BYTES 32
 #define L1_CACHE_SHIFT 5
-#define L1_CACHE_SHIFT_MAX 5
 
 #endif /* _ASM_ARCH_CACHE_H */
index 4fed8d62ccc88b251f67e1e101df0281370ef4a9..80b236b15319b6a1ea506949f429ceb332e6122d 100644 (file)
@@ -4,6 +4,5 @@
 /* A cache-line is 32 bytes. */
 #define L1_CACHE_BYTES 32
 #define L1_CACHE_SHIFT 5
-#define L1_CACHE_SHIFT_MAX 5
 
 #endif /* _ASM_CRIS_ARCH_CACHE_H */
index 8eff51349ae75235f59764974031bf73f9705210..cbf1a98f012975d67ca8b3b5efd04b896ccc38b8 100644 (file)
@@ -153,7 +153,7 @@ dma_set_mask(struct device *dev, u64 mask)
 static inline int
 dma_get_cache_alignment(void)
 {
-       return (1 << L1_CACHE_SHIFT_MAX);
+       return (1 << INTERNODE_CACHE_SHIFT);
 }
 
 #define dma_is_consistent(d)   (1)
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 3f54fea2b051b65570b556891c04d527a94f47e7..9c9e9499cfd866b8699cecc8bfcabbbae9670566 100644 (file)
@@ -218,51 +218,12 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig
        __typeof__(*(ptr)) __xg_orig;                                           \
                                                                                \
        switch (sizeof(__xg_orig)) {                                            \
-       case 1:                                                                 \
-               asm volatile(                                                   \
-                       "0:                                             \n"     \
-                       "       orcc            gr0,gr0,gr0,icc3        \n"     \
-                       "       ckeq            icc3,cc7                \n"     \
-                       "       ldub.p          %M0,%1                  \n"     \
-                       "       orcr            cc7,cc7,cc3             \n"     \
-                       "       cstb.p          %2,%M0          ,cc3,#1 \n"     \
-                       "       corcc           gr29,gr29,gr0   ,cc3,#1 \n"     \
-                       "       beq             icc3,#0,0b              \n"     \
-                       : "+U"(*__xg_ptr), "=&r"(__xg_orig)                     \
-                       : "r"(x)                                                \
-                       : "memory", "cc7", "cc3", "icc3"                        \
-                       );                                                      \
-               break;                                                          \
-                                                                               \
-       case 2:                                                                 \
-               asm volatile(                                                   \
-                       "0:                                             \n"     \
-                       "       orcc            gr0,gr0,gr0,icc3        \n"     \
-                       "       ckeq            icc3,cc7                \n"     \
-                       "       lduh.p          %M0,%1                  \n"     \
-                       "       orcr            cc7,cc7,cc3             \n"     \
-                       "       csth.p          %2,%M0          ,cc3,#1 \n"     \
-                       "       corcc           gr29,gr29,gr0   ,cc3,#1 \n"     \
-                       "       beq             icc3,#0,0b              \n"     \
-                       : "+U"(*__xg_ptr), "=&r"(__xg_orig)                     \
-                       : "r"(x)                                                \
-                       : "memory", "cc7", "cc3", "icc3"                        \
-                       );                                                      \
-               break;                                                          \
-                                                                               \
        case 4:                                                                 \
                asm volatile(                                                   \
-                       "0:                                             \n"     \
-                       "       orcc            gr0,gr0,gr0,icc3        \n"     \
-                       "       ckeq            icc3,cc7                \n"     \
-                       "       ld.p            %M0,%1                  \n"     \
-                       "       orcr            cc7,cc7,cc3             \n"     \
-                       "       cst.p           %2,%M0          ,cc3,#1 \n"     \
-                       "       corcc           gr29,gr29,gr0   ,cc3,#1 \n"     \
-                       "       beq             icc3,#0,0b              \n"     \
-                       : "+U"(*__xg_ptr), "=&r"(__xg_orig)                     \
+                       "swap%I0 %2,%M0"                                        \
+                       : "+m"(*__xg_ptr), "=&r"(__xg_orig)                     \
                        : "r"(x)                                                \
-                       : "memory", "cc7", "cc3", "icc3"                        \
+                       : "memory"                                              \
                        );                                                      \
                break;                                                          \
                                                                                \
@@ -277,8 +238,6 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig
 
 #else
 
-extern uint8_t  __xchg_8 (uint8_t i,  volatile void *v);
-extern uint16_t __xchg_16(uint16_t i, volatile void *v);
 extern uint32_t __xchg_32(uint32_t i, volatile void *v);
 
 #define xchg(ptr, x)                                                                           \
@@ -287,8 +246,6 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
        __typeof__(*(ptr)) __xg_orig;                                                           \
                                                                                                \
        switch (sizeof(__xg_orig)) {                                                            \
-       case 1: __xg_orig = (__typeof__(*(ptr))) __xchg_8 ((uint8_t)  x, __xg_ptr);     break;  \
-       case 2: __xg_orig = (__typeof__(*(ptr))) __xchg_16((uint16_t) x, __xg_ptr);     break;  \
        case 4: __xg_orig = (__typeof__(*(ptr))) __xchg_32((uint32_t) x, __xg_ptr);     break;  \
        default:                                                                                \
                __xg_orig = 0;                                                                  \
@@ -318,46 +275,6 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
        __typeof__(*(ptr)) __xg_new = (new);                                    \
                                                                                \
        switch (sizeof(__xg_orig)) {                                            \
-       case 1:                                                                 \
-               asm volatile(                                                   \
-                       "0:                                             \n"     \
-                       "       orcc            gr0,gr0,gr0,icc3        \n"     \
-                       "       ckeq            icc3,cc7                \n"     \
-                       "       ldub.p          %M0,%1                  \n"     \
-                       "       orcr            cc7,cc7,cc3             \n"     \
-                       "       sub%I4          %1,%4,%2                \n"     \
-                       "       sllcc           %2,#24,gr0,icc0         \n"     \
-                       "       bne             icc0,#0,1f              \n"     \
-                       "       cstb.p          %3,%M0          ,cc3,#1 \n"     \
-                       "       corcc           gr29,gr29,gr0   ,cc3,#1 \n"     \
-                       "       beq             icc3,#0,0b              \n"     \
-                       "1:                                             \n"     \
-                       : "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp)    \
-                       : "r"(__xg_new), "NPr"(__xg_test)                       \
-                       : "memory", "cc7", "cc3", "icc3", "icc0"                \
-                       );                                                      \
-               break;                                                          \
-                                                                               \
-       case 2:                                                                 \
-               asm volatile(                                                   \
-                       "0:                                             \n"     \
-                       "       orcc            gr0,gr0,gr0,icc3        \n"     \
-                       "       ckeq            icc3,cc7                \n"     \
-                       "       lduh.p          %M0,%1                  \n"     \
-                       "       orcr            cc7,cc7,cc3             \n"     \
-                       "       sub%I4          %1,%4,%2                \n"     \
-                       "       sllcc           %2,#16,gr0,icc0         \n"     \
-                       "       bne             icc0,#0,1f              \n"     \
-                       "       csth.p          %3,%M0          ,cc3,#1 \n"     \
-                       "       corcc           gr29,gr29,gr0   ,cc3,#1 \n"     \
-                       "       beq             icc3,#0,0b              \n"     \
-                       "1:                                             \n"     \
-                       : "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp)    \
-                       : "r"(__xg_new), "NPr"(__xg_test)                       \
-                       : "memory", "cc7", "cc3", "icc3", "icc0"                \
-                       );                                                      \
-               break;                                                          \
-                                                                               \
        case 4:                                                                 \
                asm volatile(                                                   \
                        "0:                                             \n"     \
@@ -388,8 +305,6 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
 
 #else
 
-extern uint8_t  __cmpxchg_8 (uint8_t *v,  uint8_t test,  uint8_t new);
-extern uint16_t __cmpxchg_16(uint16_t *v, uint16_t test, uint16_t new);
 extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
 
 #define cmpxchg(ptr, test, new)                                                        \
@@ -400,8 +315,6 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
        __typeof__(*(ptr)) __xg_new = (new);                                    \
                                                                                \
        switch (sizeof(__xg_orig)) {                                            \
-       case 1: __xg_orig = __cmpxchg_8 (__xg_ptr, __xg_test, __xg_new); break; \
-       case 2: __xg_orig = __cmpxchg_16(__xg_ptr, __xg_test, __xg_new); break; \
        case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break; \
        default:                                                                \
                __xg_orig = 0;                                                  \
@@ -414,7 +327,7 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
 
 #endif
 
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 
 #define atomic_add_unless(v, a, u)                             \
 ({                                                             \
@@ -424,6 +337,7 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
                c = old;                                        \
        c != (u);                                               \
 })
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #include <asm-generic/atomic.h>
index 074c0d5770ebd4cb6f5f4f64645323da6bd812fc..451712cc30600901ba0cae6b28623f8d546debaf 100644 (file)
@@ -12,6 +12,7 @@
 #define _ASM_BUG_H
 
 #include <linux/config.h>
+#include <linux/linkage.h>
 
 #ifdef CONFIG_BUG
 /*
index 5003e017fd1ecae1905950c1fb49f75e8aca37c1..e9fc1d47797e295664a0fa5f025b80bdce7fb50b 100644 (file)
@@ -23,7 +23,7 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t
  * returns, or alternatively stop on the first sg_dma_len(sg) which
  * is 0.
  */
-#define sg_dma_address(sg)     ((unsigned long) (page_to_phys((sg)->page) + (sg)->offset))
+#define sg_dma_address(sg)     ((sg)->dma_address)
 #define sg_dma_len(sg)         ((sg)->length)
 
 /*
index 48829f72724229513c4c7720dbe4306cf32e996c..075369b1a34baba46412a739b95b2fe66517111d 100644 (file)
@@ -18,6 +18,7 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <linux/types.h>
 #include <asm/virtconvert.h>
 #include <asm/string.h>
 #include <asm/mb-regs.h>
@@ -104,6 +105,8 @@ static inline void __insl(unsigned long addr, void *buf, int len, int swap)
                __insl_sw(addr, buf, len);
 }
 
+#define mmiowb() mb()
+
 /*
  *     make the short names macros so specific devices
  *     can override them as required
@@ -209,6 +212,10 @@ static inline uint32_t readl(const volatile void __iomem *addr)
        return ret;
 }
 
+#define readb_relaxed readb
+#define readw_relaxed readw
+#define readl_relaxed readl
+
 static inline void writeb(uint8_t datum, volatile void __iomem *addr)
 {
        __builtin_write8((volatile uint8_t __force *) addr, datum);
@@ -268,11 +275,106 @@ static inline void __iomem *ioremap_fullcache(unsigned long physaddr, unsigned l
 
 extern void iounmap(void __iomem *addr);
 
+static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+       return (void __iomem *) port;
+}
+
+static inline void ioport_unmap(void __iomem *p)
+{
+}
+
 static inline void flush_write_buffers(void)
 {
        __asm__ __volatile__ ("membar" : : :"memory");
 }
 
+/*
+ * do appropriate I/O accesses for token type
+ */
+static inline unsigned int ioread8(void __iomem *p)
+{
+       return __builtin_read8(p);
+}
+
+static inline unsigned int ioread16(void __iomem *p)
+{
+       uint16_t ret = __builtin_read16(p);
+       if (__is_PCI_addr(p))
+               ret = _swapw(ret);
+       return ret;
+}
+
+static inline unsigned int ioread32(void __iomem *p)
+{
+       uint32_t ret = __builtin_read32(p);
+       if (__is_PCI_addr(p))
+               ret = _swapl(ret);
+       return ret;
+}
+
+static inline void iowrite8(u8 val, void __iomem *p)
+{
+       __builtin_write8(p, val);
+       if (__is_PCI_MEM(p))
+               __flush_PCI_writes();
+}
+
+static inline void iowrite16(u16 val, void __iomem *p)
+{
+       if (__is_PCI_addr(p))
+               val = _swapw(val);
+       __builtin_write16(p, val);
+       if (__is_PCI_MEM(p))
+               __flush_PCI_writes();
+}
+
+static inline void iowrite32(u32 val, void __iomem *p)
+{
+       if (__is_PCI_addr(p))
+               val = _swapl(val);
+       __builtin_write32(p, val);
+       if (__is_PCI_MEM(p))
+               __flush_PCI_writes();
+}
+
+static inline void ioread8_rep(void __iomem *p, void *dst, unsigned long count)
+{
+       io_insb((unsigned long) p, dst, count);
+}
+
+static inline void ioread16_rep(void __iomem *p, void *dst, unsigned long count)
+{
+       io_insw((unsigned long) p, dst, count);
+}
+
+static inline void ioread32_rep(void __iomem *p, void *dst, unsigned long count)
+{
+       __insl_ns((unsigned long) p, dst, count);
+}
+
+static inline void iowrite8_rep(void __iomem *p, const void *src, unsigned long count)
+{
+       io_outsb((unsigned long) p, src, count);
+}
+
+static inline void iowrite16_rep(void __iomem *p, const void *src, unsigned long count)
+{
+       io_outsw((unsigned long) p, src, count);
+}
+
+static inline void iowrite32_rep(void __iomem *p, const void *src, unsigned long count)
+{
+       __outsl_ns((unsigned long) p, src, count);
+}
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+struct pci_dev;
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
+{
+}
+
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
@@ -285,6 +387,27 @@ static inline void flush_write_buffers(void)
  */
 #define xlate_dev_kmem_ptr(p)  p
 
+/*
+ * Check BIOS signature
+ */
+static inline int check_signature(volatile void __iomem *io_addr,
+                                 const unsigned char *signature, int length)
+{
+       int retval = 0;
+
+       do {
+               if (readb(io_addr) != *signature)
+                       goto out;
+               io_addr++;
+               signature++;
+               length--;
+       } while (length);
+
+       retval = 1;
+out:
+       return retval;
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_IO_H */
index c8f575fc42fa536b3cdaed6b7fd63ed35cb14c31..93fa732fb0cd17b6a02225eb9a19570088e836cc 100644 (file)
@@ -68,6 +68,9 @@ do {                                                                  \
 #define __is_PCI_MEM(addr) \
        ((unsigned long)(addr) - __region_PCI_MEM < 0x08000000UL)
 
+#define __is_PCI_addr(addr) \
+       ((unsigned long)(addr) - __region_PCI_IO < 0x0c000000UL)
+
 #define __get_CLKSW()  ({ *(volatile unsigned long *)(__region_CS2 + 0x0130000cUL) & 0xffUL; })
 #define __get_CLKIN()  (__get_CLKSW() * 125U * 100000U / 24U)
 
@@ -149,6 +152,7 @@ do {                                                                        \
 
 #define __is_PCI_IO(addr)      0       /* no PCI */
 #define __is_PCI_MEM(addr)     0
+#define __is_PCI_addr(addr)    0
 #define __region_PCI_IO                0
 #define __region_PCI_MEM       0
 #define __flush_PCI_writes()   do { } while(0)
diff --git a/include/asm-frv/mc146818rtc.h b/include/asm-frv/mc146818rtc.h
new file mode 100644 (file)
index 0000000..90dfb7a
--- /dev/null
@@ -0,0 +1,16 @@
+/* mc146818rtc.h: RTC defs
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+
+#endif /* _ASM_MC146818RTC_H */
index 3223cfaef743d91df3a4225c8fa86bfeaff5b1bd..3d5c6360289a8085bb782c5909263bc00a83c697 100644 (file)
 #ifndef _ASM_MODULE_H
 #define _ASM_MODULE_H
 
-#define module_map(x)          vmalloc(x)
-#define module_unmap(x)                vfree(x)
-#define module_arch_init(x)    (0)
-#define arch_init_modules(x)   do { } while (0)
+struct mod_arch_specific
+{
+};
+
+#define Elf_Shdr       Elf32_Shdr
+#define Elf_Sym                Elf32_Sym
+#define Elf_Ehdr       Elf32_Ehdr
+
+/*
+ * Include the architecture version.
+ */
+#define MODULE_ARCH_VERMAGIC __stringify(PROCESSOR_MODEL_NAME) " "
 
 #endif /* _ASM_MODULE_H */
 
index 1168451c275fb1603892630bf3510a6899dace0b..598b0c6b695da9af576f43458241604bbcc4678c 100644 (file)
@@ -57,6 +57,14 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
  */
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)           (0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
+
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
index 844666377dcbfc45db86c4b33d5c9ec431fb4907..d1c3b182c6914282b860d4b4d4a855dfb27f5d5d 100644 (file)
@@ -420,6 +420,11 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
        asm volatile("dcf %M0" :: "U"(*ptep));
 }
 
+/*
+ * Macro to mark a page protection value as "uncacheable"
+ */
+#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NOCACHE))
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
index 50605df6d8acbc024adcba5f4c7aabe1ac57ca14..2560f596a75db78b2e7f406864f281933fff3957 100644 (file)
@@ -59,7 +59,6 @@ typedef unsigned int u32;
 
 typedef signed long long s64;
 typedef unsigned long long u64;
-typedef u64 u_quad_t;
 
 /* Dma addresses are 32-bits wide.  */
 
index 991b50fbba24d77b64c402389f2e93e0c48bb2a8..b6bcbe01f6ee43851e0f67570684010f529de01f 100644 (file)
@@ -180,16 +180,16 @@ do {                                              \
                                                                        \
        switch (sizeof(*(ptr))) {                                       \
        case 1:                                                         \
-               __get_user_asm(__gu_err, __gu_val, ptr, "ub", "=r");    \
+               __get_user_asm(__gu_err, *(u8*)&__gu_val, ptr, "ub", "=r"); \
                break;                                                  \
        case 2:                                                         \
-               __get_user_asm(__gu_err, __gu_val, ptr, "uh", "=r");    \
+               __get_user_asm(__gu_err, *(u16*)&__gu_val, ptr, "uh", "=r"); \
                break;                                                  \
        case 4:                                                         \
-               __get_user_asm(__gu_err, __gu_val, ptr, "", "=r");      \
+               __get_user_asm(__gu_err, *(u32*)&__gu_val, ptr, "", "=r"); \
                break;                                                  \
        case 8:                                                         \
-               __get_user_asm(__gu_err, __gu_val, ptr, "d", "=e");     \
+               __get_user_asm(__gu_err, *(u64*)&__gu_val, ptr, "d", "=e"); \
                break;                                                  \
        default:                                                        \
                __gu_err = __get_user_bad();                            \
index 5cf989b448d5200a190a1f320cd1bb4dcb5edafd..cde376a7a85733e57dda51e8569bd16389ad6b6b 100644 (file)
@@ -313,7 +313,7 @@ do {                                                                        \
         unsigned long __sr2 = (res);                                   \
        if (__builtin_expect(__sr2 >= (unsigned long)(-4095), 0)) {     \
                errno = (-__sr2);                                       \
-               __sr2 = ULONG_MAX;                                      \
+               __sr2 = ~0UL;                                           \
        }                                                               \
        return (type) __sr2;                                            \
 } while (0)
diff --git a/include/asm-frv/vga.h b/include/asm-frv/vga.h
new file mode 100644 (file)
index 0000000..a702c80
--- /dev/null
@@ -0,0 +1,17 @@
+/* vga.h: VGA register stuff
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_VGA_H
+#define _ASM_VGA_H
+
+
+
+#endif /* _ASM_VGA_H */
diff --git a/include/asm-frv/xor.h b/include/asm-frv/xor.h
new file mode 100644 (file)
index 0000000..c82eb12
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
index e0a28b925ef0713d18dbda38faa8f21b08c1b9f2..0fada8f16dc6d8f6ca0a1f2907684edefdcf76c6 100644 (file)
@@ -8,6 +8,7 @@
  * edit all arch specific atomic.h files.
  */
 
+#include <asm/types.h>
 
 /*
  * Suppport for atomic_long_t
index 747d790295f3ddf02229f1a2838830f09ff22247..1b356207712c848a3e7318c96515d7fcac24608b 100644 (file)
@@ -274,7 +274,7 @@ dma_get_cache_alignment(void)
 {
        /* no easy way to get cache size on all processors, so return
         * the maximum possible, to be safe */
-       return (1 << L1_CACHE_SHIFT_MAX);
+       return (1 << INTERNODE_CACHE_SHIFT);
 }
 
 static inline void
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
new file mode 100644 (file)
index 0000000..3ae2c73
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ASM_GENERIC_FUTEX_H
+#define _ASM_GENERIC_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret;
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       switch (op) {
+       case FUTEX_OP_SET:
+       case FUTEX_OP_ADD:
+       case FUTEX_OP_OR:
+       case FUTEX_OP_ANDN:
+       case FUTEX_OP_XOR:
+       default:
+               ret = -ENOSYS;
+       }
+
+       dec_preempt_count();
+
+       if (!ret) {
+               switch (cmp) {
+               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               default: ret = -ENOSYS;
+               }
+       }
+       return ret;
+}
+
+#endif
+#endif
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 849788710feb33fcecc22d695b8df92bbf44a06a..615911e5bd244e61a74ffe5d673054d6a7974a78 100644 (file)
@@ -10,6 +10,4 @@
 #define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT)
 #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
 
-#define L1_CACHE_SHIFT_MAX 7   /* largest L1 which this arch supports */
-
 #endif
index e56c335f8ef9f0f5c7294eeee9e65a1b98d0165b..6c37a9ab8d607e5a7121fa227ee3785110a9ac7d 100644 (file)
@@ -150,7 +150,7 @@ dma_get_cache_alignment(void)
 {
        /* no easy way to get cache size on all x86, so return the
         * maximum possible, to be safe */
-       return (1 << L1_CACHE_SHIFT_MAX);
+       return (1 << INTERNODE_CACHE_SHIFT);
 }
 
 #define dma_is_consistent(d)   (1)
index 270f1986b19f781ff7788a126d2d1486b5e5bfbc..5169d7af456f4cdfa9ac082db031b38dbda02504 100644 (file)
@@ -21,8 +21,6 @@ static __inline__ int irq_canonicalize(int irq)
        return ((irq == 2) ? 9 : irq);
 }
 
-extern void release_vm86_irqs(struct task_struct *);
-
 #ifdef CONFIG_X86_LOCAL_APIC
 # define ARCH_HAS_NMI_WATCHDOG         /* See include/linux/nmi.h */
 #endif
index 7e0f2945d17d48587dadf5a6b6b5d027b9869b0a..f324c53b6f9a8e96be3ada795ff90e3e296e6acd 100644 (file)
@@ -54,6 +54,9 @@ struct pt_regs {
 #define PTRACE_GET_THREAD_AREA    25
 #define PTRACE_SET_THREAD_AREA    26
 
+#define PTRACE_SYSEMU            31
+#define PTRACE_SYSEMU_SINGLESTEP  32
+
 #ifdef __KERNEL__
 
 #include <asm/vm86.h>
index fe38b9a96233f86fb47f34d0920802f23b3f0542..481c3c0ea720d32c1570a3588ef31da4ac81247b 100644 (file)
 #define __NR_inotify_init      291
 #define __NR_inotify_add_watch 292
 #define __NR_inotify_rm_watch  293
+#define __NR_migrate_pages     294
 
-#define NR_syscalls 294
+#define NR_syscalls 295
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
index 40ec82c6914ddf1559876d4afd82a06136023aee..952fd695738073e0c5e4639a85ade992b3349b39 100644 (file)
 #define IF_MASK                0x00000200
 #define IOPL_MASK      0x00003000
 #define NT_MASK                0x00004000
+#ifdef CONFIG_VM86
 #define VM_MASK                0x00020000
+#else
+#define VM_MASK                0 /* ignored */
+#endif
 #define AC_MASK                0x00040000
 #define VIF_MASK       0x00080000      /* virtual interrupt flag */
 #define VIP_MASK       0x00100000      /* virtual interrupt pending */
@@ -200,9 +204,25 @@ struct kernel_vm86_struct {
  */
 };
 
+#ifdef CONFIG_VM86
+
 void handle_vm86_fault(struct kernel_vm86_regs *, long);
 int handle_vm86_trap(struct kernel_vm86_regs *, long, int);
 
+struct task_struct;
+void release_vm86_irqs(struct task_struct *);
+
+#else
+
+#define handle_vm86_fault(a, b)
+#define release_vm86_irqs(a)
+
+static inline int handle_vm86_trap(struct kernel_vm86_regs *a, long b, int c) {
+       return 0;
+}
+
+#endif /* CONFIG_VM86 */
+
 #endif /* __KERNEL__ */
 
 #endif
index 3aa0a0a5474bd20f7898995bf45cc13da5986bac..823616b5020b366ba5b20e06529d0095748e7477 100644 (file)
@@ -2,11 +2,7 @@
 #define _ASM_IA64_BUG_H
 
 #ifdef CONFIG_BUG
-#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
-# define ia64_abort()  __builtin_trap()
-#else
-# define ia64_abort()  (*(volatile int *) 0 = 0)
-#endif
+#define ia64_abort()   __builtin_trap()
 #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0)
 
 /* should this BUG be made generic? */
index 666d8f175cb3c99613667a21b91b2a100622d25d..40dd25195d656e0c171106a9735d931d7f0116e7 100644 (file)
@@ -12,8 +12,6 @@
 #define L1_CACHE_SHIFT         CONFIG_IA64_L1_CACHE_SHIFT
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
-#define L1_CACHE_SHIFT_MAX 7   /* largest L1 which this arch supports */
-
 #ifdef CONFIG_SMP
 # define SMP_CACHE_SHIFT       L1_CACHE_SHIFT
 # define SMP_CACHE_BYTES       L1_CACHE_BYTES
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index cf772a67f858763719a615f03ea8b8d117501973..b64fdb9854941cfcd816f003b99d3e66235dc34d 100644 (file)
@@ -89,6 +89,7 @@ phys_to_virt (unsigned long address)
 
 #define ARCH_HAS_VALID_PHYS_ADDR_RANGE
 extern int valid_phys_addr_range (unsigned long addr, size_t *count); /* efi.c */
+extern int valid_mmap_phys_addr_range (unsigned long addr, size_t *count);
 
 /*
  * The following two macros are deprecated and scheduled for removal.
index 0c91a76c5ea3cff8decee9debe0cf45d696a83c7..9e83210dc31257adc4c5356b64f37b24e83bf1e4 100644 (file)
@@ -34,7 +34,7 @@ __raw_spin_lock_flags (raw_spinlock_t *lock, unsigned long flags)
 {
        register volatile unsigned int *ptr asm ("r31") = &lock->lock;
 
-#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
+#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
 # ifdef CONFIG_ITANIUM
        /* don't use brl on Itanium... */
        asm volatile ("{\n\t"
index 2bf543493cb86675d7b3ec43bd58b8f684e6196b..962f9bd1bdff71c81f6810c9cc144a0086ab2022 100644 (file)
 #define __NR_inotify_init              1277
 #define __NR_inotify_add_watch         1278
 #define __NR_inotify_rm_watch          1279
+#define __NR_migrate_pages             1280
 
 #ifdef __KERNEL__
 
 #include <linux/config.h>
 
-#define NR_syscalls                    256 /* length of syscall table */
+#define NR_syscalls                    270 /* length of syscall table */
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
 
index 724820596980947f9c8d5a3baa7889a24271e23a..9c2b2d9998bc9e13397cb28cc9d21f91e3a42214 100644 (file)
@@ -7,6 +7,4 @@
 #define L1_CACHE_SHIFT         4
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
-#define L1_CACHE_SHIFT_MAX     4
-
 #endif  /* _ASM_M32R_CACHE_H */
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 6161fd3d860040bb5babf9201b6e9f433d1a50d4..fed3fd30de7e468797a85ff5945119c436f92fce 100644 (file)
@@ -8,6 +8,4 @@
 #define        L1_CACHE_SHIFT  4
 #define        L1_CACHE_BYTES  (1<< L1_CACHE_SHIFT)
 
-#define L1_CACHE_SHIFT_MAX 4   /* largest L1 which this arch supports */
-
 #endif
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 1a5d1a669db382e4a2e398704b4052eddc083797..55e19f2ff0e012474a2d0f4c94a123e5e72bc9d9 100644 (file)
@@ -15,7 +15,6 @@
 #define L1_CACHE_SHIFT         CONFIG_MIPS_L1_CACHE_SHIFT
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
-#define L1_CACHE_SHIFT_MAX     6
 #define SMP_CACHE_SHIFT                L1_CACHE_SHIFT
 #define SMP_CACHE_BYTES                L1_CACHE_BYTES
 
index 5da72e38bdde4dd8a0599ac95e1f7d611319b233..38d201b5652dccd74e8ba4e1181e89be4ccba7c4 100644 (file)
@@ -28,7 +28,6 @@
 #define L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 
 #define SMP_CACHE_BYTES L1_CACHE_BYTES
-#define L1_CACHE_SHIFT_MAX 5   /* largest L1 which this arch supports */
 
 extern void flush_data_cache_local(void);  /* flushes local data-cache only */
 extern void flush_instruction_cache_local(void); /* flushes local code-cache only */
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 18415108fc56636b75a6459858a8f4106afa0494..c5c3259e0f86f3d147f9daf50719ea5e6311162c 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_ABS_ADDR_H
 #define _ASM_POWERPC_ABS_ADDR_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 
@@ -70,4 +71,5 @@ static inline unsigned long phys_to_abs(unsigned long pa)
 #define iseries_hv_addr(virtaddr)      \
        (0x8000000000000000 | virt_to_abs(virtaddr))
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_ABS_ADDR_H */
index 885b4631a6cf047560c40a5be44c8fc173cbd606..e5ccaca2f5a42a0d379281536601766594ccec49 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_AGP_H
 #define _ASM_POWERPC_AGP_H
+#ifdef __KERNEL__
 
 #include <asm/io.h>
 
@@ -18,4 +19,5 @@
 #define free_gatt_pages(table, order)  \
        free_pages((unsigned long)(table), (order))
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_AGP_H */
index 8b133efc9f7916ef76228e0048091cd870551d5d..8e64be0cc47d3d0f7579445af6726a661f50a17b 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _ASM_POWERPC_ASM_COMPAT_H
 #define _ASM_POWERPC_ASM_COMPAT_H
 
-#include <linux/config.h>
 #include <asm/types.h>
 
 #ifdef __ASSEMBLY__
@@ -41,6 +40,7 @@
 
 #endif
 
+#ifdef __KERNEL__
 #ifdef CONFIG_IBM405_ERR77
 /* Erratum #77 on the 405 means we need a sync or dcbt before every
  * stwcx.  The old ATOMIC_SYNC_FIX covered some but not all of this.
@@ -51,5 +51,6 @@
 #define PPC405_ERR77(ra,rb)
 #define PPC405_ERR77_SYNC
 #endif
+#endif
 
 #endif /* _ASM_POWERPC_ASM_COMPAT_H */
diff --git a/include/asm-powerpc/bootx.h b/include/asm-powerpc/bootx.h
new file mode 100644 (file)
index 0000000..57b82e3
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * This file describes the structure passed from the BootX application
+ * (for MacOS) when it is used to boot Linux.
+ *
+ * Written by Benjamin Herrenschmidt.
+ */
+
+
+#ifndef __ASM_BOOTX_H__
+#define __ASM_BOOTX_H__
+
+#include <asm/types.h>
+
+#ifdef macintosh
+#include <Types.h>
+#include "linux_type_defs.h"
+#endif
+
+#ifdef macintosh
+/* All this requires PowerPC alignment */
+#pragma options align=power
+#endif
+
+/* On kernel entry:
+ *
+ * r3 = 0x426f6f58    ('BooX')
+ * r4 = pointer to boot_infos
+ * r5 = NULL
+ *
+ * Data and instruction translation disabled, interrupts
+ * disabled, kernel loaded at physical 0x00000000 on PCI
+ * machines (will be different on NuBus).
+ */
+
+#define BOOT_INFO_VERSION               5
+#define BOOT_INFO_COMPATIBLE_VERSION    1
+
+/* Bit in the architecture flag mask. More to be defined in
+   future versions. Note that either BOOT_ARCH_PCI or
+   BOOT_ARCH_NUBUS is set. The other BOOT_ARCH_NUBUS_xxx are
+   set additionally when BOOT_ARCH_NUBUS is set.
+ */
+#define BOOT_ARCH_PCI                   0x00000001UL
+#define BOOT_ARCH_NUBUS                 0x00000002UL
+#define BOOT_ARCH_NUBUS_PDM             0x00000010UL
+#define BOOT_ARCH_NUBUS_PERFORMA        0x00000020UL
+#define BOOT_ARCH_NUBUS_POWERBOOK       0x00000040UL
+
+/*  Maximum number of ranges in phys memory map */
+#define MAX_MEM_MAP_SIZE                               26
+
+/* This is the format of an element in the physical memory map. Note that
+   the map is optional and current BootX will only build it for pre-PCI
+   machines */
+typedef struct boot_info_map_entry
+{
+    __u32       physAddr;                /* Physical starting address */
+    __u32       size;                    /* Size in bytes */
+} boot_info_map_entry_t;
+
+
+/* Here are the boot informations that are passed to the bootstrap
+ * Note that the kernel arguments and the device tree are appended
+ * at the end of this structure. */
+typedef struct boot_infos
+{
+    /* Version of this structure */
+    __u32       version;
+    /* backward compatible down to version: */
+    __u32       compatible_version;
+
+    /* NEW (vers. 2) this holds the current _logical_ base addr of
+       the frame buffer (for use by early boot message) */
+    __u8*       logicalDisplayBase;
+
+    /* NEW (vers. 4) Apple's machine identification */
+    __u32       machineID;
+
+    /* NEW (vers. 4) Detected hw architecture */
+    __u32       architecture;
+
+    /* The device tree (internal addresses relative to the beginning of the tree,
+     * device tree offset relative to the beginning of this structure).
+     * On pre-PCI macintosh (BOOT_ARCH_PCI bit set to 0 in architecture), this
+     * field is 0.
+     */
+    __u32       deviceTreeOffset;        /* Device tree offset */
+    __u32       deviceTreeSize;          /* Size of the device tree */
+
+    /* Some infos about the current MacOS display */
+    __u32       dispDeviceRect[4];       /* left,top,right,bottom */
+    __u32       dispDeviceDepth;         /* (8, 16 or 32) */
+    __u8*       dispDeviceBase;          /* base address (physical) */
+    __u32       dispDeviceRowBytes;      /* rowbytes (in bytes) */
+    __u32       dispDeviceColorsOffset;  /* Colormap (8 bits only) or 0 (*) */
+    /* Optional offset in the registry to the current
+     * MacOS display. (Can be 0 when not detected) */
+     __u32      dispDeviceRegEntryOffset;
+
+    /* Optional pointer to boot ramdisk (offset from this structure) */
+    __u32       ramDisk;
+    __u32       ramDiskSize;             /* size of ramdisk image */
+
+    /* Kernel command line arguments (offset from this structure) */
+    __u32       kernelParamsOffset;
+
+    /* ALL BELOW NEW (vers. 4) */
+
+    /* This defines the physical memory. Valid with BOOT_ARCH_NUBUS flag
+       (non-PCI) only. On PCI, memory is contiguous and it's size is in the
+       device-tree. */
+    boot_info_map_entry_t
+               physMemoryMap[MAX_MEM_MAP_SIZE]; /* Where the phys memory is */
+    __u32       physMemoryMapSize;               /* How many entries in map */
+
+
+    /* The framebuffer size (optional, currently 0) */
+    __u32       frameBufferSize;         /* Represents a max size, can be 0. */
+
+    /* NEW (vers. 5) */
+
+    /* Total params size (args + colormap + device tree + ramdisk) */
+    __u32       totalParamsSize;
+
+} boot_infos_t;
+
+#ifdef __KERNEL__
+/* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index
+ * is represented by 3 short words containing a 16 bits (unsigned) color
+ * component. Later versions may contain the gamma table for direct-color
+ * devices here.
+ */
+#define BOOTX_COLORTABLE_SIZE    (256UL*3UL*2UL)
+
+/* BootX passes the device-tree using a format that comes from earlier
+ * ppc32 kernels. This used to match what is in prom.h, but not anymore
+ * so we now define it here
+ */
+struct bootx_dt_prop {
+       u32     name;
+       int     length;
+       u32     value;
+       u32     next;
+};
+
+struct bootx_dt_node {
+       u32     unused0;
+       u32     unused1;
+       u32     phandle;        /* not really available */
+       u32     unused2;
+       u32     unused3;
+       u32     unused4;
+       u32     unused5;
+       u32     full_name;
+       u32     properties;
+       u32     parent;
+       u32     child;
+       u32     sibling;
+       u32     next;
+       u32     allnext;
+};
+
+extern void bootx_init(unsigned long r4, unsigned long phys);
+
+#endif /* __KERNEL__ */
+
+#ifdef macintosh
+#pragma options align=reset
+#endif
+
+#endif
index 71cce36bc63099e837b4081547acaa5c8f76442f..906f46e3100642455fef5ae957b68e7db9be0275 100644 (file)
@@ -7,21 +7,22 @@
 #define __PPC_BTEXT_H
 #ifdef __KERNEL__
 
-extern void btext_clearscreen(void);
-extern void btext_flushscreen(void);
-
-extern int boot_text_mapped;
-
-extern int btext_initialize(struct device_node *np);
-
-extern void map_boot_text(void);
-extern void init_boot_display(void);
+extern int btext_find_display(int allow_nonstdout);
 extern void btext_update_display(unsigned long phys, int width, int height,
                                 int depth, int pitch);
+extern void btext_setup_display(int width, int height, int depth, int pitch,
+                               unsigned long address);
+extern void btext_prepare_BAT(void);
+extern void btext_unmap(void);
 
 extern void btext_drawchar(char c);
 extern void btext_drawstring(const char *str);
 extern void btext_drawhex(unsigned long v);
+extern void btext_drawtext(const char *c, unsigned int len);
+
+extern void btext_clearscreen(void);
+extern void btext_flushscreen(void);
+extern void btext_flushline(void);
 
 #endif /* __KERNEL__ */
 #endif /* __PPC_BTEXT_H */
index b001ecb3cd9956030f8520b6fad183eb3186eee7..99817a802ca4e4d7c6a6784b3be2d39620018aa0 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_BUG_H
 #define _ASM_POWERPC_BUG_H
+#ifdef __KERNEL__
 
 #include <asm/asm-compat.h>
 /*
@@ -67,4 +68,5 @@ struct bug_entry *find_bug(unsigned long bugaddr);
 
 #include <asm-generic/bug.h>
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_BUG_H */
index 26ce502e76e82ace309a08a40b0da98d8edd7c65..6379c2df5c40ff51830e32ecbffd55a949bd0b7a 100644 (file)
@@ -19,7 +19,6 @@
 #define        L1_CACHE_BYTES          (1 << L1_CACHE_SHIFT)
 
 #define        SMP_CACHE_BYTES         L1_CACHE_BYTES
-#define L1_CACHE_SHIFT_MAX     7 /* largest L1 which this arch supports */
 
 #if defined(__powerpc64__) && !defined(__ASSEMBLY__)
 struct ppc64_caches {
index d8354d8a49ceab96ec9d64ee7f01caaf9e41c571..609ecbbd7210ee9935afce49da562f147fe8c75a 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_CHECKSUM_H
 #define _ASM_POWERPC_CHECKSUM_H
+#ifdef __KERNEL__
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -129,4 +130,5 @@ static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
 }
 
 #endif
+#endif /* __KERNEL__ */
 #endif
index 4db4360c4d4aee1df36c131cdc6a4117dd3e73d3..accb80c9a339c2b2b2ee38de36c3fec1a76ab551 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_COMPAT_H
 #define _ASM_POWERPC_COMPAT_H
+#ifdef __KERNEL__
 /*
  * Architecture specific compatibility types
  */
@@ -202,4 +203,5 @@ struct compat_shmid64_ds {
        compat_ulong_t __unused6;
 };
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_COMPAT_H */
index d1cfa3f515ea2d2162941c42ea534a567d22d7b5..ef6ead34a773c358aa45dc6e802df198ff4d4898 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __ASM_POWERPC_CPUTABLE_H
 #define __ASM_POWERPC_CPUTABLE_H
 
-#include <linux/config.h>
 #include <asm/asm-compat.h>
 
 #define PPC_FEATURE_32                 0x80000000
  * via the mkdefs mechanism.
  */
 struct cpu_spec;
-struct op_powerpc_model;
 
 typedef        void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
 
+enum powerpc_oprofile_type {
+       INVALID = 0,
+       RS64 = 1,
+       POWER4 = 2,
+       G4 = 3,
+       BOOKE = 4,
+};
+
 struct cpu_spec {
        /* CPU is matched via (PVR & pvr_mask) == pvr_value */
        unsigned int    pvr_mask;
@@ -57,7 +63,7 @@ struct cpu_spec {
        char            *oprofile_cpu_type;
 
        /* Processor specific oprofile operations */
-       struct op_powerpc_model *oprofile_model;
+       enum powerpc_oprofile_type oprofile_type;
 };
 
 extern struct cpu_spec         *cur_cpu_spec;
@@ -106,6 +112,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
 #define CPU_FTR_LOCKLESS_TLBIE         ASM_CONST(0x0000040000000000)
 #define CPU_FTR_MMCRA_SIHV             ASM_CONST(0x0000080000000000)
 #define CPU_FTR_CI_LARGE_PAGE          ASM_CONST(0x0000100000000000)
+#define CPU_FTR_PAUSE_ZERO             ASM_CONST(0x0000200000000000)
 #else
 /* ensure on 32b processors the flags are available for compiling but
  * don't do anything */
@@ -305,12 +312,18 @@ enum {
            CPU_FTR_MMCRA_SIHV,
        CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
-           CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT,
+           CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT |
+           CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO,
        CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2,
 #endif
 
        CPU_FTRS_POSSIBLE =
+#ifdef __powerpc64__
+           CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |
+           CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL |
+            CPU_FTR_CI_LARGE_PAGE |
+#else
 #if CLASSIC_PPC
            CPU_FTRS_PPC601 | CPU_FTRS_603 | CPU_FTRS_604 | CPU_FTRS_740_NOTAU |
            CPU_FTRS_740 | CPU_FTRS_750 | CPU_FTRS_750FX1 |
@@ -344,14 +357,14 @@ enum {
 #ifdef CONFIG_E500
            CPU_FTRS_E500 | CPU_FTRS_E500_2 |
 #endif
-#ifdef __powerpc64__
-           CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |
-           CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL |
-            CPU_FTR_CI_LARGE_PAGE |
-#endif
+#endif /* __powerpc64__ */
            0,
 
        CPU_FTRS_ALWAYS =
+#ifdef __powerpc64__
+           CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &
+           CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &
+#else
 #if CLASSIC_PPC
            CPU_FTRS_PPC601 & CPU_FTRS_603 & CPU_FTRS_604 & CPU_FTRS_740_NOTAU &
            CPU_FTRS_740 & CPU_FTRS_750 & CPU_FTRS_750FX1 &
@@ -385,10 +398,7 @@ enum {
 #ifdef CONFIG_E500
            CPU_FTRS_E500 & CPU_FTRS_E500_2 &
 #endif
-#ifdef __powerpc64__
-           CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &
-           CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &
-#endif
+#endif /* __powerpc64__ */
            CPU_FTRS_POSSIBLE,
 };
 
index 82cd4a9ca99a92faca63cf01e41ebc75f6a35c38..1938d6abd255056f46711b2786c3720123d90445 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_CURRENT_H
 #define _ASM_POWERPC_CURRENT_H
+#ifdef __KERNEL__
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -24,4 +25,5 @@ register struct task_struct *current asm ("r2");
 
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_CURRENT_H */
index 54fe1f4f8fd069bdaa121aa6bd90e7e855f2e8eb..057a6095547483e36f96b3ba243ae79a13b5fd36 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_DELAY_H
 #define _ASM_POWERPC_DELAY_H
+#ifdef __KERNEL__
 
 /*
  * Copyright 1996, Paul Mackerras.
@@ -16,4 +17,5 @@
 extern void __delay(unsigned long loops);
 extern void udelay(unsigned long usecs);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DELAY_H */
index 59a80163f75fb2abac5dec482958012f784bef16..837756ab7dc7fe868c2caa19d526406849617d13 100644 (file)
@@ -6,6 +6,7 @@
  */
 #ifndef _ASM_DMA_MAPPING_H
 #define _ASM_DMA_MAPPING_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -229,7 +230,7 @@ static inline int dma_get_cache_alignment(void)
 #ifdef CONFIG_PPC64
        /* no easy way to get cache size on all processors, so return
         * the maximum possible, to be safe */
-       return (1 << L1_CACHE_SHIFT_MAX);
+       return (1 << INTERNODE_CACHE_SHIFT);
 #else
        /*
         * Each processor family will define its own L1_CACHE_SHIFT,
@@ -282,4 +283,5 @@ struct dma_mapping_ops {
        int             (*dac_dma_supported)(struct device *dev, u64 mask);
 };
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_DMA_MAPPING_H */
index 926378d2cd94d9f4f45ad29dd106c24006bbf66d..4bb57fe370972cf5c77893bbca5f9de710d7ead8 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_DMA_H
 #define _ASM_POWERPC_DMA_H
+#ifdef __KERNEL__
 
 /*
  * Defines for using and allocating dma channels.
@@ -387,4 +388,5 @@ extern int isa_dma_bridge_buggy;
 
 #endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DMA_H */
index f8633aafe4baa5d000e608b35b92e5f13be45311..4395b7bc1ed462b839d21881e7ef3f1382988bcf 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifndef _PPC64_EEH_H
 #define _PPC64_EEH_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <linux/init.h>
@@ -57,6 +58,7 @@ void __init pci_addr_cache_build(void);
  * to finish the eeh setup for this device.
  */
 void eeh_add_device_early(struct device_node *);
+void eeh_add_device_tree_early(struct device_node *);
 void eeh_add_device_late(struct pci_dev *);
 
 /**
@@ -71,6 +73,15 @@ void eeh_add_device_late(struct pci_dev *);
  */
 void eeh_remove_device(struct pci_dev *);
 
+/**
+ * eeh_remove_device_recursive - undo EEH for device & children.
+ * @dev: pci device to be removed
+ *
+ * As above, this removes the device; it also removes child
+ * pci devices as well.
+ */
+void eeh_remove_bus_device(struct pci_dev *);
+
 /**
  * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
  *
@@ -107,6 +118,9 @@ static inline void eeh_add_device_late(struct pci_dev *dev) { }
 
 static inline void eeh_remove_device(struct pci_dev *dev) { }
 
+static inline void eeh_add_device_tree_early(struct device_node *dn) { }
+
+static inline void eeh_remove_bus_device(struct pci_dev *dev) { }
 #define EEH_POSSIBLE_ERROR(val, type) (0)
 #define EEH_IO_ERROR_VALUE(size) (-1UL)
 #endif /* CONFIG_EEH */
@@ -363,4 +377,5 @@ static inline void eeh_insl_ns(unsigned long port, void * buf, int nl)
                eeh_check_failure((void __iomem *)(port), *(u32*)buf);
 }
 
+#endif /* __KERNEL__ */
 #endif /* _PPC64_EEH_H */
index d168a30b3866ea11283ac10155befa7c2234c01b..5e11a00b6fa01722031e647e610f03d00faab3b9 100644 (file)
@@ -20,6 +20,7 @@
 
 #ifndef ASM_PPC64_EEH_EVENT_H
 #define ASM_PPC64_EEH_EVENT_H
+#ifdef __KERNEL__
 
 /** EEH event -- structure holding pci controller data that describes
  *  a change in the isolation status of a PCI slot.  A pointer
@@ -49,4 +50,5 @@ int eeh_send_failure_event (struct device_node *dn,
                             int reset_state,
                             int time_unavail);
 
+#endif /* __KERNEL__ */
 #endif /* ASM_PPC64_EEH_EVENT_H */
index 3dcd65edf97805daf4f496fc4ecaf83f3cfe81f1..c5a635d9bba4d5edb3360aca169bf81078c52a96 100644 (file)
@@ -1,7 +1,10 @@
 #ifndef _ASM_POWERPC_ELF_H
 #define _ASM_POWERPC_ELF_H
 
+#ifdef __KERNEL__
 #include <linux/sched.h>       /* for task_struct */
+#endif
+
 #include <asm/types.h>
 #include <asm/ptrace.h>
 #include <asm/cputable.h>
index 12fabbcb04f04a7bcb7ec248c39fdbeedb0ea915..f804b34cf06a6f63136955e315407a456107ce44 100644 (file)
@@ -98,6 +98,12 @@ typedef struct {
 extern firmware_feature_t firmware_features_table[];
 #endif
 
+extern void system_reset_fwnmi(void);
+extern void machine_check_fwnmi(void);
+
+/* This is true if we are using the firmware NMI handler (typically LPAR) */
+extern int fwnmi_active;
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_FIRMWARE_H */
index 64276a3f6153f7ea6461233287ad9c4473f87b88..e258778ca429ea5ccb9e90eb3672df61f821fede 100644 (file)
@@ -9,6 +9,7 @@
  */
 #ifndef __ASM_POWERPC_FLOPPY_H
 #define __ASM_POWERPC_FLOPPY_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <asm/machdep.h>
@@ -102,4 +103,5 @@ static int FDC2 = -1;
 
 #define EXTRA_FLOPPY_PARAMS
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_FLOPPY_H */
index 563c7a5e64c9ad3228f8126f914baae754142fab..bd7812a519d4ad717045912175b7e6fb310aa706 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_GRACKLE_H
+#define _ASM_POWERPC_GRACKLE_H
+#ifdef __KERNEL__
 /*
  * Functions for setting up and using a MPC106 northbridge
  */
@@ -5,3 +8,5 @@
 #include <asm/pci-bridge.h>
 
 extern void setup_grackle(struct pci_controller *hose);
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_GRACKLE_H */
index 3b3e3b49ec127a411d4df7ba5324a11aebea3428..288e14d53b7fa2a17b4012c4b21b413a037a8521 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_HARDIRQ_H
 #define _ASM_POWERPC_HARDIRQ_H
+#ifdef __KERNEL__
 
 #include <asm/irq.h>
 #include <asm/bug.h>
@@ -24,4 +25,5 @@ static inline void ack_bad_irq(int irq)
        BUG();
 }
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HARDIRQ_H */
index 22ac179856b9002e97dc542fb619a28b90bec9e0..93f54958a9d14813c7466fdb44b0f7ebb785044b 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_HEATHROW_H
+#define _ASM_POWERPC_HEATHROW_H
+#ifdef __KERNEL__
 /*
  * heathrow.h: definitions for using the "Heathrow" I/O controller chip.
  *
@@ -60,3 +63,5 @@
 /* Looks like Heathrow has some sort of GPIOs as well... */
 #define HRW_GPIO_MODEM_RESET   0x6d
 
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_HEATHROW_H */
index d36da61dbc5318fb900f7c487b12551e990bd6f6..da7af5a720e098adf14ad1ccf9b0817e9d429fde 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_HVCALL_H
 #define _ASM_POWERPC_HVCALL_H
+#ifdef __KERNEL__
 
 #define HVSC                   .long 0x44000022
 
@@ -170,4 +171,5 @@ long plpar_hcall_4out(unsigned long opcode,
                      unsigned long *out4);
 
 #endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HVCALL_H */
index 6da93ce74dc06353faca972eb0d0fdce16138b34..34daf7b9b62fe5d1b1944f62aa5ca27fa5640808 100644 (file)
@@ -21,6 +21,7 @@
 
 #ifndef _PPC64_HVCONSOLE_H
 #define _PPC64_HVCONSOLE_H
+#ifdef __KERNEL__
 
 /*
  * This is the max number of console adapters that can/will be found as
@@ -46,4 +47,5 @@ extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
                                                 struct hv_ops *ops);
 /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
 extern int __devexit hvc_remove(struct hvc_struct *hp);
+#endif /* __KERNEL__ */
 #endif /* _PPC64_HVCONSOLE_H */
index aecba966579690892b1afc5abc874863aaa8ac11..67d7da3a4da49634d24d2706d0fc36cdc522f4fd 100644 (file)
@@ -21,6 +21,7 @@
 
 #ifndef _PPC64_HVCSERVER_H
 #define _PPC64_HVCSERVER_H
+#ifdef __KERNEL__
 
 #include <linux/list.h>
 
@@ -54,4 +55,5 @@ extern int hvcs_register_connection(uint32_t unit_address,
                uint32_t p_partition_ID, uint32_t p_unit_address);
 extern int hvcs_free_connection(uint32_t unit_address);
 
+#endif /* __KERNEL__ */
 #endif /* _PPC64_HVCSERVER_H */
index fc4bfee124d7016689b785becfc741f5ae55e60e..0392159e16e4f9cbd3b1c99519a858bf505755e8 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_I8259_H
 #define _ASM_POWERPC_I8259_H
+#ifdef __KERNEL__
 
 #include <linux/irq.h>
 
@@ -9,4 +10,5 @@ extern void i8259_init(unsigned long intack_addr, int offset);
 extern int i8259_irq(struct pt_regs *regs);
 extern int i8259_irq_cascade(struct pt_regs *regs, void *unused);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_I8259_H */
diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
new file mode 100644 (file)
index 0000000..7a42723
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * IBM PowerPC eBus Infrastructure Support.
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *  Heiko J Schick <schickhj@de.ibm.com>
+ *    
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB 
+ * BSD. 
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met: 
+ *
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer. 
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials
+ * provided with the distribution. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_EBUS_H
+#define _ASM_EBUS_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <asm/of_device.h>
+
+extern struct dma_mapping_ops ibmebus_dma_ops;
+extern struct bus_type ibmebus_bus_type;
+
+struct ibmebus_dev {   
+       char *name;
+       struct of_device ofdev;
+};
+
+struct ibmebus_driver {        
+       char *name;
+       struct of_device_id *id_table;
+       int (*probe) (struct ibmebus_dev *dev, const struct of_device_id *id);
+       int (*remove) (struct ibmebus_dev *dev);
+       struct device_driver driver;
+};
+
+int ibmebus_register_driver(struct ibmebus_driver *drv);
+void ibmebus_unregister_driver(struct ibmebus_driver *drv);
+
+int ibmebus_request_irq(struct ibmebus_dev *dev,
+                       u32 ist, 
+                       irqreturn_t (*handler)(int, void*, struct pt_regs *),
+                       unsigned long irq_flags, const char * devname,
+                       void *dev_id);
+void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id);
+
+static inline struct ibmebus_driver *to_ibmebus_driver(struct device_driver *drv)
+{
+       return container_of(drv, struct ibmebus_driver, driver);
+}
+
+static inline struct ibmebus_dev *to_ibmebus_dev(struct device *dev)
+{
+       return container_of(dev, struct ibmebus_dev, ofdev.dev);
+}
+
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_IBMEBUS_H */
index 48938d84d055e89086b8665879ce47810e3926d4..68efbea379c98bd909201c12d80e3d1567a7e3aa 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_IO_H
 #define _ASM_POWERPC_IO_H
+#ifdef __KERNEL__
 
 /* 
  * This program is free software; you can redistribute it and/or
@@ -186,7 +187,6 @@ extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, int nl);
 #define IO_SPACE_LIMIT ~(0UL)
 
 
-#ifdef __KERNEL__
 extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr,
                              unsigned long size, unsigned long flags);
 extern void __iomem *__ioremap(unsigned long address, unsigned long size,
@@ -256,8 +256,6 @@ static inline void * phys_to_virt(unsigned long address)
  */
 #define BIO_VMERGE_BOUNDARY    0
 
-#endif /* __KERNEL__ */
-
 static inline void iosync(void)
 {
         __asm__ __volatile__ ("sync" : : : "memory");
@@ -405,8 +403,6 @@ static inline void out_be64(volatile unsigned long __iomem *addr, unsigned long
 #include <asm/eeh.h>
 #endif
 
-#ifdef __KERNEL__
-
 /**
  *     check_signature         -       find BIOS signatures
  *     @io_addr: mmio address to check
index f89f0605089378e6579f6b3710044fa70813a017..8a8393e507747fd8e3c089df81cc539782fb63cd 100644 (file)
@@ -20,6 +20,7 @@
 
 #ifndef _ASM_IOMMU_H
 #define _ASM_IOMMU_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <asm/types.h>
@@ -56,7 +57,7 @@ struct device_node;
 
 /* Walks all buses and creates iommu tables */
 extern void iommu_setup_pSeries(void);
-extern void iommu_setup_u3(void);
+extern void iommu_setup_dart(void);
 
 /* Frees table for an individual device node */
 extern void iommu_free_table(struct device_node *dn);
@@ -104,7 +105,7 @@ extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
 
 extern void iommu_init_early_pSeries(void);
 extern void iommu_init_early_iSeries(void);
-extern void iommu_init_early_u3(void);
+extern void iommu_init_early_dart(void);
 
 #ifdef CONFIG_PCI
 extern void pci_iommu_init(void);
@@ -113,6 +114,7 @@ extern void pci_direct_iommu_init(void);
 static inline void pci_iommu_init(void) { }
 #endif
 
-extern void alloc_u3_dart_table(void);
+extern void alloc_dart_table(void);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_IOMMU_H */
index 288044b702dee394dc6e2c43a732358e17a34d19..81824e1bb7675ddf70f797d47d0946ff721560bb 100644 (file)
@@ -81,4 +81,6 @@ struct ItLpRegSave {
        u8      xRsvd3[176];    // Reserved                     350-3FF
 };
 
+extern struct ItLpRegSave iseries_reg_save[];
+
 #endif /* _ITLPREGSAVE_H */
index 9dcbac674811b6094511cb854c5fa4ede8d3156b..7c16265568e0483ebc04b11f7aea695075a45a34 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_KDEBUG_H
 #define _ASM_POWERPC_KDEBUG_H
+#ifdef __KERNEL__
 
 /* nearly identical to x86_64/i386 code */
 
@@ -39,4 +40,5 @@ static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,lon
        return notifier_call_chain(&powerpc_die_chain, val, &args);
 }
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_KDEBUG_H */
diff --git a/include/asm-powerpc/kdump.h b/include/asm-powerpc/kdump.h
new file mode 100644 (file)
index 0000000..a87aed0
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _PPC64_KDUMP_H
+#define _PPC64_KDUMP_H
+
+/* How many bytes to reserve at zero for kdump. The reserve limit should
+ * be greater or equal to the trampoline's end address. */
+#define KDUMP_RESERVE_LIMIT    0x8000
+
+#define KDUMP_TRAMPOLINE_START 0x0100
+#define KDUMP_TRAMPOLINE_END   0x3000
+
+extern void kdump_setup(void);
+
+#endif /* __PPC64_KDUMP_H */
index c72ffc709ea8ac0143ab13270895263c05394789..4263af3cadfde4edaf1b1742fd2b060034350914 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_KEXEC_H
 #define _ASM_POWERPC_KEXEC_H
+#ifdef __KERNEL__
 
 /*
  * Maximum page that is mapped directly into kernel memory.
 #define KEXEC_ARCH KEXEC_ARCH_PPC
 #endif
 
+#define HAVE_ARCH_COPY_OLDMEM_PAGE
+
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_KEXEC
+
 #define MAX_NOTE_BYTES 1024
 typedef u32 note_buf_t[MAX_NOTE_BYTES / sizeof(u32)];
 
@@ -41,10 +46,18 @@ extern note_buf_t crash_notes[];
 extern void kexec_smp_wait(void);      /* get and clear naca physid, wait for
                                          master to copy new code to 0 */
 extern void __init kexec_setup(void);
-#else
+extern int crashing_cpu;
+extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
+#endif /* __powerpc64 __ */
+
 struct kimage;
-extern void machine_kexec_simple(struct kimage *image);
-#endif
+struct pt_regs;
+extern void default_machine_kexec(struct kimage *image);
+extern int default_machine_kexec_prepare(struct kimage *image);
+extern void default_machine_crash_shutdown(struct pt_regs *regs);
+
+#endif /* !CONFIG_KEXEC */
 
 #endif /* ! __ASSEMBLY__ */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_KEXEC_H */
index a669a3f0f5a26923b898b1721f22feb4fd5000bf..d8520ef121f90e1f86db8dd460b6199b62e6741f 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_KEYLARGO_H
+#define _ASM_POWERPC_KEYLARGO_H
+#ifdef __KERNEL__
 /*
  * keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
  *
 #define K2_FCR1_I2S0_RESET             0x00000800
 #define K2_FCR1_I2S0_CLK_ENABLE_BIT    0x00001000
 #define K2_FCR1_I2S0_ENABLE                    0x00002000
-
 #define K2_FCR1_PCI1_CLK_ENABLE                0x00004000
 #define K2_FCR1_FW_CLK_ENABLE          0x00008000
 #define K2_FCR1_FW_RESET_N             0x00010000
+#define K2_FCR1_I2S1_CELL_ENABLE       0x00020000
+#define K2_FCR1_I2S1_CLK_ENABLE_BIT    0x00080000
+#define K2_FCR1_I2S1_ENABLE            0x00100000
 #define K2_FCR1_GMAC_CLK_ENABLE                0x00400000
 #define K2_FCR1_GMAC_POWER_DOWN                0x00800000
 #define K2_FCR1_GMAC_RESET_N           0x01000000
 #define K2_FCR1_UATA_RESET_N           0x40000000
 #define K2_FCR1_UATA_CHOOSE_CLK66      0x80000000
 
+/* Shasta definitions */
+#define SH_FCR1_I2S2_CELL_ENABLE       0x00000010
+#define SH_FCR1_I2S2_CLK_ENABLE_BIT    0x00000040
+#define SH_FCR1_I2S2_ENABLE            0x00000080
+#define SH_FCR3_I2S2_CLK18_ENABLE      0x00008000
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_KEYLARGO_H */
index 6cd0a3bfa28033a67dd6da3997aff32c6e46127a..0654f79b06df9b81c9c00816ae0a4e9408924c1e 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_KPROBES_H
 #define _ASM_POWERPC_KPROBES_H
+#ifdef __KERNEL__
 /*
  *  Kernel Probes (KProbes)
  *
@@ -78,4 +79,5 @@ static inline int kprobe_exceptions_notify(struct notifier_block *self,
        return 0;
 }
 #endif
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_KPROBES_H */
index ea0afe34354551a998adc2e3ae85ed1a25031ea2..d3546c4c9f46070e2c4ca3036fa96eb6a88abb0d 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _PPC64_LMB_H
 #define _PPC64_LMB_H
+#ifdef __KERNEL__
 
 /*
  * Definitions for talking to the Open Firmware PROM on
@@ -78,4 +79,5 @@ lmb_end_pfn(struct lmb_region *type, unsigned long region_nr)
               lmb_size_pages(type, region_nr);
 }
 
+#endif /* __KERNEL__ */
 #endif /* _PPC64_LMB_H */
index c1bedab1515bad821642ee28d5f7cbee2e0383bd..ff82ea7c48292bcfcf194f06d1a7c88e5459b370 100644 (file)
@@ -18,6 +18,7 @@
  */
 #ifndef _ASM_POWERPC_LPPACA_H
 #define _ASM_POWERPC_LPPACA_H
+#ifdef __KERNEL__
 
 //=============================================================================
 //
@@ -128,4 +129,5 @@ struct lppaca {
        u8      pmc_save_area[256];     // PMC interrupt Area           x00-xFF
 };
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_LPPACA_H */
index c011abb8b600f1248fdfed9bb4ff9bbbd88ef87b..5348b820788cbdaf5e9dbcbfe97064f12b67b4bd 100644 (file)
@@ -27,6 +27,9 @@ struct device_node;
 struct iommu_table;
 struct rtc_time;
 struct file;
+#ifdef CONFIG_KEXEC
+struct kimage;
+#endif
 
 #ifdef CONFIG_SMP
 struct smp_ops_t {
@@ -131,7 +134,7 @@ struct machdep_calls {
        void            (*nvram_sync)(void);
 
        /* Exception handlers */
-       void            (*system_reset_exception)(struct pt_regs *regs);
+       int             (*system_reset_exception)(struct pt_regs *regs);
        int             (*machine_check_exception)(struct pt_regs *regs);
 
        /* Motherboard/chipset features. This is a kind of general purpose
@@ -207,19 +210,19 @@ struct machdep_calls {
 
        /* this is for modules, since _machine can be a define -- Cort */
        int ppc_machine;
+#endif /* CONFIG_PPC32 */
 
-#ifdef CONFIG_KEXEC
        /* Called to shutdown machine specific hardware not already controlled
         * by other drivers.
-        * XXX Should we move this one out of kexec scope?
         */
        void (*machine_shutdown)(void);
 
+#ifdef CONFIG_KEXEC
        /* Called to do the minimal shutdown needed to run a kexec'd kernel
         * to run successfully.
         * XXX Should we move this one out of kexec scope?
         */
-       void (*machine_crash_shutdown)(void);
+       void (*machine_crash_shutdown)(struct pt_regs *regs);
 
        /* Called to do what every setup is needed on image and the
         * reboot code buffer. Returns 0 on success.
@@ -237,7 +240,6 @@ struct machdep_calls {
         */
        void (*machine_kexec)(struct kimage *image);
 #endif /* CONFIG_KEXEC */
-#endif /* CONFIG_PPC32 */
 };
 
 extern void default_idle(void);
index b553dd4b139ef21c2bfb08481209a071ccf0f750..3a6cb1a513b73e2078fc27f2528304383f58ad4e 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef __MACIO_ASIC_H__
 #define __MACIO_ASIC_H__
+#ifdef __KERNEL__
 
 #include <asm/of_device.h>
 
@@ -137,4 +138,5 @@ struct macio_driver
 extern int macio_register_driver(struct macio_driver *);
 extern void macio_unregister_driver(struct macio_driver *);
 
+#endif /* __KERNEL__ */
 #endif /* __MACIO_ASIC_H__ */
index 29b0bb0086d3fc5f40e8848d82662c345d4a4a44..d096d9e76ad7ff575cdbbc7936097c9effa807b5 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_MMU_H_
 #define _ASM_POWERPC_MMU_H_
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/mmu.h>
@@ -33,7 +34,8 @@
 
 /* Location of cpu0's segment table */
 #define STAB0_PAGE     0x6
-#define STAB0_PHYS_ADDR        (STAB0_PAGE<<12)
+#define STAB0_OFFSET   (STAB0_PAGE << 12)
+#define STAB0_PHYS_ADDR        (STAB0_OFFSET + PHYSICAL_START)
 
 #ifndef __ASSEMBLY__
 extern char initial_stab[];
@@ -394,7 +396,12 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
 #define VSID_SCRAMBLE(pvsid)   (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
 #define KERNEL_VSID(ea)                VSID_SCRAMBLE(GET_ESID(ea))
 
+/* Physical address used by some IO functions */
+typedef unsigned long phys_addr_t;
+
+
 #endif /* __ASSEMBLY */
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MMU_H_ */
index ea6798c7d5fcf84c9083d6dc082f47a69145c820..1b8a25fd48f3f90f65d5d1602a49a2e4e28b1bb4 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef __ASM_POWERPC_MMU_CONTEXT_H
 #define __ASM_POWERPC_MMU_CONTEXT_H
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/mmu_context.h>
@@ -86,4 +87,5 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
 }
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_MMU_CONTEXT_H */
index 54958d6cae0440353ade0ff8a73f8668a52e5bac..88d70bae7769629c8d31a34c54aec9fe6b00ab9e 100644 (file)
@@ -6,6 +6,7 @@
  */
 #ifndef _ASM_MMZONE_H_
 #define _ASM_MMZONE_H_
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 
@@ -47,4 +48,5 @@ extern unsigned long max_pfn;
 extern int __init early_pfn_to_nid(unsigned long pfn);
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_MMZONE_H_ */
index 7ecd05e0305196d3e4b387ec3a56d5f2bfc1519b..584fabfb4f08aa9eccfb688727e109da3d021530 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_MODULE_H
 #define _ASM_POWERPC_MODULE_H
+#ifdef __KERNEL__
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -74,4 +75,5 @@ struct exception_table_entry;
 void sort_ex_table(struct exception_table_entry *start,
                   struct exception_table_entry *finish);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MODULE_H */
index 7083d1f74260b6b156d6b6ef67ac1a9c03535677..6b9e78142f4fd6ba55ea277eed989443641d38da 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_MPIC_H
 #define _ASM_POWERPC_MPIC_H
+#ifdef __KERNEL__
 
 #include <linux/irq.h>
 
@@ -117,7 +118,9 @@ typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data);
 struct mpic_irq_fixup
 {
        u8 __iomem      *base;
-       unsigned int   irq;
+       u8 __iomem      *applebase;
+       u32             data;
+       unsigned int    index;
 };
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
@@ -284,4 +287,5 @@ extern int mpic_get_irq(struct pt_regs *regs);
 /* global mpic for pSeries */
 extern struct mpic *pSeries_mpic;
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MPIC_H */
index 795533aca095b77c4e635eff0a5f652b22c4fb5b..e138edae09ddfea3209d0a3680d8e6d4ef51027d 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef _ASM_POWERPC_MAX_NUMNODES_H
 #define _ASM_POWERPC_MAX_NUMNODES_H
+#ifdef __KERNEL__
 
 /* Max 16 Nodes */
 #define NODES_SHIFT    4
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MAX_NUMNODES_H */
index 24bd8c2388ea5b912546423b04dd8ca13ed03141..f3563e11e260b7162d19b758f24d47dd1de0e956 100644 (file)
@@ -55,6 +55,7 @@ struct nvram_header {
        char name[12];
 };
 
+#ifdef __KERNEL__
 struct nvram_partition {
        struct list_head partition;
        struct nvram_header header;
@@ -69,6 +70,7 @@ extern struct nvram_partition *nvram_find_partition(int sig, const char *name);
 
 extern int pSeries_nvram_init(void);
 extern int mmio_nvram_init(void);
+#endif /* __KERNEL__ */
 
 /* PowerMac specific nvram stuffs */
 
@@ -78,6 +80,7 @@ enum {
        pmac_nvram_NR           /* MacOS Name Registry partition */
 };
 
+#ifdef __KERNEL__
 /* Return partition offset in nvram */
 extern int     pmac_get_partition(int partition);
 
@@ -91,6 +94,7 @@ extern void   nvram_sync(void);
 /* Normal access to NVRAM */
 extern unsigned char nvram_read_byte(int i);
 extern void nvram_write_byte(unsigned char c, int i);
+#endif
 
 /* Some offsets in XPRAM */
 #define PMAC_XPRAM_MACHINE_LOC 0xe4
index ddb16aae0bd656aba9b37f6cfef77be192a0402b..6249a7c396395c469dd67a0ac25ddf5edb554876 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_OF_DEVICE_H
 #define _ASM_POWERPC_OF_DEVICE_H
+#ifdef __KERNEL__
 
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
@@ -61,4 +62,5 @@ extern struct of_device *of_platform_device_create(struct device_node *np,
                                                   struct device *parent);
 extern void of_release_dev(struct device *dev);
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OF_DEVICE_H */
index 023b59772231b9ea2e9c01966c138fa83bfb3135..0d030f9dea24a551196c2f62b0e7f2a42c929c6d 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_OHARE_H
+#define _ASM_POWERPC_OHARE_H
+#ifdef __KERNEL__
 /*
  * ohare.h: definitions for using the "O'Hare" I/O controller chip.
  *
@@ -46,3 +49,6 @@
  * Contributed by Harry Eaton.
  */
 #define STARMAX_FEATURES       0xbeff7a
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_OHARE_H */
index 8013cd273cedf7edfd4312737065e3d9581538e2..338e6a7cff4a4dbf1976d69052e7c8d8c3cc892a 100644 (file)
@@ -11,6 +11,7 @@
 
 #ifndef _ASM_POWERPC_OPROFILE_IMPL_H
 #define _ASM_POWERPC_OPROFILE_IMPL_H
+#ifdef __KERNEL__
 
 #define OP_MAX_COUNTER 8
 
@@ -22,24 +23,22 @@ struct op_counter_config {
        unsigned long enabled;
        unsigned long event;
        unsigned long count;
+       /* Classic doesn't support per-counter user/kernel selection */
        unsigned long kernel;
-#ifdef __powerpc64__
-       /* We dont support per counter user/kernel selection */
-#endif
        unsigned long user;
        unsigned long unit_mask;
 };
 
 /* System-wide configuration as set via oprofilefs.  */
 struct op_system_config {
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
        unsigned long mmcr0;
        unsigned long mmcr1;
        unsigned long mmcra;
 #endif
        unsigned long enable_kernel;
        unsigned long enable_user;
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
        unsigned long backtrace_spinlocks;
 #endif
 };
@@ -49,9 +48,7 @@ struct op_powerpc_model {
        void (*reg_setup) (struct op_counter_config *,
                           struct op_system_config *,
                           int num_counters);
-#ifdef __powerpc64__
        void (*cpu_setup) (void *);
-#endif
        void (*start) (struct op_counter_config *);
        void (*stop) (void);
        void (*handle_interrupt) (struct pt_regs *,
@@ -59,10 +56,19 @@ struct op_powerpc_model {
        int num_counters;
 };
 
-#ifdef __powerpc64__
+#ifdef CONFIG_FSL_BOOKE
+extern struct op_powerpc_model op_model_fsl_booke;
+#else /* Otherwise, it's classic */
+
+#ifdef CONFIG_PPC64
 extern struct op_powerpc_model op_model_rs64;
 extern struct op_powerpc_model op_model_power4;
 
+#else /* Otherwise, CONFIG_PPC32 */
+extern struct op_powerpc_model op_model_7450;
+#endif
+
+/* All the classic PPC parts use these */
 static inline unsigned int ctr_read(unsigned int i)
 {
        switch(i) {
@@ -78,10 +84,14 @@ static inline unsigned int ctr_read(unsigned int i)
                return mfspr(SPRN_PMC5);
        case 5:
                return mfspr(SPRN_PMC6);
+
+/* No PPC32 chip has more than 6 so far */
+#ifdef CONFIG_PPC64
        case 6:
                return mfspr(SPRN_PMC7);
        case 7:
                return mfspr(SPRN_PMC8);
+#endif
        default:
                return 0;
        }
@@ -108,16 +118,21 @@ static inline void ctr_write(unsigned int i, unsigned int val)
        case 5:
                mtspr(SPRN_PMC6, val);
                break;
+
+/* No PPC32 chip has more than 6, yet */
+#ifdef CONFIG_PPC64
        case 6:
                mtspr(SPRN_PMC7, val);
                break;
        case 7:
                mtspr(SPRN_PMC8, val);
                break;
+#endif
        default:
                break;
        }
 }
-#endif /* __powerpc64__ */
+#endif /* !CONFIG_FSL_BOOKE */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OPROFILE_IMPL_H */
index c0db1ea7f7d1ba4921265eadd4bdad8f97e2daaf..ea6cfb8efb84eb84e6a83cec13d2ca66619f3732 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _PPC64_PSERIES_RECONFIG_H
 #define _PPC64_PSERIES_RECONFIG_H
+#ifdef __KERNEL__
 
 #include <linux/notifier.h>
 
@@ -22,4 +23,5 @@ static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
 static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
 #endif /* CONFIG_PPC_PSERIES */
 
+#endif /* __KERNEL__ */
 #endif /* _PPC64_PSERIES_RECONFIG_H */
index 92c765c35bd0738d452d2bc702c2f6d941525c8b..3ae52d9dc9ff16ed37c79121e55c836a02a19d82 100644 (file)
  */
 #ifndef _ASM_POWERPC_PACA_H
 #define _ASM_POWERPC_PACA_H
+#ifdef __KERNEL__
 
 #include       <linux/config.h>
 #include       <asm/types.h>
 #include       <asm/lppaca.h>
-#include       <asm/iseries/it_lp_reg_save.h>
 #include       <asm/mmu.h>
 
 register struct paca_struct *local_paca asm("r13");
@@ -31,9 +31,9 @@ struct task_struct;
  *
  * This structure is not directly accessed by firmware or the service
  * processor except for the first two pointers that point to the
- * lppaca area and the ItLpRegSave area for this CPU.  Both the
- * lppaca and ItLpRegSave objects are currently contained within the
- * PACA but they do not need to be.
+ * lppaca area and the ItLpRegSave area for this CPU.  The lppaca
+ * object is currently contained within the PACA but it doesn't need
+ * to be.
  */
 struct paca_struct {
        /*
@@ -48,7 +48,9 @@ struct paca_struct {
         * accessed by the firmware
         */
        struct lppaca *lppaca_ptr;      /* Pointer to LpPaca for PLIC */
-       struct ItLpRegSave *reg_save_ptr; /* Pointer to LpRegSave for PLIC */
+#ifdef CONFIG_PPC_ISERIES
+       void *reg_save_ptr; /* Pointer to LpRegSave for PLIC */
+#endif /* CONFIG_PPC_ISERIES */
 
        /*
         * MAGIC: the spinlock functions in arch/ppc64/lib/locks.c
@@ -59,7 +61,6 @@ struct paca_struct {
        u16 lock_token;                 /* Constant 0x8000, used in locks */
        u16 paca_index;                 /* Logical processor number */
 
-       u32 default_decr;               /* Default decrementer value */
        u64 kernel_toc;                 /* Kernel TOC address */
        u64 stab_real;                  /* Absolute address of segment table */
        u64 stab_addr;                  /* Virtual address of segment table */
@@ -90,14 +91,10 @@ struct paca_struct {
        struct task_struct *__current;  /* Pointer to current */
        u64 kstack;                     /* Saved Kernel stack addr */
        u64 stab_rr;                    /* stab/slb round-robin counter */
-       u64 next_jiffy_update_tb;       /* TB value for next jiffy update */
        u64 saved_r1;                   /* r1 save for RTAS calls */
        u64 saved_msr;                  /* MSR saved here by enter_rtas */
        u8 proc_enabled;                /* irq soft-enable flag */
 
-       /* not yet used */
-       u64 exdsi[8];           /* used for linear mapping hash table misses */
-
        /*
         * iSeries structure which the hypervisor knows about -
         * this structure should not cross a page boundary.
@@ -110,11 +107,9 @@ struct paca_struct {
         * cross a page boundary.
         */
        struct lppaca lppaca __attribute__((__aligned__(0x400)));
-#ifdef CONFIG_PPC_ISERIES
-       struct ItLpRegSave reg_save;
-#endif
 };
 
 extern struct paca_struct paca[];
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PACA_H */
index 18c1e5ee81a38c91d5bb3eed3416fd1b00fe10e4..76d7cb4b4ffc3f63ec140ccc0740c810b9ac15a3 100644 (file)
  */
 #define PAGE_MASK      (~((1 << PAGE_SHIFT) - 1))
 
+/*
+ * KERNELBASE is the virtual address of the start of the kernel, it's often
+ * the same as PAGE_OFFSET, but _might not be_.
+ *
+ * The kdump dump kernel is one example where KERNELBASE != PAGE_OFFSET.
+ *
+ * To get a physical address from a virtual one you subtract PAGE_OFFSET,
+ * _not_ KERNELBASE.
+ *
+ * If you want to know something's offset from the start of the kernel you
+ * should subtract KERNELBASE.
+ *
+ * If you want to test if something's a kernel address, use is_kernel_addr().
+ */
+
+#ifdef CONFIG_CRASH_DUMP
+/* Kdump kernel runs at 32 MB, change at your peril. */
+#define PHYSICAL_START 0x2000000
+#else
+#define PHYSICAL_START 0x0
+#endif
+
 #define PAGE_OFFSET     ASM_CONST(CONFIG_KERNEL_START)
-#define KERNELBASE      PAGE_OFFSET
+#define KERNELBASE      (PAGE_OFFSET + PHYSICAL_START)
 
 #ifdef CONFIG_DISCONTIGMEM
 #define page_to_pfn(page)      discontigmem_page_to_pfn(page)
@@ -56,7 +78,7 @@
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
-#define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
 #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
 
 /*
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       _ALIGN(addr, PAGE_SIZE)
 
+/*
+ * Don't compare things with KERNELBASE or PAGE_OFFSET to test for
+ * "kernelness", use is_kernel_addr() - it should do what you want.
+ */
+#define is_kernel_addr(x)      ((x) >= PAGE_OFFSET)
+
 #ifndef __ASSEMBLY__
 
 #undef STRICT_MM_TYPECHECKS
index 7259cfd85da911066b1642ba3e4bf1ccfbacbc9c..2677bad70f401c92236170f1fe27a1c3f4ceee51 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PAGE_32_H
 #define _ASM_POWERPC_PAGE_32_H
+#ifdef __KERNEL__
 
 #define VM_DATA_DEFAULT_FLAGS  VM_DATA_DEFAULT_FLAGS32
 
@@ -37,4 +38,5 @@ extern __inline__ int get_order(unsigned long size)
 
 #endif /* __ASSEMBLY__ */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PAGE_32_H */
index 6642c012500177fc5e6f90a6ddf84e0cfa2e5ec5..3fb061bab9ecd75f0fc912d23fc7cbb71f5c45c7 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PAGE_64_H
 #define _ASM_POWERPC_PAGE_64_H
+#ifdef __KERNEL__
 
 /*
  * Copyright (C) 2001 PPC64 Team, IBM Corp
  */
 #define PAGE_FACTOR            (PAGE_SHIFT - HW_PAGE_SHIFT)
 
-#define REGION_SIZE   4UL
-#define REGION_SHIFT  60UL
-#define REGION_MASK   (((1UL<<REGION_SIZE)-1UL)<<REGION_SHIFT)
-
-#define VMALLOCBASE            ASM_CONST(0xD000000000000000)
-#define VMALLOC_REGION_ID      (VMALLOCBASE >> REGION_SHIFT)
-#define KERNEL_REGION_ID       (KERNELBASE >> REGION_SHIFT)
-#define USER_REGION_ID         (0UL)
-#define REGION_ID(ea)          (((unsigned long)(ea)) >> REGION_SHIFT)
-
 /* Segment size */
 #define SID_SHIFT              28
 #define SID_MASK               0xfffffffffUL
@@ -180,4 +171,5 @@ extern unsigned int HPAGE_SHIFT;
 
 #include <asm-generic/page.h>
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PAGE_64_H */
index bdc724f70884609e85de0f7406c6e779a16c5ae5..094f63d4d5ca4a87743c965ae6a4bb86a2eead0c 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _ASM_POWERPC_PARAM_H
 #define _ASM_POWERPC_PARAM_H
 
-#include <linux/config.h>
-
 #ifdef __KERNEL__
 #define HZ             CONFIG_HZ       /* internal kernel timer frequency */
 #define USER_HZ                100             /* for user interfaces in "ticks" */
index d86b410a6f8bbaa45104717ce5786981a96d48d0..897e49a88a6b091dde6d8910d0553adf8578887e 100644 (file)
@@ -8,6 +8,7 @@
 
 #ifndef _ASM_POWERPC_PARPORT_H
 #define _ASM_POWERPC_PARPORT_H
+#ifdef __KERNEL__
 
 static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
 static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
@@ -15,4 +16,5 @@ static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
        return parport_pc_find_isa_ports (autoirq, autodma);
 }
 
+#endif /* __KERNEL__ */
 #endif /* !(_ASM_POWERPC_PARPORT_H) */
index 223ec7bd81da6fb1e0c0ac07a50fb1132bc1600e..1a08860e789ec7e5bae3005770bd42b63f519df5 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PCI_BRIDGE_H
 #define _ASM_POWERPC_PCI_BRIDGE_H
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/pci-bridge.h>
@@ -125,9 +126,19 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
                return bus->sysdata; /* Must be root bus (PHB) */
 }
 
+/** Find the bus corresponding to the indicated device node */
+struct pci_bus * pcibios_find_pci_bus(struct device_node *dn);
+
 extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                         struct device_node *dev, int primary);
 
+/** Remove all of the PCI devices under this bus */
+void pcibios_remove_pci_devices(struct pci_bus *bus);
+
+/** Discover new pci devices under this bus, and add them */
+void pcibios_add_pci_devices(struct pci_bus * bus);
+void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus);
+
 extern int pcibios_remove_root_bus(struct pci_controller *phb);
 
 extern void phbs_remap_io(void);
@@ -140,14 +151,27 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
        return PCI_DN(busdn)->phb;
 }
 
+extern struct pci_controller*
+pci_find_hose_for_OF_device(struct device_node* node);
+
 extern struct pci_controller *
 pcibios_alloc_controller(struct device_node *dev);
 extern void pcibios_free_controller(struct pci_controller *phb);
 
+#ifdef CONFIG_PCI
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#else
+static inline unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       return (unsigned long)-1;
+}
+#endif
+
 /* Return values for ppc_md.pci_probe_mode function */
 #define PCI_PROBE_NONE         -1      /* Don't look at this bus at all */
 #define PCI_PROBE_NORMAL       0       /* Do normal PCI probing */
 #define PCI_PROBE_DEVTREE      1       /* Instantiate from device tree */
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif
index d5934a076bd0ed68cf7485378e7a1670a7f9c0e6..5d2c9e6c4be2ba1483118e2de61b572ccbb2c2b1 100644 (file)
@@ -216,6 +216,8 @@ extern int remap_bus_range(struct pci_bus *bus);
 extern void pcibios_fixup_device_resources(struct pci_dev *dev,
                        struct pci_bus *bus);
 
+extern void pcibios_claim_one_bus(struct pci_bus *b);
+
 extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
 
 extern struct pci_dev *of_create_pci_dev(struct device_node *node,
index bfc2113b36309b58cf93795b3081e442fade1482..9f5b052784a5419ccf5298d74005b095c512dfa2 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PGALLOC_H
 #define _ASM_POWERPC_PGALLOC_H
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/pgalloc.h>
@@ -153,4 +154,5 @@ extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
 #define check_pgt_cache()      do { } while (0)
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGALLOC_H */
index 154f1840ece4d0c49e403177b8262640e91048a6..653915014dcdd7b2d64b645e2cff4a0ad6cc41b2 100644 (file)
@@ -1,3 +1,7 @@
+#ifndef _ASM_POWERPC_PGTABLE_64K_H
+#define _ASM_POWERPC_PGTABLE_64K_H
+#ifdef __KERNEL__
+
 #include <asm-generic/pgtable-nopud.h>
 
 
@@ -88,3 +92,5 @@
 
 
 #endif /*  __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_PGTABLE_64K_H */
index 0303f57366c1286ff9f1798c939f4c78a7496818..e38931379a723541eeb2504df1195b36622ec191 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_PGTABLE_H
 #define _ASM_POWERPC_PGTABLE_H
+#ifdef __KERNEL__
 
 #ifndef CONFIG_PPC64
 #include <asm-ppc/pgtable.h>
@@ -57,6 +58,17 @@ struct mm_struct;
 #define IMALLOC_BASE   (PHBS_IO_BASE + 0x80000000ul)   /* Reserve 2 gigs for PHBs */
 #define IMALLOC_END    (VMALLOC_START + PGTABLE_RANGE)
 
+/*
+ * Region IDs
+ */
+#define REGION_SHIFT           60UL
+#define REGION_MASK            (0xfUL << REGION_SHIFT)
+#define REGION_ID(ea)          (((unsigned long)(ea)) >> REGION_SHIFT)
+
+#define VMALLOC_REGION_ID      (REGION_ID(VMALLOC_START))
+#define KERNEL_REGION_ID       (REGION_ID(PAGE_OFFSET))
+#define USER_REGION_ID         (0UL)
+
 /*
  * Common bits in a linux-style PTE.  These match the bits in the
  * (hardware-defined) PowerPC PTE as closely as possible. Additional
@@ -521,4 +533,5 @@ void pgtable_cache_init(void);
 #endif /* __ASSEMBLY__ */
 
 #endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGTABLE_H */
index e9683bcff19bcec68c3b5ab16d9ee50f18299bd4..3221628130c4e27d772c8cf3b1540fbdd3d89cf0 100644 (file)
 #define PMAC_TYPE_IMAC_G5              0x152   /* iMac G5 */
 #define PMAC_TYPE_XSERVE_G5            0x153   /* Xserve G5 */
 #define PMAC_TYPE_UNKNOWN_K2           0x19f   /* Any other K2 based */
+#define PMAC_TYPE_UNKNOWN_SHASTA               0x19e   /* Any other Shasta based */
 
 /*
  * Motherboard flags
@@ -317,10 +318,6 @@ extern void pmac_register_agp_pm(struct pci_dev *bridge,
 extern void pmac_suspend_agp_for_card(struct pci_dev *dev);
 extern void pmac_resume_agp_for_card(struct pci_dev *dev);
 
-/* Used by the via-pmu driver for suspend/resume
- */
-extern void pmac_tweak_clock_spreading(int enable);
-
 /*
  * The part below is for use by macio_asic.c only, do not rely
  * on the data structures or constants below in a normal driver
@@ -341,6 +338,7 @@ enum {
        macio_pangea,
        macio_intrepid,
        macio_keylargo2,
+       macio_shasta,
 };
 
 struct macio_chip
@@ -376,5 +374,24 @@ extern struct macio_chip* macio_find(struct device_node* child, int type);
 #define MACIO_IN8(r)           (in_8(MACIO_FCR8(macio,r)))
 #define MACIO_OUT8(r,v)                (out_8(MACIO_FCR8(macio,r), (v)))
 
+/*
+ * Those are exported by pmac feature for internal use by arch code
+ * only like the platform function callbacks, do not use directly in drivers
+ */
+extern spinlock_t feature_lock;
+extern struct device_node *uninorth_node;
+extern u32 __iomem *uninorth_base;
+
+/*
+ * Uninorth reg. access. Note that Uni-N regs are big endian
+ */
+
+#define UN_REG(r)      (uninorth_base + ((r) >> 2))
+#define UN_IN(r)       (in_be32(UN_REG(r)))
+#define UN_OUT(r,v)    (out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v)    (UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v)    (UN_OUT((r), UN_IN(r) & ~(v)))
+
+
 #endif /* __PPC_ASM_PMAC_FEATURE_H */
 #endif /* __KERNEL__ */
index 809a5963d5e70432f51863d6af640604fa722b19..131011bd7e7682236434235b5081934b6ab5e5cf 100644 (file)
  */
 #ifndef __PMAC_LOW_I2C_H__
 #define __PMAC_LOW_I2C_H__
+#ifdef __KERNEL__
 
 /* i2c mode (based on the platform functions format) */
 enum {
-       pmac_low_i2c_mode_dumb          = 1,
-       pmac_low_i2c_mode_std           = 2,
-       pmac_low_i2c_mode_stdsub        = 3,
-       pmac_low_i2c_mode_combined      = 4,
+       pmac_i2c_mode_dumb      = 1,
+       pmac_i2c_mode_std       = 2,
+       pmac_i2c_mode_stdsub    = 3,
+       pmac_i2c_mode_combined  = 4,
 };
 
 /* RW bit in address */
 enum {
-       pmac_low_i2c_read               = 0x01,
-       pmac_low_i2c_write              = 0x00
+       pmac_i2c_read           = 0x01,
+       pmac_i2c_write          = 0x00
 };
 
+/* i2c bus type */
+enum {
+       pmac_i2c_bus_keywest    = 0,
+       pmac_i2c_bus_pmu        = 1,
+       pmac_i2c_bus_smu        = 2,
+};
+
+/* i2c bus features */
+enum {
+       /* can_largesub : supports >1 byte subaddresses (SMU only) */
+       pmac_i2c_can_largesub   = 0x00000001u,
+
+       /* multibus : device node holds multiple busses, bus number is
+        * encoded in bits 0xff00 of "reg" of a given device
+        */
+       pmac_i2c_multibus       = 0x00000002u,
+};
+
+/* i2c busses in the system */
+struct pmac_i2c_bus;
+struct i2c_adapter;
+
 /* Init, called early during boot */
-extern void pmac_init_low_i2c(void);
+extern int pmac_i2c_init(void);
+
+/* Lookup an i2c bus for a device-node. The node can be either the bus
+ * node itself or a device below it. In the case of a multibus, the bus
+ * node itself is the controller node, else, it's a child of the controller
+ * node
+ */
+extern struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node);
+
+/* Get the address for an i2c device. This strips the bus number if
+ * necessary. The 7 bits address is returned 1 bit right shifted so that the
+ * direction can be directly ored in
+ */
+extern u8 pmac_i2c_get_dev_addr(struct device_node *device);
+
+/* Get infos about a bus */
+extern struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus);
+extern struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_type(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_flags(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_channel(struct pmac_i2c_bus *bus);
+
+/* i2c layer adapter attach/detach */
+extern void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
+                                   struct i2c_adapter *adapter);
+extern void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
+                                   struct i2c_adapter *adapter);
+extern struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus);
+extern struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter);
+
+/* March a device or bus with an i2c adapter structure, to be used by drivers
+ * to match device-tree nodes with i2c adapters during adapter discovery
+ * callbacks
+ */
+extern int pmac_i2c_match_adapter(struct device_node *dev,
+                                 struct i2c_adapter *adapter);
+
 
-/* Locking functions exposed to i2c-keywest */
-int pmac_low_i2c_lock(struct device_node *np);
-int pmac_low_i2c_unlock(struct device_node *np);
+/* (legacy) Locking functions exposed to i2c-keywest */
+extern int pmac_low_i2c_lock(struct device_node *np);
+extern int pmac_low_i2c_unlock(struct device_node *np);
 
 /* Access functions for platform code */
-int pmac_low_i2c_open(struct device_node *np, int channel);
-int pmac_low_i2c_close(struct device_node *np);
-int pmac_low_i2c_setmode(struct device_node *np, int mode);
-int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len);
+extern int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled);
+extern void pmac_i2c_close(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode);
+extern int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+                        u32 subaddr, u8 *data,  int len);
 
+/* Suspend/resume code called by via-pmu directly for now */
+extern void pmac_pfunc_i2c_suspend(void);
+extern void pmac_pfunc_i2c_resume(void);
 
+#endif /* __KERNEL__ */
 #endif /* __PMAC_LOW_I2C_H__ */
diff --git a/include/asm-powerpc/pmac_pfunc.h b/include/asm-powerpc/pmac_pfunc.h
new file mode 100644 (file)
index 0000000..d9728c8
--- /dev/null
@@ -0,0 +1,253 @@
+#ifndef __PMAC_PFUNC_H__
+#define __PMAC_PFUNC_H__
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+/* Flags in command lists */
+#define PMF_FLAGS_ON_INIT              0x80000000u
+#define PMF_FLGAS_ON_TERM              0x40000000u
+#define PMF_FLAGS_ON_SLEEP             0x20000000u
+#define PMF_FLAGS_ON_WAKE              0x10000000u
+#define PMF_FLAGS_ON_DEMAND            0x08000000u
+#define PMF_FLAGS_INT_GEN              0x04000000u
+#define PMF_FLAGS_HIGH_SPEED           0x02000000u
+#define PMF_FLAGS_LOW_SPEED            0x01000000u
+#define PMF_FLAGS_SIDE_EFFECTS         0x00800000u
+
+/*
+ * Arguments to a platform function call.
+ *
+ * NOTE: By convention, pointer arguments point to an u32
+ */
+struct pmf_args {
+       union {
+               u32 v;
+               u32 *p;
+       } u[4];
+       unsigned int count;
+};
+
+/*
+ * A driver capable of interpreting commands provides a handlers
+ * structure filled with whatever handlers are implemented by this
+ * driver. Non implemented handlers are left NULL.
+ *
+ * PMF_STD_ARGS are the same arguments that are passed to the parser
+ * and that gets passed back to the various handlers.
+ *
+ * Interpreting a given function always start with a begin() call which
+ * returns an instance data to be passed around subsequent calls, and
+ * ends with an end() call. This allows the low level driver to implement
+ * locking policy or per-function instance data.
+ *
+ * For interrupt capable functions, irq_enable() is called when a client
+ * registers, and irq_disable() is called when the last client unregisters
+ * Note that irq_enable & irq_disable are called within a semaphore held
+ * by the core, thus you should not try to register yourself to some other
+ * pmf interrupt during those calls.
+ */
+
+#define PMF_STD_ARGS   struct pmf_function *func, void *instdata, \
+                       struct pmf_args *args
+
+struct pmf_function;
+
+struct pmf_handlers {
+       void * (*begin)(struct pmf_function *func, struct pmf_args *args);
+       void (*end)(struct pmf_function *func, void *instdata);
+
+       int (*irq_enable)(struct pmf_function *func);
+       int (*irq_disable)(struct pmf_function *func);
+
+       int (*write_gpio)(PMF_STD_ARGS, u8 value, u8 mask);
+       int (*read_gpio)(PMF_STD_ARGS, u8 mask, int rshift, u8 xor);
+
+       int (*write_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask);
+       int (*read_reg32)(PMF_STD_ARGS, u32 offset);
+       int (*write_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask);
+       int (*read_reg16)(PMF_STD_ARGS, u32 offset);
+       int (*write_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask);
+       int (*read_reg8)(PMF_STD_ARGS, u32 offset);
+
+       int (*delay)(PMF_STD_ARGS, u32 duration);
+
+       int (*wait_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask);
+       int (*wait_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask);
+       int (*wait_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask);
+
+       int (*read_i2c)(PMF_STD_ARGS, u32 len);
+       int (*write_i2c)(PMF_STD_ARGS, u32 len, const u8 *data);
+       int (*rmw_i2c)(PMF_STD_ARGS, u32 masklen, u32 valuelen, u32 totallen,
+                      const u8 *maskdata, const u8 *valuedata);
+
+       int (*read_cfg)(PMF_STD_ARGS, u32 offset, u32 len);
+       int (*write_cfg)(PMF_STD_ARGS, u32 offset, u32 len, const u8 *data);
+       int (*rmw_cfg)(PMF_STD_ARGS, u32 offset, u32 masklen, u32 valuelen,
+                      u32 totallen, const u8 *maskdata, const u8 *valuedata);
+
+       int (*read_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len);
+       int (*write_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len, const u8 *data);
+       int (*set_i2c_mode)(PMF_STD_ARGS, int mode);
+       int (*rmw_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 masklen, u32 valuelen,
+                          u32 totallen, const u8 *maskdata,
+                          const u8 *valuedata);
+
+       int (*read_reg32_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+                              u32 xor);
+       int (*read_reg16_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+                              u32 xor);
+       int (*read_reg8_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+                             u32 xor);
+
+       int (*write_reg32_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+       int (*write_reg16_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+       int (*write_reg8_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+
+       int (*mask_and_compare)(PMF_STD_ARGS, u32 len, const u8 *maskdata,
+                               const u8 *valuedata);
+
+       struct module *owner;
+};
+
+
+/*
+ * Drivers who expose platform functions register at init time, this
+ * causes the platform functions for that device node to be parsed in
+ * advance and associated with the device. The data structures are
+ * partially public so a driver can walk the list of platform functions
+ * and eventually inspect the flags
+ */
+struct pmf_device;
+
+struct pmf_function {
+       /* All functions for a given driver are linked */
+       struct list_head        link;
+
+       /* Function node & driver data */
+       struct device_node      *node;
+       void                    *driver_data;
+
+       /* For internal use by core */
+       struct pmf_device       *dev;
+
+       /* The name is the "xxx" in "platform-do-xxx", this is how
+        * platform functions are identified by this code. Some functions
+        * only operate for a given target, in which case the phandle is
+        * here (or 0 if the filter doesn't apply)
+        */
+       const char              *name;
+       u32                     phandle;
+
+       /* The flags for that function. You can have several functions
+        * with the same name and different flag
+        */
+       u32                     flags;
+
+       /* The actual tokenized function blob */
+       const void              *data;
+       unsigned int            length;
+
+       /* Interrupt clients */
+       struct list_head        irq_clients;
+
+       /* Refcounting */
+       struct kref             ref;
+};
+
+/*
+ * For platform functions that are interrupts, one can register
+ * irq_client structures. You canNOT use the same structure twice
+ * as it contains a link member. Also, the callback is called with
+ * a spinlock held, you must not call back into any of the pmf_* functions
+ * from within that callback
+ */
+struct pmf_irq_client {
+       void                    (*handler)(void *data);
+       void                    *data;
+       struct module           *owner;
+       struct list_head        link;
+};
+
+
+/*
+ * Register/Unregister a function-capable driver and its handlers
+ */
+extern int pmf_register_driver(struct device_node *np,
+                             struct pmf_handlers *handlers,
+                             void *driverdata);
+
+extern void pmf_unregister_driver(struct device_node *np);
+
+
+/*
+ * Register/Unregister interrupt clients
+ */
+extern int pmf_register_irq_client(struct device_node *np,
+                                  const char *name,
+                                  struct pmf_irq_client *client);
+
+extern void pmf_unregister_irq_client(struct device_node *np,
+                                     const char *name,
+                                     struct pmf_irq_client *client);
+
+/*
+ * Called by the handlers when an irq happens
+ */
+extern void pmf_do_irq(struct pmf_function *func);
+
+
+/*
+ * Low level call to platform functions.
+ *
+ * The phandle can filter on the target object for functions that have
+ * multiple targets, the flags allow you to restrict the call to a given
+ * combination of flags.
+ *
+ * The args array contains as many arguments as is required by the function,
+ * this is dependent on the function you are calling, unfortunately Apple
+ * mecanism provides no way to encode that so you have to get it right at
+ * the call site. Some functions require no args, in which case, you can
+ * pass NULL.
+ *
+ * You can also pass NULL to the name. This will match any function that has
+ * the appropriate combination of flags & phandle or you can pass 0 to the
+ * phandle to match any
+ */
+extern int pmf_do_functions(struct device_node *np, const char *name,
+                           u32 phandle, u32 flags, struct pmf_args *args);
+
+
+
+/*
+ * High level call to a platform function.
+ *
+ * This one looks for the platform-xxx first so you should call it to the
+ * actual target if any. It will fallback to platform-do-xxx if it can't
+ * find one. It will also exclusively target functions that have
+ * the "OnDemand" flag.
+ */
+
+extern int pmf_call_function(struct device_node *target, const char *name,
+                            struct pmf_args *args);
+
+
+/*
+ * For low latency interrupt usage, you can lookup for on-demand functions
+ * using the functions below
+ */
+
+extern struct pmf_function *pmf_find_function(struct device_node *target,
+                                             const char *name);
+
+extern struct pmf_function * pmf_get_function(struct pmf_function *func);
+extern void pmf_put_function(struct pmf_function *func);
+
+extern int pmf_call_one(struct pmf_function *func, struct pmf_args *args);
+
+
+/* Suspend/resume code called by via-pmu directly for now */
+extern void pmac_pfunc_base_suspend(void);
+extern void pmac_pfunc_base_resume(void);
+
+#endif /* __PMAC_PFUNC_H__ */
index 5f41f3a2b293cfd304795330f2f758e345dd67fc..07d6a427931983d4df83ea146083a289f3f7f980 100644 (file)
@@ -18,6 +18,7 @@
  */
 #ifndef _POWERPC_PMC_H
 #define _POWERPC_PMC_H
+#ifdef __KERNEL__
 
 #include <asm/ptrace.h>
 
@@ -44,4 +45,5 @@ void dump_pmcs(void);
 extern struct op_powerpc_model op_model_fsl_booke;
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _POWERPC_PMC_H */
index 36cdc869e580146d573d5daf070f36b63028365b..bdef312900a1d23c2b98708cf34aa42733492f53 100644 (file)
@@ -8,6 +8,7 @@
  */
 #ifndef _ASM_POWERPC_PPC_PCI_H
 #define _ASM_POWERPC_PPC_PCI_H
+#ifdef __KERNEL__
 
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
@@ -93,4 +94,5 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag);
 
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PPC_PCI_H */
index c27baa0563feaa4020b330a29b480f2748aac9e2..0dc798d46ea462bc33759f1637f708928c61bbc7 100644 (file)
@@ -94,6 +94,7 @@
 #define RFDI           .long 0x4c00004e        /* rfdi instruction */
 #define RFMCI          .long 0x4c00004c        /* rfmci instruction */
 
+#ifdef __KERNEL__
 #ifdef CONFIG_PPC64
 
 #define XGLUE(a,b) a##b
@@ -325,6 +326,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
 #define CLR_TOP32(r)
 #endif
 
+#endif /* __KERNEL__ */
+
 /* The boring bits... */
 
 /* Condition Register Bit Fields */
index d12382d292d421931234e1d59007e4f070bf376b..415fa393b00c554de51282b6a5f6db09ed050a77 100644 (file)
@@ -10,7 +10,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <asm/reg.h>
 
 #ifndef __ASSEMBLY__
@@ -50,6 +49,7 @@
 #define _CHRP_IBM      0x05    /* IBM chrp, the longtrail and longtrail 2 */
 #define _CHRP_Pegasos  0x06    /* Genesi/bplan's Pegasos and Pegasos2 */
 
+#ifdef __KERNEL__
 #define platform_is_pseries()  (_machine == PLATFORM_PSERIES || \
                                 _machine == PLATFORM_PSERIES_LPAR)
 #define platform_is_lpar()     (!!(_machine & PLATFORM_LPAR))
@@ -68,7 +68,6 @@ extern int _chrp_type;
  * vendor. Board revision is also made available. This will be moved
  * elsewhere soon
  */
-extern unsigned char ucSystemType;
 extern unsigned char ucBoardRev;
 extern unsigned char ucBoardRevMaj, ucBoardRevMin;
 
@@ -82,7 +81,7 @@ extern unsigned char ucBoardRevMaj, ucBoardRevMin;
 #else
 #define _machine 0
 #endif /* CONFIG_PPC_MULTIPLATFORM */
-
+#endif /* __KERNEL__ */
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
index f999df1c5c90bc18c994fe4e83b3b2cb4b1f9e57..329e9bf62260cd69c074430224b547855c70bd12 100644 (file)
@@ -65,49 +65,11 @@ struct boot_param_header
 typedef u32 phandle;
 typedef u32 ihandle;
 
-struct address_range {
-       unsigned long space;
-       unsigned long address;
-       unsigned long size;
-};
-
 struct interrupt_info {
        int     line;
        int     sense;          /* +ve/-ve logic, edge or level, etc. */
 };
 
-struct pci_address {
-       u32 a_hi;
-       u32 a_mid;
-       u32 a_lo;
-};
-
-struct isa_address {
-       u32 a_hi;
-       u32 a_lo;
-};
-
-struct isa_range {
-       struct isa_address isa_addr;
-       struct pci_address pci_addr;
-       unsigned int size;
-};
-
-struct reg_property {
-       unsigned long address;
-       unsigned long size;
-};
-
-struct reg_property32 {
-       unsigned int address;
-       unsigned int size;
-};
-
-struct reg_property64 {
-       u64 address;
-       u64 size;
-};
-
 struct property {
        char    *name;
        int     length;
@@ -120,8 +82,6 @@ struct device_node {
        char    *type;
        phandle node;
        phandle linux_phandle;
-       int     n_addrs;
-       struct  address_range *addrs;
        int     n_intrs;
        struct  interrupt_info *intrs;
        char    *full_name;
@@ -223,5 +183,36 @@ extern struct resource *request_OF_resource(struct device_node* node,
                                int index, const char* name_postfix);
 extern int release_OF_resource(struct device_node* node, int index);
 
+
+/*
+ * OF address retreival & translation
+ */
+
+
+/* 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, u32 *addr);
+
+/* Extract an address from a device, returns the region size and
+ * the address space flags too. The PCI version uses a BAR number
+ * instead of an absolute index
+ */
+extern u32 *of_get_address(struct device_node *dev, int index,
+                          u64 *size, unsigned int *flags);
+extern u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+                              u64 *size, unsigned int *flags);
+
+/* Get an address as a resource. Note that if your address is
+ * a PIO address, the conversion will fail if the physical address
+ * can't be internally converted to an IO token with
+ * pci_address_to_pio(), that is because it's either called to early
+ * or it can't be matched to any host bridge IO space
+ */
+extern int of_address_to_resource(struct device_node *dev, int index,
+                                 struct resource *r);
+extern int of_pci_address_to_resource(struct device_node *dev, int bar,
+                                     struct resource *r);
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PROM_H */
index 1f7ecdb0b6cebf6e4156efac91a5ede01440e48a..9c550b3148231418b99f63403f0631c2ef2402fa 100644 (file)
@@ -87,7 +87,7 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 
 #define force_successful_syscall_return()   \
        do { \
-               current_thread_info()->syscall_noerror = 1; \
+               set_thread_flag(TIF_NOERROR); \
        } while(0)
 
 /*
index eb392d038ed7dacdaea492f65f6311494bed17cd..12ecc9b9f2855403dc1cc1ab4de2adf9842ab2bf 100644 (file)
 #define SPRN_CTR       0x009   /* Count Register */
 #define SPRN_CTRLF     0x088
 #define SPRN_CTRLT     0x098
+#define   CTRL_CT      0xc0000000      /* current thread */
+#define   CTRL_CT0     0x80000000      /* thread 0 */
+#define   CTRL_CT1     0x40000000      /* thread 1 */
+#define   CTRL_TE      0x00c00000      /* thread enable */
 #define   CTRL_RUNLATCH        0x1
 #define SPRN_DABR      0x3F5   /* Data Address Breakpoint Register */
 #define   DABR_TRANSLATION     (1UL << 2)
 #define        SPRN_HID6       0x3F9   /* BE HID 6 */
 #define          HID6_LB       (0x0F<<12) /* Concurrent Large Page Modes */
 #define          HID6_DLP      (1<<20) /* Disable all large page modes (4K only) */
-#define        SPRN_TSCR       0x399   /* Thread switch control on BE */
-#define        SPRN_TTR        0x39A   /* Thread switch timeout on BE */
-#define          TSCR_DEC_ENABLE       0x200000 /* Decrementer Interrupt */
-#define          TSCR_EE_ENABLE        0x100000 /* External Interrupt */
-#define          TSCR_EE_BOOST         0x080000 /* External Interrupt Boost */
+#define        SPRN_TSC_CELL   0x399   /* Thread switch control on Cell */
+#define          TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */
+#define          TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */
+#define          TSC_CELL_EE_ENABLE    0x100000 /* External Interrupt */
+#define          TSC_CELL_EE_BOOST     0x080000 /* External Interrupt Boost */
 #define        SPRN_TSC        0x3FD   /* Thread switch control on others */
 #define        SPRN_TST        0x3FC   /* Thread switch timeout on others */
 #if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
 #define SPRN_SPRG7     0x117   /* Special Purpose Register General 7 */
 #define SPRN_SRR0      0x01A   /* Save/Restore Register 0 */
 #define SPRN_SRR1      0x01B   /* Save/Restore Register 1 */
+#define   SRR1_WAKEMASK                0x00380000 /* reason for wakeup */
+#define   SRR1_WAKERESET       0x00380000 /* System reset */
+#define   SRR1_WAKESYSERR      0x00300000 /* System error */
+#define   SRR1_WAKEEE          0x00200000 /* External interrupt */
+#define   SRR1_WAKEMT          0x00280000 /* mtctrl */
+#define   SRR1_WAKEDEC         0x00180000 /* Decrementer interrupt */
+#define   SRR1_WAKETHERM       0x00100000 /* Thermal management interrupt */
+
 #ifndef SPRN_SVR
 #define SPRN_SVR       0x11E   /* System Version Register */
 #endif
 #define SPRN_SDAR      781
 
 #else /* 32-bit */
-#define SPRN_MMCR0     0x3B8   /* Monitor Mode Control Register 0 */
-#define SPRN_MMCR1     0x3BC   /* Monitor Mode Control Register 1 */
-#define SPRN_PMC1      0x3B9   /* Performance Counter Register 1 */
-#define SPRN_PMC2      0x3BA   /* Performance Counter Register 2 */
-#define SPRN_PMC3      0x3BD   /* Performance Counter Register 3 */
-#define SPRN_PMC4      0x3BE   /* Performance Counter Register 4 */
+#define SPRN_MMCR0     952     /* Monitor Mode Control Register 0 */
+#define   MMCR0_FC     0x80000000UL /* freeze counters */
+#define   MMCR0_FCS    0x40000000UL /* freeze in supervisor state */
+#define   MMCR0_FCP    0x20000000UL /* freeze in problem state */
+#define   MMCR0_FCM1   0x10000000UL /* freeze counters while MSR mark = 1 */
+#define   MMCR0_FCM0   0x08000000UL /* freeze counters while MSR mark = 0 */
+#define   MMCR0_PMXE   0x04000000UL /* performance monitor exception enable */
+#define   MMCR0_FCECE  0x02000000UL /* freeze ctrs on enabled cond or event */
+#define   MMCR0_TBEE   0x00400000UL /* time base exception enable */
+#define   MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/
+#define   MMCR0_PMCnCE 0x00004000UL /* count enable for all but PMC 1*/
+#define   MMCR0_TRIGGER        0x00002000UL /* TRIGGER enable */
+#define   MMCR0_PMC1SEL        0x00001fc0UL /* PMC 1 Event */
+#define   MMCR0_PMC2SEL        0x0000003fUL /* PMC 2 Event */
+
+#define SPRN_MMCR1     956
+#define   MMCR1_PMC3SEL        0xf8000000UL /* PMC 3 Event */
+#define   MMCR1_PMC4SEL        0x07c00000UL /* PMC 4 Event */
+#define   MMCR1_PMC5SEL        0x003e0000UL /* PMC 5 Event */
+#define   MMCR1_PMC6SEL 0x0001f800UL /* PMC 6 Event */
+#define SPRN_MMCR2     944
+#define SPRN_PMC1      953     /* Performance Counter Register 1 */
+#define SPRN_PMC2      954     /* Performance Counter Register 2 */
+#define SPRN_PMC3      957     /* Performance Counter Register 3 */
+#define SPRN_PMC4      958     /* Performance Counter Register 4 */
+#define SPRN_PMC5      945     /* Performance Counter Register 5 */
+#define SPRN_PMC6      946     /* Performance Counter Register 6 */
+
+#define SPRN_SIAR      955     /* Sampled Instruction Address Register */
 
 /* Bit definitions for MMCR0 and PMC1 / PMC2. */
 #define MMCR0_PMC1_CYCLES      (1 << 7)
 #define MMCR0_PMC2_CYCLES      0x1
 #define MMCR0_PMC2_ITLB                0x7
 #define MMCR0_PMC2_LOADMISSTIME        0x5
-#define MMCR0_PMXE     (1 << 26)
 #endif
 
 /* Processor Version Register (PVR) field extraction */
index d1bb611ea626190189cf80d36d6982d2f2e607a9..3428889e27b78f04ae563ca47edda4e12f2b8e1e 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _POWERPC_RTAS_H
 #define _POWERPC_RTAS_H
+#ifdef __KERNEL__
 
 #include <linux/spinlock.h>
 #include <asm/page.h>
@@ -229,4 +230,5 @@ extern unsigned long rtas_rmo_buf;
 
 #define GLOBAL_INTERRUPT_QUEUE 9005
 
+#endif /* __KERNEL__ */
 #endif /* _POWERPC_RTAS_H */
index 1e1cfe12882b8017fff4b6b9a9f158784a02c0ff..853765eb1f6584e23edc6f1c8c3272814c0fa395 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _ASM_POWERPC_SECCOMP_H
+#define _ASM_POWERPC_SECCOMP_H
 
+#ifdef __KERNEL__
 #include <linux/thread_info.h>
+#endif
+
 #include <linux/unistd.h>
 
 #define __NR_seccomp_read __NR_read
index 47be2ac2a925cef5caf37aec8b9e0caec8ae9da5..916018e425c4dc7112f6c0c1f49f884118d4bd0b 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_SECTIONS_H
 #define _ASM_POWERPC_SECTIONS_H
+#ifdef __KERNEL__
 
 #include <asm-generic/sections.h>
 
@@ -17,4 +18,5 @@ static inline int in_kernel_text(unsigned long addr)
 
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SECTIONS_H */
index b273d630b32ffea833e3fec9fbf76243d2666d86..6dc9546d6908c2604692a531a16043fa1983f6f5 100644 (file)
@@ -15,4 +15,6 @@
 /* Default baud base if not found in device-tree */
 #define BASE_BAUD ( 1843200 / 16 )
 
+extern void find_legacy_serial_ports(void);
+
 #endif /* _PPC64_SERIAL_H */
index 694c8d2dab8777d67094c0ef610a5bc4c3844160..a4d8f864854125e1f1bdd369738519d844f7538e 100644 (file)
@@ -2,10 +2,13 @@
 #define _ASM_POWERPC_SIGNAL_H
 
 #include <linux/types.h>
-#include <linux/config.h>
 
 #define _NSIG          64
-#define _NSIG_BPW      BITS_PER_LONG
+#ifdef __powerpc64__
+#define _NSIG_BPW      64
+#else
+#define _NSIG_BPW      32
+#endif
 #define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
 
 typedef unsigned long old_sigset_t;            /* at least 32 bits */
index 76c29a9784ddb3ece86c1718f0edf56c1e034470..134c2b5be0f284f600ec9bfebb41ef8b170925b1 100644 (file)
@@ -4,9 +4,11 @@
 /*
  * Definitions for talking to the SMU chip in newer G5 PowerMacs
  */
-
+#ifdef __KERNEL__
 #include <linux/config.h>
 #include <linux/list.h>
+#endif
+#include <linux/types.h>
 
 /*
  * Known SMU commands
@@ -356,6 +358,9 @@ extern unsigned long smu_cmdbuf_abs;
  * Kenrel asynchronous i2c interface
  */
 
+#define SMU_I2C_READ_MAX       0x1d
+#define SMU_I2C_WRITE_MAX      0x15
+
 /* SMU i2c header, exactly matches i2c header on wire */
 struct smu_i2c_param
 {
@@ -366,12 +371,9 @@ struct smu_i2c_param
        u8      subaddr[3];     /* subaddress */
        u8      caddr;          /* combined address, filled by SMU driver */
        u8      datalen;        /* length of transfer */
-       u8      data[7];        /* data */
+       u8      data[SMU_I2C_READ_MAX]; /* data */
 };
 
-#define SMU_I2C_READ_MAX       0x0d
-#define SMU_I2C_WRITE_MAX      0x05
-
 struct smu_i2c_cmd
 {
        /* public */
@@ -385,7 +387,7 @@ struct smu_i2c_cmd
        int                     read;
        int                     stage;
        int                     retries;
-       u8                      pdata[0x10];
+       u8                      pdata[32];
        struct list_head        link;
 };
 
@@ -487,8 +489,8 @@ struct smu_sdbp_slotspow {
 #define SMU_SDB_SENSORTREE_ID          0x25
 
 struct smu_sdbp_sensortree {
-       u8      model_id;
-       u8      unknown[3];
+       __u8    model_id;
+       __u8    unknown[3];
 };
 
 /* This partition contains CPU thermal control PID informations. So far
@@ -498,13 +500,13 @@ struct smu_sdbp_sensortree {
 #define SMU_SDB_CPUPIDDATA_ID          0x17
 
 struct smu_sdbp_cpupiddata {
-       u8      unknown1;
-       u8      target_temp_delta;
-       u8      unknown2;
-       u8      history_len;
-       s16     power_adj;
-       u16     max_power;
-       s32     gp,gr,gd;
+       __u8    unknown1;
+       __u8    target_temp_delta;
+       __u8    unknown2;
+       __u8    history_len;
+       __s16   power_adj;
+       __u16   max_power;
+       __s32   gp,gr,gd;
 };
 
 
@@ -517,7 +519,7 @@ struct smu_sdbp_cpupiddata {
  * if not found. The data format is described below
  */
 extern struct smu_sdbp_header *smu_get_sdb_partition(int id,
-                                                    unsigned int *size);
+                                       unsigned int *size);
 
 #endif /* __KERNEL__ */
 
index ba1b34fdb967e86c7cd761f8e91c2317cd5adf36..38b1ea3b58fd43ba801aeca6dbce186616b60ecd 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_SPARSEMEM_H
 #define _ASM_POWERPC_SPARSEMEM_H 1
+#ifdef __KERNEL__
 
 #ifdef CONFIG_SPARSEMEM
 /*
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 extern void create_section_mapping(unsigned long start, unsigned long end);
+#ifdef CONFIG_NUMA
+extern int hot_add_scn_to_nid(unsigned long scn_addr);
+#else
+static inline int hot_add_scn_to_nid(unsigned long scn_addr)
+{
+       return 0;
+}
+#endif /* CONFIG_NUMA */
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
 #endif /* CONFIG_SPARSEMEM */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SPARSEMEM_H */
index caa4b14e0e94785910d1ad188626c654b13f10dc..754900901cd8fbeb05673bdb086a6f41a1b92655 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
+#ifdef __KERNEL__
 
 /*
  * Simple spin lock operations.  
@@ -266,4 +267,5 @@ static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
        rw->lock = 0;
 }
 
+#endif /* __KERNEL__ */
 #endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
new file mode 100644 (file)
index 0000000..38bacf2
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * SPU core / file system interface and HW structures
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@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.
+ */
+
+#ifndef _SPU_H
+#define _SPU_H
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/kref.h>
+#include <linux/workqueue.h>
+
+#define LS_SIZE (256 * 1024)
+#define LS_ADDR_MASK (LS_SIZE - 1)
+
+#define MFC_PUT_CMD             0x20
+#define MFC_PUTS_CMD            0x28
+#define MFC_PUTR_CMD            0x30
+#define MFC_PUTF_CMD            0x22
+#define MFC_PUTB_CMD            0x21
+#define MFC_PUTFS_CMD           0x2A
+#define MFC_PUTBS_CMD           0x29
+#define MFC_PUTRF_CMD           0x32
+#define MFC_PUTRB_CMD           0x31
+#define MFC_PUTL_CMD            0x24
+#define MFC_PUTRL_CMD           0x34
+#define MFC_PUTLF_CMD           0x26
+#define MFC_PUTLB_CMD           0x25
+#define MFC_PUTRLF_CMD          0x36
+#define MFC_PUTRLB_CMD          0x35
+
+#define MFC_GET_CMD             0x40
+#define MFC_GETS_CMD            0x48
+#define MFC_GETF_CMD            0x42
+#define MFC_GETB_CMD            0x41
+#define MFC_GETFS_CMD           0x4A
+#define MFC_GETBS_CMD           0x49
+#define MFC_GETL_CMD            0x44
+#define MFC_GETLF_CMD           0x46
+#define MFC_GETLB_CMD           0x45
+
+#define MFC_SDCRT_CMD           0x80
+#define MFC_SDCRTST_CMD         0x81
+#define MFC_SDCRZ_CMD           0x89
+#define MFC_SDCRS_CMD           0x8D
+#define MFC_SDCRF_CMD           0x8F
+
+#define MFC_GETLLAR_CMD         0xD0
+#define MFC_PUTLLC_CMD          0xB4
+#define MFC_PUTLLUC_CMD         0xB0
+#define MFC_PUTQLLUC_CMD        0xB8
+#define MFC_SNDSIG_CMD          0xA0
+#define MFC_SNDSIGB_CMD         0xA1
+#define MFC_SNDSIGF_CMD         0xA2
+#define MFC_BARRIER_CMD         0xC0
+#define MFC_EIEIO_CMD           0xC8
+#define MFC_SYNC_CMD            0xCC
+
+#define MFC_MIN_DMA_SIZE_SHIFT  4       /* 16 bytes */
+#define MFC_MAX_DMA_SIZE_SHIFT  14      /* 16384 bytes */
+#define MFC_MIN_DMA_SIZE        (1 << MFC_MIN_DMA_SIZE_SHIFT)
+#define MFC_MAX_DMA_SIZE        (1 << MFC_MAX_DMA_SIZE_SHIFT)
+#define MFC_MIN_DMA_SIZE_MASK   (MFC_MIN_DMA_SIZE - 1)
+#define MFC_MAX_DMA_SIZE_MASK   (MFC_MAX_DMA_SIZE - 1)
+#define MFC_MIN_DMA_LIST_SIZE   0x0008  /*   8 bytes */
+#define MFC_MAX_DMA_LIST_SIZE   0x4000  /* 16K bytes */
+
+#define MFC_TAGID_TO_TAGMASK(tag_id)  (1 << (tag_id & 0x1F))
+
+/* Events for Channels 0-2 */
+#define MFC_DMA_TAG_STATUS_UPDATE_EVENT     0x00000001
+#define MFC_DMA_TAG_CMD_STALL_NOTIFY_EVENT  0x00000002
+#define MFC_DMA_QUEUE_AVAILABLE_EVENT       0x00000008
+#define MFC_SPU_MAILBOX_WRITTEN_EVENT       0x00000010
+#define MFC_DECREMENTER_EVENT               0x00000020
+#define MFC_PU_INT_MAILBOX_AVAILABLE_EVENT  0x00000040
+#define MFC_PU_MAILBOX_AVAILABLE_EVENT      0x00000080
+#define MFC_SIGNAL_2_EVENT                  0x00000100
+#define MFC_SIGNAL_1_EVENT                  0x00000200
+#define MFC_LLR_LOST_EVENT                  0x00000400
+#define MFC_PRIV_ATTN_EVENT                 0x00000800
+#define MFC_MULTI_SRC_EVENT                 0x00001000
+
+/* Flags indicating progress during context switch. */
+#define SPU_CONTEXT_SWITCH_PENDING     0UL
+#define SPU_CONTEXT_SWITCH_ACTIVE      1UL
+
+struct spu_context;
+struct spu_runqueue;
+
+struct spu {
+       char *name;
+       unsigned long local_store_phys;
+       u8 *local_store;
+       struct spu_problem __iomem *problem;
+       struct spu_priv1 __iomem *priv1;
+       struct spu_priv2 __iomem *priv2;
+       struct list_head list;
+       struct list_head sched_list;
+       int number;
+       u32 isrc;
+       u32 node;
+       u64 flags;
+       u64 dar;
+       u64 dsisr;
+       struct kref kref;
+       size_t ls_size;
+       unsigned int slb_replace;
+       struct mm_struct *mm;
+       struct spu_context *ctx;
+       struct spu_runqueue *rq;
+       unsigned long long timestamp;
+       pid_t pid;
+       int prio;
+       int class_0_pending;
+       spinlock_t register_lock;
+
+       u32 stop_code;
+       void (* wbox_callback)(struct spu *spu);
+       void (* ibox_callback)(struct spu *spu);
+       void (* stop_callback)(struct spu *spu);
+
+       char irq_c0[8];
+       char irq_c1[8];
+       char irq_c2[8];
+};
+
+struct spu *spu_alloc(void);
+void spu_free(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);
+
+extern struct spufs_calls {
+       asmlinkage long (*create_thread)(const char __user *name,
+                                       unsigned int flags, mode_t mode);
+       asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
+                                               __u32 __user *ustatus);
+       struct module *owner;
+} spufs_calls;
+
+#ifdef CONFIG_SPU_FS_MODULE
+int register_spu_syscalls(struct spufs_calls *calls);
+void unregister_spu_syscalls(struct spufs_calls *calls);
+#else
+static inline int register_spu_syscalls(struct spufs_calls *calls)
+{
+       return 0;
+}
+static inline void unregister_spu_syscalls(struct spufs_calls *calls)
+{
+}
+#endif /* MODULE */
+
+
+/* access to priv1 registers */
+void spu_int_mask_and(struct spu *spu, int class, u64 mask);
+void spu_int_mask_or(struct spu *spu, int class, u64 mask);
+void spu_int_mask_set(struct spu *spu, int class, u64 mask);
+u64 spu_int_mask_get(struct spu *spu, int class);
+void spu_int_stat_clear(struct spu *spu, int class, u64 stat);
+u64 spu_int_stat_get(struct spu *spu, int class);
+void spu_int_route_set(struct spu *spu, u64 route);
+u64 spu_mfc_dar_get(struct spu *spu);
+u64 spu_mfc_dsisr_get(struct spu *spu);
+void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr);
+void spu_mfc_sdr_set(struct spu *spu, u64 sdr);
+void spu_mfc_sr1_set(struct spu *spu, u64 sr1);
+u64 spu_mfc_sr1_get(struct spu *spu);
+void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id);
+u64 spu_mfc_tclass_id_get(struct spu *spu);
+void spu_tlb_invalidate(struct spu *spu);
+void spu_resource_allocation_groupID_set(struct spu *spu, u64 id);
+u64 spu_resource_allocation_groupID_get(struct spu *spu);
+void spu_resource_allocation_enable_set(struct spu *spu, u64 enable);
+u64 spu_resource_allocation_enable_get(struct spu *spu);
+
+
+/*
+ * This defines the Local Store, Problem Area and Privlege Area of an SPU.
+ */
+
+union mfc_tag_size_class_cmd {
+       struct {
+               u16 mfc_size;
+               u16 mfc_tag;
+               u8  pad;
+               u8  mfc_rclassid;
+               u16 mfc_cmd;
+       } u;
+       struct {
+               u32 mfc_size_tag32;
+               u32 mfc_class_cmd32;
+       } by32;
+       u64 all64;
+};
+
+struct mfc_cq_sr {
+       u64 mfc_cq_data0_RW;
+       u64 mfc_cq_data1_RW;
+       u64 mfc_cq_data2_RW;
+       u64 mfc_cq_data3_RW;
+};
+
+struct spu_problem {
+#define MS_SYNC_PENDING         1L
+       u64 spc_mssync_RW;                                      /* 0x0000 */
+       u8  pad_0x0008_0x3000[0x3000 - 0x0008];
+
+       /* DMA Area */
+       u8  pad_0x3000_0x3004[0x4];                             /* 0x3000 */
+       u32 mfc_lsa_W;                                          /* 0x3004 */
+       u64 mfc_ea_W;                                           /* 0x3008 */
+       union mfc_tag_size_class_cmd mfc_union_W;                       /* 0x3010 */
+       u8  pad_0x3018_0x3104[0xec];                            /* 0x3018 */
+       u32 dma_qstatus_R;                                      /* 0x3104 */
+       u8  pad_0x3108_0x3204[0xfc];                            /* 0x3108 */
+       u32 dma_querytype_RW;                                   /* 0x3204 */
+       u8  pad_0x3208_0x321c[0x14];                            /* 0x3208 */
+       u32 dma_querymask_RW;                                   /* 0x321c */
+       u8  pad_0x3220_0x322c[0xc];                             /* 0x3220 */
+       u32 dma_tagstatus_R;                                    /* 0x322c */
+#define DMA_TAGSTATUS_INTR_ANY 1u
+#define DMA_TAGSTATUS_INTR_ALL 2u
+       u8  pad_0x3230_0x4000[0x4000 - 0x3230];                 /* 0x3230 */
+
+       /* SPU Control Area */
+       u8  pad_0x4000_0x4004[0x4];                             /* 0x4000 */
+       u32 pu_mb_R;                                            /* 0x4004 */
+       u8  pad_0x4008_0x400c[0x4];                             /* 0x4008 */
+       u32 spu_mb_W;                                           /* 0x400c */
+       u8  pad_0x4010_0x4014[0x4];                             /* 0x4010 */
+       u32 mb_stat_R;                                          /* 0x4014 */
+       u8  pad_0x4018_0x401c[0x4];                             /* 0x4018 */
+       u32 spu_runcntl_RW;                                     /* 0x401c */
+#define SPU_RUNCNTL_STOP       0L
+#define SPU_RUNCNTL_RUNNABLE   1L
+       u8  pad_0x4020_0x4024[0x4];                             /* 0x4020 */
+       u32 spu_status_R;                                       /* 0x4024 */
+#define SPU_STOP_STATUS_SHIFT           16
+#define SPU_STATUS_STOPPED             0x0
+#define SPU_STATUS_RUNNING             0x1
+#define SPU_STATUS_STOPPED_BY_STOP     0x2
+#define SPU_STATUS_STOPPED_BY_HALT     0x4
+#define SPU_STATUS_WAITING_FOR_CHANNEL 0x8
+#define SPU_STATUS_SINGLE_STEP         0x10
+#define SPU_STATUS_INVALID_INSTR        0x20
+#define SPU_STATUS_INVALID_CH           0x40
+#define SPU_STATUS_ISOLATED_STATE       0x80
+#define SPU_STATUS_ISOLATED_LOAD_STAUTUS 0x200
+#define SPU_STATUS_ISOLATED_EXIT_STAUTUS 0x400
+       u8  pad_0x4028_0x402c[0x4];                             /* 0x4028 */
+       u32 spu_spe_R;                                          /* 0x402c */
+       u8  pad_0x4030_0x4034[0x4];                             /* 0x4030 */
+       u32 spu_npc_RW;                                         /* 0x4034 */
+       u8  pad_0x4038_0x14000[0x14000 - 0x4038];               /* 0x4038 */
+
+       /* Signal Notification Area */
+       u8  pad_0x14000_0x1400c[0xc];                           /* 0x14000 */
+       u32 signal_notify1;                                     /* 0x1400c */
+       u8  pad_0x14010_0x1c00c[0x7ffc];                        /* 0x14010 */
+       u32 signal_notify2;                                     /* 0x1c00c */
+} __attribute__ ((aligned(0x20000)));
+
+/* SPU Privilege 2 State Area */
+struct spu_priv2 {
+       /* MFC Registers */
+       u8  pad_0x0000_0x1100[0x1100 - 0x0000];                 /* 0x0000 */
+
+       /* SLB Management Registers */
+       u8  pad_0x1100_0x1108[0x8];                             /* 0x1100 */
+       u64 slb_index_W;                                        /* 0x1108 */
+#define SLB_INDEX_MASK                         0x7L
+       u64 slb_esid_RW;                                        /* 0x1110 */
+       u64 slb_vsid_RW;                                        /* 0x1118 */
+#define SLB_VSID_SUPERVISOR_STATE      (0x1ull << 11)
+#define SLB_VSID_SUPERVISOR_STATE_MASK (0x1ull << 11)
+#define SLB_VSID_PROBLEM_STATE         (0x1ull << 10)
+#define SLB_VSID_PROBLEM_STATE_MASK    (0x1ull << 10)
+#define SLB_VSID_EXECUTE_SEGMENT       (0x1ull << 9)
+#define SLB_VSID_NO_EXECUTE_SEGMENT    (0x1ull << 9)
+#define SLB_VSID_EXECUTE_SEGMENT_MASK  (0x1ull << 9)
+#define SLB_VSID_4K_PAGE               (0x0 << 8)
+#define SLB_VSID_LARGE_PAGE            (0x1ull << 8)
+#define SLB_VSID_PAGE_SIZE_MASK                (0x1ull << 8)
+#define SLB_VSID_CLASS_MASK            (0x1ull << 7)
+#define SLB_VSID_VIRTUAL_PAGE_SIZE_MASK        (0x1ull << 6)
+       u64 slb_invalidate_entry_W;                             /* 0x1120 */
+       u64 slb_invalidate_all_W;                               /* 0x1128 */
+       u8  pad_0x1130_0x2000[0x2000 - 0x1130];                 /* 0x1130 */
+
+       /* Context Save / Restore Area */
+       struct mfc_cq_sr spuq[16];                              /* 0x2000 */
+       struct mfc_cq_sr puq[8];                                /* 0x2200 */
+       u8  pad_0x2300_0x3000[0x3000 - 0x2300];                 /* 0x2300 */
+
+       /* MFC Control */
+       u64 mfc_control_RW;                                     /* 0x3000 */
+#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_NORMAL_DMA_QUEUE_OPERATION    (0ull << 8)
+#define MFC_CNTL_SUSPEND_IN_PROGRESS           (1ull << 8)
+#define MFC_CNTL_SUSPEND_COMPLETE              (3ull << 8)
+#define MFC_CNTL_SUSPEND_DMA_STATUS_MASK       (3ull << 8)
+#define MFC_CNTL_DMA_QUEUES_EMPTY              (1ull << 14)
+#define MFC_CNTL_DMA_QUEUES_EMPTY_MASK         (1ull << 14)
+#define MFC_CNTL_PURGE_DMA_REQUEST             (1ull << 15)
+#define MFC_CNTL_PURGE_DMA_IN_PROGRESS         (1ull << 24)
+#define MFC_CNTL_PURGE_DMA_COMPLETE            (3ull << 24)
+#define MFC_CNTL_PURGE_DMA_STATUS_MASK         (3ull << 24)
+#define MFC_CNTL_RESTART_DMA_COMMAND           (1ull << 32)
+#define MFC_CNTL_DMA_COMMAND_REISSUE_PENDING   (1ull << 32)
+#define MFC_CNTL_DMA_COMMAND_REISSUE_STATUS_MASK (1ull << 32)
+#define MFC_CNTL_MFC_PRIVILEGE_STATE           (2ull << 33)
+#define MFC_CNTL_MFC_PROBLEM_STATE             (3ull << 33)
+#define MFC_CNTL_MFC_KEY_PROTECTION_STATE_MASK (3ull << 33)
+#define MFC_CNTL_DECREMENTER_HALTED            (1ull << 35)
+#define MFC_CNTL_DECREMENTER_RUNNING           (1ull << 40)
+#define MFC_CNTL_DECREMENTER_STATUS_MASK       (1ull << 40)
+       u8  pad_0x3008_0x4000[0x4000 - 0x3008];                 /* 0x3008 */
+
+       /* Interrupt Mailbox */
+       u64 puint_mb_R;                                         /* 0x4000 */
+       u8  pad_0x4008_0x4040[0x4040 - 0x4008];                 /* 0x4008 */
+
+       /* SPU Control */
+       u64 spu_privcntl_RW;                                    /* 0x4040 */
+#define SPU_PRIVCNTL_MODE_NORMAL               (0x0ull << 0)
+#define SPU_PRIVCNTL_MODE_SINGLE_STEP          (0x1ull << 0)
+#define SPU_PRIVCNTL_MODE_MASK                 (0x1ull << 0)
+#define SPU_PRIVCNTL_NO_ATTENTION_EVENT                (0x0ull << 1)
+#define SPU_PRIVCNTL_ATTENTION_EVENT           (0x1ull << 1)
+#define SPU_PRIVCNTL_ATTENTION_EVENT_MASK      (0x1ull << 1)
+#define SPU_PRIVCNT_LOAD_REQUEST_NORMAL                (0x0ull << 2)
+#define SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK   (0x1ull << 2)
+       u8  pad_0x4048_0x4058[0x10];                            /* 0x4048 */
+       u64 spu_lslr_RW;                                        /* 0x4058 */
+       u64 spu_chnlcntptr_RW;                                  /* 0x4060 */
+       u64 spu_chnlcnt_RW;                                     /* 0x4068 */
+       u64 spu_chnldata_RW;                                    /* 0x4070 */
+       u64 spu_cfg_RW;                                         /* 0x4078 */
+       u8  pad_0x4080_0x5000[0x5000 - 0x4080];                 /* 0x4080 */
+
+       /* PV2_ImplRegs: Implementation-specific privileged-state 2 regs */
+       u64 spu_pm_trace_tag_status_RW;                         /* 0x5000 */
+       u64 spu_tag_status_query_RW;                            /* 0x5008 */
+#define TAG_STATUS_QUERY_CONDITION_BITS (0x3ull << 32)
+#define TAG_STATUS_QUERY_MASK_BITS (0xffffffffull)
+       u64 spu_cmd_buf1_RW;                                    /* 0x5010 */
+#define SPU_COMMAND_BUFFER_1_LSA_BITS (0x7ffffull << 32)
+#define SPU_COMMAND_BUFFER_1_EAH_BITS (0xffffffffull)
+       u64 spu_cmd_buf2_RW;                                    /* 0x5018 */
+#define SPU_COMMAND_BUFFER_2_EAL_BITS ((0xffffffffull) << 32)
+#define SPU_COMMAND_BUFFER_2_TS_BITS (0xffffull << 16)
+#define SPU_COMMAND_BUFFER_2_TAG_BITS (0x3full)
+       u64 spu_atomic_status_RW;                               /* 0x5020 */
+} __attribute__ ((aligned(0x20000)));
+
+/* SPU Privilege 1 State Area */
+struct spu_priv1 {
+       /* Control and Configuration Area */
+       u64 mfc_sr1_RW;                                         /* 0x000 */
+#define MFC_STATE1_LOCAL_STORAGE_DECODE_MASK   0x01ull
+#define MFC_STATE1_BUS_TLBIE_MASK              0x02ull
+#define MFC_STATE1_REAL_MODE_OFFSET_ENABLE_MASK        0x04ull
+#define MFC_STATE1_PROBLEM_STATE_MASK          0x08ull
+#define MFC_STATE1_RELOCATE_MASK               0x10ull
+#define MFC_STATE1_MASTER_RUN_CONTROL_MASK     0x20ull
+       u64 mfc_lpid_RW;                                        /* 0x008 */
+       u64 spu_idr_RW;                                         /* 0x010 */
+       u64 mfc_vr_RO;                                          /* 0x018 */
+#define MFC_VERSION_BITS               (0xffff << 16)
+#define MFC_REVISION_BITS              (0xffff)
+#define MFC_GET_VERSION_BITS(vr)       (((vr) & MFC_VERSION_BITS) >> 16)
+#define MFC_GET_REVISION_BITS(vr)      ((vr) & MFC_REVISION_BITS)
+       u64 spu_vr_RO;                                          /* 0x020 */
+#define SPU_VERSION_BITS               (0xffff << 16)
+#define SPU_REVISION_BITS              (0xffff)
+#define SPU_GET_VERSION_BITS(vr)       (vr & SPU_VERSION_BITS) >> 16
+#define SPU_GET_REVISION_BITS(vr)      (vr & SPU_REVISION_BITS)
+       u8  pad_0x28_0x100[0x100 - 0x28];                       /* 0x28 */
+
+
+       /* Interrupt Area */
+       u64 int_mask_RW[3];                                     /* 0x100 */
+#define CLASS0_ENABLE_DMA_ALIGNMENT_INTR               0x1L
+#define CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR         0x2L
+#define CLASS0_ENABLE_SPU_ERROR_INTR                   0x4L
+#define CLASS0_ENABLE_MFC_FIR_INTR                     0x8L
+#define CLASS1_ENABLE_SEGMENT_FAULT_INTR               0x1L
+#define CLASS1_ENABLE_STORAGE_FAULT_INTR               0x2L
+#define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_GET_INTR   0x4L
+#define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_PUT_INTR   0x8L
+#define CLASS2_ENABLE_MAILBOX_INTR                     0x1L
+#define CLASS2_ENABLE_SPU_STOP_INTR                    0x2L
+#define CLASS2_ENABLE_SPU_HALT_INTR                    0x4L
+#define CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR  0x8L
+       u8  pad_0x118_0x140[0x28];                              /* 0x118 */
+       u64 int_stat_RW[3];                                     /* 0x140 */
+       u8  pad_0x158_0x180[0x28];                              /* 0x158 */
+       u64 int_route_RW;                                       /* 0x180 */
+
+       /* Interrupt Routing */
+       u8  pad_0x188_0x200[0x200 - 0x188];                     /* 0x188 */
+
+       /* Atomic Unit Control Area */
+       u64 mfc_atomic_flush_RW;                                /* 0x200 */
+#define mfc_atomic_flush_enable                        0x1L
+       u8  pad_0x208_0x280[0x78];                              /* 0x208 */
+       u64 resource_allocation_groupID_RW;                     /* 0x280 */
+       u64 resource_allocation_enable_RW;                      /* 0x288 */
+       u8  pad_0x290_0x3c8[0x3c8 - 0x290];                     /* 0x290 */
+
+       /* SPU_Cache_ImplRegs: Implementation-dependent cache registers */
+
+       u64 smf_sbi_signal_sel;                                 /* 0x3c8 */
+#define smf_sbi_mask_lsb       56
+#define smf_sbi_shift          (63 - smf_sbi_mask_lsb)
+#define smf_sbi_mask           (0x301LL << smf_sbi_shift)
+#define smf_sbi_bus0_bits      (0x001LL << smf_sbi_shift)
+#define smf_sbi_bus2_bits      (0x100LL << smf_sbi_shift)
+#define smf_sbi2_bus0_bits     (0x201LL << smf_sbi_shift)
+#define smf_sbi2_bus2_bits     (0x300LL << smf_sbi_shift)
+       u64 smf_ato_signal_sel;                                 /* 0x3d0 */
+#define smf_ato_mask_lsb       35
+#define smf_ato_shift          (63 - smf_ato_mask_lsb)
+#define smf_ato_mask           (0x3LL << smf_ato_shift)
+#define smf_ato_bus0_bits      (0x2LL << smf_ato_shift)
+#define smf_ato_bus2_bits      (0x1LL << smf_ato_shift)
+       u8  pad_0x3d8_0x400[0x400 - 0x3d8];                     /* 0x3d8 */
+
+       /* TLB Management Registers */
+       u64 mfc_sdr_RW;                                         /* 0x400 */
+       u8  pad_0x408_0x500[0xf8];                              /* 0x408 */
+       u64 tlb_index_hint_RO;                                  /* 0x500 */
+       u64 tlb_index_W;                                        /* 0x508 */
+       u64 tlb_vpn_RW;                                         /* 0x510 */
+       u64 tlb_rpn_RW;                                         /* 0x518 */
+       u8  pad_0x520_0x540[0x20];                              /* 0x520 */
+       u64 tlb_invalidate_entry_W;                             /* 0x540 */
+       u64 tlb_invalidate_all_W;                               /* 0x548 */
+       u8  pad_0x550_0x580[0x580 - 0x550];                     /* 0x550 */
+
+       /* SPU_MMU_ImplRegs: Implementation-dependent MMU registers */
+       u64 smm_hid;                                            /* 0x580 */
+#define PAGE_SIZE_MASK         0xf000000000000000ull
+#define PAGE_SIZE_16MB_64KB    0x2000000000000000ull
+       u8  pad_0x588_0x600[0x600 - 0x588];                     /* 0x588 */
+
+       /* MFC Status/Control Area */
+       u64 mfc_accr_RW;                                        /* 0x600 */
+#define MFC_ACCR_EA_ACCESS_GET         (1 << 0)
+#define MFC_ACCR_EA_ACCESS_PUT         (1 << 1)
+#define MFC_ACCR_LS_ACCESS_GET         (1 << 3)
+#define MFC_ACCR_LS_ACCESS_PUT         (1 << 4)
+       u8  pad_0x608_0x610[0x8];                               /* 0x608 */
+       u64 mfc_dsisr_RW;                                       /* 0x610 */
+#define MFC_DSISR_PTE_NOT_FOUND                (1 << 30)
+#define MFC_DSISR_ACCESS_DENIED                (1 << 27)
+#define MFC_DSISR_ATOMIC               (1 << 26)
+#define MFC_DSISR_ACCESS_PUT           (1 << 25)
+#define MFC_DSISR_ADDR_MATCH           (1 << 22)
+#define MFC_DSISR_LS                   (1 << 17)
+#define MFC_DSISR_L                    (1 << 16)
+#define MFC_DSISR_ADDRESS_OVERFLOW     (1 << 0)
+       u8  pad_0x618_0x620[0x8];                               /* 0x618 */
+       u64 mfc_dar_RW;                                         /* 0x620 */
+       u8  pad_0x628_0x700[0x700 - 0x628];                     /* 0x628 */
+
+       /* Replacement Management Table (RMT) Area */
+       u64 rmt_index_RW;                                       /* 0x700 */
+       u8  pad_0x708_0x710[0x8];                               /* 0x708 */
+       u64 rmt_data1_RW;                                       /* 0x710 */
+       u8  pad_0x718_0x800[0x800 - 0x718];                     /* 0x718 */
+
+       /* Control/Configuration Registers */
+       u64 mfc_dsir_R;                                         /* 0x800 */
+#define MFC_DSIR_Q                     (1 << 31)
+#define MFC_DSIR_SPU_QUEUE             MFC_DSIR_Q
+       u64 mfc_lsacr_RW;                                       /* 0x808 */
+#define MFC_LSACR_COMPARE_MASK         ((~0ull) << 32)
+#define MFC_LSACR_COMPARE_ADDR         ((~0ull) >> 32)
+       u64 mfc_lscrr_R;                                        /* 0x810 */
+#define MFC_LSCRR_Q                    (1 << 31)
+#define MFC_LSCRR_SPU_QUEUE            MFC_LSCRR_Q
+#define MFC_LSCRR_QI_SHIFT             32
+#define MFC_LSCRR_QI_MASK              ((~0ull) << MFC_LSCRR_QI_SHIFT)
+       u8  pad_0x818_0x820[0x8];                               /* 0x818 */
+       u64 mfc_tclass_id_RW;                                   /* 0x820 */
+#define MFC_TCLASS_ID_ENABLE           (1L << 0L)
+#define MFC_TCLASS_SLOT2_ENABLE                (1L << 5L)
+#define MFC_TCLASS_SLOT1_ENABLE                (1L << 6L)
+#define MFC_TCLASS_SLOT0_ENABLE                (1L << 7L)
+#define MFC_TCLASS_QUOTA_2_SHIFT       8L
+#define MFC_TCLASS_QUOTA_1_SHIFT       16L
+#define MFC_TCLASS_QUOTA_0_SHIFT       24L
+#define MFC_TCLASS_QUOTA_2_MASK                (0x1FL << MFC_TCLASS_QUOTA_2_SHIFT)
+#define MFC_TCLASS_QUOTA_1_MASK                (0x1FL << MFC_TCLASS_QUOTA_1_SHIFT)
+#define MFC_TCLASS_QUOTA_0_MASK                (0x1FL << MFC_TCLASS_QUOTA_0_SHIFT)
+       u8  pad_0x828_0x900[0x900 - 0x828];                     /* 0x828 */
+
+       /* Real Mode Support Registers */
+       u64 mfc_rm_boundary;                                    /* 0x900 */
+       u8  pad_0x908_0x938[0x30];                              /* 0x908 */
+       u64 smf_dma_signal_sel;                                 /* 0x938 */
+#define mfc_dma1_mask_lsb      41
+#define mfc_dma1_shift         (63 - mfc_dma1_mask_lsb)
+#define mfc_dma1_mask          (0x3LL << mfc_dma1_shift)
+#define mfc_dma1_bits          (0x1LL << mfc_dma1_shift)
+#define mfc_dma2_mask_lsb      43
+#define mfc_dma2_shift         (63 - mfc_dma2_mask_lsb)
+#define mfc_dma2_mask          (0x3LL << mfc_dma2_shift)
+#define mfc_dma2_bits          (0x1LL << mfc_dma2_shift)
+       u8  pad_0x940_0xa38[0xf8];                              /* 0x940 */
+       u64 smm_signal_sel;                                     /* 0xa38 */
+#define smm_sig_mask_lsb       12
+#define smm_sig_shift          (63 - smm_sig_mask_lsb)
+#define smm_sig_mask           (0x3LL << smm_sig_shift)
+#define smm_sig_bus0_bits      (0x2LL << smm_sig_shift)
+#define smm_sig_bus2_bits      (0x1LL << smm_sig_shift)
+       u8  pad_0xa40_0xc00[0xc00 - 0xa40];                     /* 0xa40 */
+
+       /* DMA Command Error Area */
+       u64 mfc_cer_R;                                          /* 0xc00 */
+#define MFC_CER_Q              (1 << 31)
+#define MFC_CER_SPU_QUEUE      MFC_CER_Q
+       u8  pad_0xc08_0x1000[0x1000 - 0xc08];                   /* 0xc08 */
+
+       /* PV1_ImplRegs: Implementation-dependent privileged-state 1 regs */
+       /* DMA Command Error Area */
+       u64 spu_ecc_cntl_RW;                                    /* 0x1000 */
+#define SPU_ECC_CNTL_E                 (1ull << 0ull)
+#define SPU_ECC_CNTL_ENABLE            SPU_ECC_CNTL_E
+#define SPU_ECC_CNTL_DISABLE           (~SPU_ECC_CNTL_E & 1L)
+#define SPU_ECC_CNTL_S                 (1ull << 1ull)
+#define SPU_ECC_STOP_AFTER_ERROR       SPU_ECC_CNTL_S
+#define SPU_ECC_CONTINUE_AFTER_ERROR   (~SPU_ECC_CNTL_S & 2L)
+#define SPU_ECC_CNTL_B                 (1ull << 2ull)
+#define SPU_ECC_BACKGROUND_ENABLE      SPU_ECC_CNTL_B
+#define SPU_ECC_BACKGROUND_DISABLE     (~SPU_ECC_CNTL_B & 4L)
+#define SPU_ECC_CNTL_I_SHIFT           3ull
+#define SPU_ECC_CNTL_I_MASK            (3ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_WRITE_ALWAYS           (~SPU_ECC_CNTL_I & 12L)
+#define SPU_ECC_WRITE_CORRECTABLE      (1ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_WRITE_UNCORRECTABLE    (3ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_CNTL_D                 (1ull << 5ull)
+#define SPU_ECC_DETECTION_ENABLE       SPU_ECC_CNTL_D
+#define SPU_ECC_DETECTION_DISABLE      (~SPU_ECC_CNTL_D & 32L)
+       u64 spu_ecc_stat_RW;                                    /* 0x1008 */
+#define SPU_ECC_CORRECTED_ERROR                (1ull << 0ul)
+#define SPU_ECC_UNCORRECTED_ERROR      (1ull << 1ul)
+#define SPU_ECC_SCRUB_COMPLETE         (1ull << 2ul)
+#define SPU_ECC_SCRUB_IN_PROGRESS      (1ull << 3ul)
+#define SPU_ECC_INSTRUCTION_ERROR      (1ull << 4ul)
+#define SPU_ECC_DATA_ERROR             (1ull << 5ul)
+#define SPU_ECC_DMA_ERROR              (1ull << 6ul)
+#define SPU_ECC_STATUS_CNT_MASK                (256ull << 8)
+       u64 spu_ecc_addr_RW;                                    /* 0x1010 */
+       u64 spu_err_mask_RW;                                    /* 0x1018 */
+#define SPU_ERR_ILLEGAL_INSTR          (1ull << 0ul)
+#define SPU_ERR_ILLEGAL_CHANNEL                (1ull << 1ul)
+       u8  pad_0x1020_0x1028[0x1028 - 0x1020];                 /* 0x1020 */
+
+       /* SPU Debug-Trace Bus (DTB) Selection Registers */
+       u64 spu_trig0_sel;                                      /* 0x1028 */
+       u64 spu_trig1_sel;                                      /* 0x1030 */
+       u64 spu_trig2_sel;                                      /* 0x1038 */
+       u64 spu_trig3_sel;                                      /* 0x1040 */
+       u64 spu_trace_sel;                                      /* 0x1048 */
+#define spu_trace_sel_mask             0x1f1fLL
+#define spu_trace_sel_bus0_bits                0x1000LL
+#define spu_trace_sel_bus2_bits                0x0010LL
+       u64 spu_event0_sel;                                     /* 0x1050 */
+       u64 spu_event1_sel;                                     /* 0x1058 */
+       u64 spu_event2_sel;                                     /* 0x1060 */
+       u64 spu_event3_sel;                                     /* 0x1068 */
+       u64 spu_trace_cntl;                                     /* 0x1070 */
+} __attribute__ ((aligned(0x2000)));
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
new file mode 100644 (file)
index 0000000..ba18d7d
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * spu_csa.h: Definitions for SPU context save area (CSA).
+ *
+ * (C) Copyright IBM 2005
+ *
+ * Author: Mark Nutter <mnutter@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, 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 _SPU_CSA_H_
+#define _SPU_CSA_H_
+#ifdef __KERNEL__
+
+/*
+ * Total number of 128-bit registers.
+ */
+#define NR_SPU_GPRS            128
+#define NR_SPU_SPRS            9
+#define NR_SPU_REGS_PAD                7
+#define NR_SPU_SPILL_REGS      144     /* GPRS + SPRS + PAD */
+#define SIZEOF_SPU_SPILL_REGS  NR_SPU_SPILL_REGS * 16
+
+#define SPU_SAVE_COMPLETE              0x3FFB
+#define SPU_RESTORE_COMPLETE           0x3FFC
+
+/*
+ * Definitions for various 'stopped' status conditions,
+ * to be recreated during context restore.
+ */
+#define SPU_STOPPED_STATUS_P    1
+#define SPU_STOPPED_STATUS_I    2
+#define SPU_STOPPED_STATUS_H    3
+#define SPU_STOPPED_STATUS_S    4
+#define SPU_STOPPED_STATUS_S_I  5
+#define SPU_STOPPED_STATUS_S_P  6
+#define SPU_STOPPED_STATUS_P_H  7
+#define SPU_STOPPED_STATUS_P_I  8
+#define SPU_STOPPED_STATUS_R    9
+
+#ifndef  __ASSEMBLY__
+/**
+ * spu_reg128 - generic 128-bit register definition.
+ */
+struct spu_reg128 {
+       u32 slot[4];
+};
+
+/**
+ * struct spu_lscsa - Local Store Context Save Area.
+ * @gprs: Array of saved registers.
+ * @fpcr: Saved floating point status control register.
+ * @decr: Saved decrementer value.
+ * @decr_status: Indicates decrementer run status.
+ * @ppu_mb: Saved PPU mailbox data.
+ * @ppuint_mb: Saved PPU interrupting mailbox data.
+ * @tag_mask: Saved tag group mask.
+ * @event_mask: Saved event mask.
+ * @srr0: Saved SRR0.
+ * @stopped_status: Conditions to be recreated by restore.
+ * @ls: Saved contents of Local Storage Area.
+ *
+ * The LSCSA represents state that is primarily saved and
+ * restored by SPU-side code.
+ */
+struct spu_lscsa {
+       struct spu_reg128 gprs[128];
+       struct spu_reg128 fpcr;
+       struct spu_reg128 decr;
+       struct spu_reg128 decr_status;
+       struct spu_reg128 ppu_mb;
+       struct spu_reg128 ppuint_mb;
+       struct spu_reg128 tag_mask;
+       struct spu_reg128 event_mask;
+       struct spu_reg128 srr0;
+       struct spu_reg128 stopped_status;
+       struct spu_reg128 pad[119];     /* 'ls' must be page-aligned. */
+       unsigned char ls[LS_SIZE];
+};
+
+/*
+ * struct spu_problem_collapsed - condensed problem state area, w/o pads.
+ */
+struct spu_problem_collapsed {
+       u64 spc_mssync_RW;
+       u32 mfc_lsa_W;
+       u32 unused_pad0;
+       u64 mfc_ea_W;
+       union mfc_tag_size_class_cmd mfc_union_W;
+       u32 dma_qstatus_R;
+       u32 dma_querytype_RW;
+       u32 dma_querymask_RW;
+       u32 dma_tagstatus_R;
+       u32 pu_mb_R;
+       u32 spu_mb_W;
+       u32 mb_stat_R;
+       u32 spu_runcntl_RW;
+       u32 spu_status_R;
+       u32 spu_spc_R;
+       u32 spu_npc_RW;
+       u32 signal_notify1;
+       u32 signal_notify2;
+       u32 unused_pad1;
+};
+
+/*
+ * struct spu_priv1_collapsed - condensed privileged 1 area, w/o pads.
+ */
+struct spu_priv1_collapsed {
+       u64 mfc_sr1_RW;
+       u64 mfc_lpid_RW;
+       u64 spu_idr_RW;
+       u64 mfc_vr_RO;
+       u64 spu_vr_RO;
+       u64 int_mask_class0_RW;
+       u64 int_mask_class1_RW;
+       u64 int_mask_class2_RW;
+       u64 int_stat_class0_RW;
+       u64 int_stat_class1_RW;
+       u64 int_stat_class2_RW;
+       u64 int_route_RW;
+       u64 mfc_atomic_flush_RW;
+       u64 resource_allocation_groupID_RW;
+       u64 resource_allocation_enable_RW;
+       u64 mfc_fir_R;
+       u64 mfc_fir_status_or_W;
+       u64 mfc_fir_status_and_W;
+       u64 mfc_fir_mask_R;
+       u64 mfc_fir_mask_or_W;
+       u64 mfc_fir_mask_and_W;
+       u64 mfc_fir_chkstp_enable_RW;
+       u64 smf_sbi_signal_sel;
+       u64 smf_ato_signal_sel;
+       u64 mfc_sdr_RW;
+       u64 tlb_index_hint_RO;
+       u64 tlb_index_W;
+       u64 tlb_vpn_RW;
+       u64 tlb_rpn_RW;
+       u64 tlb_invalidate_entry_W;
+       u64 tlb_invalidate_all_W;
+       u64 smm_hid;
+       u64 mfc_accr_RW;
+       u64 mfc_dsisr_RW;
+       u64 mfc_dar_RW;
+       u64 rmt_index_RW;
+       u64 rmt_data1_RW;
+       u64 mfc_dsir_R;
+       u64 mfc_lsacr_RW;
+       u64 mfc_lscrr_R;
+       u64 mfc_tclass_id_RW;
+       u64 mfc_rm_boundary;
+       u64 smf_dma_signal_sel;
+       u64 smm_signal_sel;
+       u64 mfc_cer_R;
+       u64 pu_ecc_cntl_RW;
+       u64 pu_ecc_stat_RW;
+       u64 spu_ecc_addr_RW;
+       u64 spu_err_mask_RW;
+       u64 spu_trig0_sel;
+       u64 spu_trig1_sel;
+       u64 spu_trig2_sel;
+       u64 spu_trig3_sel;
+       u64 spu_trace_sel;
+       u64 spu_event0_sel;
+       u64 spu_event1_sel;
+       u64 spu_event2_sel;
+       u64 spu_event3_sel;
+       u64 spu_trace_cntl;
+};
+
+/*
+ * struct spu_priv2_collapsed - condensed priviliged 2 area, w/o pads.
+ */
+struct spu_priv2_collapsed {
+       u64 slb_index_W;
+       u64 slb_esid_RW;
+       u64 slb_vsid_RW;
+       u64 slb_invalidate_entry_W;
+       u64 slb_invalidate_all_W;
+       struct mfc_cq_sr spuq[16];
+       struct mfc_cq_sr puq[8];
+       u64 mfc_control_RW;
+       u64 puint_mb_R;
+       u64 spu_privcntl_RW;
+       u64 spu_lslr_RW;
+       u64 spu_chnlcntptr_RW;
+       u64 spu_chnlcnt_RW;
+       u64 spu_chnldata_RW;
+       u64 spu_cfg_RW;
+       u64 spu_tag_status_query_RW;
+       u64 spu_cmd_buf1_RW;
+       u64 spu_cmd_buf2_RW;
+       u64 spu_atomic_status_RW;
+};
+
+/**
+ * struct spu_state
+ * @lscsa: Local Store Context Save Area.
+ * @prob: Collapsed Problem State Area, w/o pads.
+ * @priv1: Collapsed Privileged 1 Area, w/o pads.
+ * @priv2: Collapsed Privileged 2 Area, w/o pads.
+ * @spu_chnlcnt_RW: Array of saved channel counts.
+ * @spu_chnldata_RW: Array of saved channel data.
+ * @suspend_time: Time stamp when decrementer disabled.
+ * @slb_esid_RW: Array of saved SLB esid entries.
+ * @slb_vsid_RW: Array of saved SLB vsid entries.
+ *
+ * Structure representing the whole of the SPU
+ * context save area (CSA).  This struct contains
+ * all of the state necessary to suspend and then
+ * later optionally resume execution of an SPU
+ * context.
+ *
+ * The @lscsa region is by far the largest, and is
+ * allocated separately so that it may either be
+ * pinned or mapped to/from application memory, as
+ * appropriate for the OS environment.
+ */
+struct spu_state {
+       struct spu_lscsa *lscsa;
+       struct spu_problem_collapsed prob;
+       struct spu_priv1_collapsed priv1;
+       struct spu_priv2_collapsed priv2;
+       u64 spu_chnlcnt_RW[32];
+       u64 spu_chnldata_RW[32];
+       u32 spu_mailbox_data[4];
+       u32 pu_mailbox_data[1];
+       unsigned long suspend_time;
+       u64 slb_esid_RW[8];
+       u64 slb_vsid_RW[8];
+       spinlock_t register_lock;
+};
+
+extern void spu_init_csa(struct spu_state *csa);
+extern void spu_fini_csa(struct spu_state *csa);
+extern int spu_save(struct spu_state *prev, struct spu *spu);
+extern int spu_restore(struct spu_state *new, struct spu *spu);
+extern int spu_switch(struct spu_state *prev, struct spu_state *new,
+                     struct spu *spu);
+
+#endif /* __KERNEL__ */
+#endif /* !__ASSEMBLY__ */
+#endif /* _SPU_CSA_H_ */
index 4660c0394a7768c754e5f99c930a26a95595e7c6..794870ab8fd3edfb802fa22cb2d513c94794de8b 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _ASM_POWERPC_SYNCH_H 
 #define _ASM_POWERPC_SYNCH_H 
-
-#include <linux/config.h>
+#ifdef __KERNEL__
 
 #ifdef __powerpc64__
 #define __SUBARCH_HAS_LWSYNC
@@ -47,5 +46,6 @@ static inline void isync(void)
 #define isync_on_smp() __asm__ __volatile__("": : :"memory")
 #endif
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SYNCH_H */
 
index 5341b75c75cb6937ac3372e059346fa2dc606727..0c58e32a9570525ec4a2f036413d4cabfa69c10d 100644 (file)
@@ -4,7 +4,6 @@
 #ifndef _ASM_POWERPC_SYSTEM_H
 #define _ASM_POWERPC_SYSTEM_H
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 
 #include <asm/hw_irq.h>
@@ -42,6 +41,7 @@
 #define set_mb(var, value)     do { var = value; mb(); } while (0)
 #define set_wmb(var, value)    do { var = value; wmb(); } while (0)
 
+#ifdef __KERNEL__
 #ifdef CONFIG_SMP
 #define smp_mb()       mb()
 #define smp_rmb()      rmb()
@@ -54,7 +54,6 @@
 #define smp_read_barrier_depends()     do { } while(0)
 #endif /* CONFIG_SMP */
 
-#ifdef __KERNEL__
 struct task_struct;
 struct pt_regs;
 
index 980a094fd5a7201c488b26d577efa49f31e33dac..6fa200ad7a7f29813ae15d484b2dacaa1f7aa3ce 100644 (file)
@@ -20,6 +20,7 @@
 
 #ifndef _ASM_POWERPC_TCE_H
 #define _ASM_POWERPC_TCE_H
+#ifdef __KERNEL__
 
 /*
  * Tces come in two formats, one for the virtual bus and a different
@@ -61,4 +62,5 @@ union tce_entry {
 };
 
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_TCE_H */
index e525f49bd1790609e291dfb2d80fd91de66ed61d..ac1e80e6033ee13c22b4a8cc4ce1aa806e173582 100644 (file)
@@ -37,8 +37,7 @@ struct thread_info {
        int             preempt_count;          /* 0 => preemptable,
                                                   <0 => BUG */
        struct restart_block restart_block;
-       /* set by force_successful_syscall_return */
-       unsigned char   syscall_noerror;
+       void *nvgprs_frame;
        /* low level flags - has atomic operations done on it */
        unsigned long   flags ____cacheline_aligned_in_smp;
 };
@@ -123,6 +122,9 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SINGLESTEP         9       /* singlestepping active */
 #define TIF_MEMDIE             10
 #define TIF_SECCOMP            11      /* secure computing */
+#define TIF_RESTOREALL         12      /* Restore all regs (implies NOERROR) */
+#define TIF_SAVE_NVGPRS                13      /* Save r14-r31 in signal frame */
+#define TIF_NOERROR            14      /* Force successful syscall return */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
@@ -136,10 +138,14 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
+#define _TIF_RESTOREALL                (1<<TIF_RESTOREALL)
+#define _TIF_SAVE_NVGPRS       (1<<TIF_SAVE_NVGPRS)
+#define _TIF_NOERROR           (1<<TIF_NOERROR)
 #define _TIF_SYSCALL_T_OR_A    (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
 
 #define _TIF_USER_WORK_MASK    (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
-                                _TIF_NEED_RESCHED)
+                                _TIF_NEED_RESCHED | _TIF_RESTOREALL)
+#define _TIF_PERSYSCALL_MASK   (_TIF_RESTOREALL|_TIF_NOERROR|_TIF_SAVE_NVGPRS)
 
 #endif /* __KERNEL__ */
 
index 56659f12177981a7b71392e61039fb07a10bc0fc..601a53cf96d5b177d9077864ad8815eb207f71c7 100644 (file)
@@ -11,6 +11,7 @@
  */
 #ifndef _ASM_POWERPC_TLB_H
 #define _ASM_POWERPC_TLB_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #ifndef __powerpc64__
@@ -67,4 +68,5 @@ static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
 }
 
 #endif
+#endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_TLB_H */
index db8095cbe09bb0d59ba8432974ecfbef426ad9c9..9f3d4da261c478876f27352ce1d925de35427323 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ASM_POWERPC_TOPOLOGY_H
 #define _ASM_POWERPC_TOPOLOGY_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 
@@ -55,10 +56,15 @@ static inline int node_to_first_cpu(int node)
        .nr_balance_failed      = 0,                    \
 }
 
+extern void __init dump_numa_cpu_topology(void);
+
 #else
 
+static inline void dump_numa_cpu_topology(void) {}
+
 #include <asm-generic/topology.h>
 
 #endif /* CONFIG_NUMA */
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_TOPOLOGY_H */
index a383383bc4d43006f76dcad304ef0346c336a4fd..479f2d8ff74a9d2bcf52b999c4fa9594935c5e85 100644 (file)
@@ -9,12 +9,13 @@
 
 #ifndef _ASM_POWERPC_UDBG_H
 #define _ASM_POWERPC_UDBG_H
+#ifdef __KERNEL__
 
 #include <linux/compiler.h>
 #include <linux/init.h>
 
-extern void (*udbg_putc)(unsigned char c);
-extern unsigned char (*udbg_getc)(void);
+extern void (*udbg_putc)(char c);
+extern int (*udbg_getc)(void);
 extern int (*udbg_getc_poll)(void);
 
 extern void udbg_puts(const char *s);
@@ -23,9 +24,17 @@ extern int udbg_read(char *buf, int buflen);
 
 extern void register_early_udbg_console(void);
 extern void udbg_printf(const char *fmt, ...);
+extern void udbg_progress(char *s, unsigned short hex);
 
-extern void udbg_init_uart(void __iomem *comport, unsigned int speed);
+extern void udbg_init_uart(void __iomem *comport, unsigned int speed,
+                          unsigned int clock);
+extern unsigned int udbg_probe_uart_speed(void __iomem *comport,
+                                         unsigned int clock);
 
 struct device_node;
-extern void udbg_init_scc(struct device_node *np);
+extern void udbg_scc_init(int force_scc);
+extern int udbg_adb_init(int force_btext);
+extern void udbg_adb_init_early(void);
+
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_UDBG_H */
index 0991dfceef1df98979a45e5431107190752227a7..19eaac3fbbf9ecc6bad44f00def47608f0f13c94 100644 (file)
 #define __NR_inotify_init      275
 #define __NR_inotify_add_watch 276
 #define __NR_inotify_rm_watch  277
+#define __NR_spu_run           278
+#define __NR_spu_create                279
 
-#define __NR_syscalls          278
+#define __NR_syscalls          280
 
 #ifdef __KERNEL__
 #define __NR__exit __NR_exit
index 411832d5bbdb3ba7ab0db3b244b8b0f4eaae2f55..7aa92086c3fbfb338f9d4d20bd02f53a35b4edb4 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _VDSO_DATAPAGE_H
 #define _VDSO_DATAPAGE_H
+#ifdef __KERNEL__
 
 /*
  * Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM
@@ -105,4 +106,5 @@ extern struct vdso_data *vdso_data;
 
 #endif /* __ASSEMBLY__ */
 
+#endif /* __KERNEL__ */
 #endif /* _SYSTEMCFG_H */
index e0ccf108277cd62e81e3d5e957428778a8841451..0544ece51761f9236ff3b24cfaa46c0e653d23e9 100644 (file)
@@ -13,6 +13,7 @@
 
 #ifndef _ASM_POWERPC_VIO_H
 #define _ASM_POWERPC_VIO_H
+#ifdef __KERNEL__
 
 #include <linux/config.h>
 #include <linux/init.h>
@@ -103,4 +104,5 @@ static inline struct vio_dev *to_vio_dev(struct device *dev)
        return container_of(dev, struct vio_dev, dev);
 }
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_VIO_H */
diff --git a/include/asm-ppc/bseip.h b/include/asm-ppc/bseip.h
deleted file mode 100644 (file)
index 691f4a5..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * A collection of structures, addresses, and values associated with
- * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_BSEIP_DEFS
-#define __MACH_BSEIP_DEFS
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-       unsigned int    bi_memstart;    /* Memory start address */
-       unsigned int    bi_memsize;     /* Memory (end) size in bytes */
-       unsigned int    bi_intfreq;     /* Internal Freq, in Hz */
-       unsigned int    bi_busfreq;     /* Bus Freq, in Hz */
-       unsigned char   bi_enetaddr[6];
-       unsigned int    bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * All we need to get started is the IMMR.
- */
-#define IMAP_ADDR              ((uint)0xff000000)
-#define IMAP_SIZE              ((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR                ((uint)0x04000000)
-#define PCMCIA_MEM_SIZE                ((uint)(64 * 1024))
-#endif /* !__ASSEMBLY__ */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS   0
-
-#endif
index ccaefabe0bf5a5442eebbc41758a06a6935ea3ac..ed3630251b3b58a3230f31ec005c69db2d135015 100644 (file)
@@ -17,7 +17,7 @@ extern unsigned long disp_BAT[2];
 extern boot_infos_t disp_bi;
 extern int boot_text_mapped;
 
-extern void init_boot_display(void);
+extern void btext_init(boot_infos_t *bi);
 extern void btext_welcome(void);
 extern void btext_prepare_BAT(void);
 extern void btext_setup_display(int width, int height, int depth, int pitch,
index f01255bd1dc3739e8c71c5e4c88198ca6884d13a..39200def8d116fc0c8e1043a242007e80b65182a 100644 (file)
@@ -35,8 +35,10 @@ struct machdep_calls {
        int             (*get_irq)(struct pt_regs *);
        
        /* A general init function, called by ppc_init in init/main.c.
-          May be NULL. */
+          May be NULL. DEPRECATED ! */
        void            (*init)(void);
+       /* For compatibility with merged platforms */
+       void            (*init_early)(void);
 
        void            (*restart)(char *cmd);
        void            (*power_off)(void);
index 9d14baea3d71000e0cebab13ed01fed743159b3e..c8a96aa44fb7c974b4186da61dd89a11acd12afd 100644 (file)
 #ifdef CONFIG_STX_GP3
 #include <platforms/85xx/stx_gp3.h>
 #endif
+#if defined(CONFIG_TQM8540) || defined(CONFIG_TQM8541) || \
+       defined(CONFIG_TQM8555) || defined(CONFIG_TQM8560)
+#include <platforms/85xx/tqm85xx.h>
+#endif
 
 #define _IO_BASE        isa_io_base
 #define _ISA_MEM_BASE   isa_mem_base
index e58c78f90a5a20849b8927a58c2187b519f50616..9d5230689b31dbf3d2e4b549301c82c9cca21dd2 100644 (file)
@@ -137,5 +137,14 @@ static inline unsigned char bridge_swizzle(unsigned char pin,
  */
 extern int pciauto_bus_scan(struct pci_controller *, int);
 
+#ifdef CONFIG_PCI
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#else
+static inline unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       return (unsigned long)-1;
+}
+#endif
+
 #endif
 #endif /* __KERNEL__ */
index 3e39827ed56690bace2991437a6082fdddd88f34..eb317a0806e4b713112ced1db1a5592411798ca1 100644 (file)
@@ -136,5 +136,37 @@ extern unsigned long sub_reloc_offset(unsigned long);
 #define PTRRELOC(x)    ((typeof(x))add_reloc_offset((unsigned long)(x)))
 #define PTRUNRELOC(x)  ((typeof(x))sub_reloc_offset((unsigned long)(x)))
 
+
+/*
+ * OF address retreival & translation
+ */
+
+
+/* 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, u32 *addr);
+
+/* Extract an address from a device, returns the region size and
+ * the address space flags too. The PCI version uses a BAR number
+ * instead of an absolute index
+ */
+extern u32 *of_get_address(struct device_node *dev, int index,
+                          u64 *size, unsigned int *flags);
+extern u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+                              u64 *size, unsigned int *flags);
+
+/* Get an address as a resource. Note that if your address is
+ * a PIO address, the conversion will fail if the physical address
+ * can't be internally converted to an IO token with
+ * pci_address_to_pio(), that is because it's either called to early
+ * or it can't be matched to any host bridge IO space
+ */
+extern int of_address_to_resource(struct device_node *dev, int index,
+                                 struct resource *r);
+extern int of_pci_address_to_resource(struct device_node *dev, int bar,
+                                     struct resource *r);
+
+
 #endif /* _PPC_PROM_H */
 #endif /* __KERNEL__ */
index 29845378b206d428b55a92f01c4d2afc69cc4a56..e20cdd9074db398cc5d7440600fa22e3d8cb66ee 100644 (file)
@@ -13,7 +13,6 @@
 
 #define L1_CACHE_BYTES     256
 #define L1_CACHE_SHIFT     8
-#define L1_CACHE_SHIFT_MAX 8   /* largest L1 which this arch supports */
 
 #define ARCH_KMALLOC_MINALIGN  8
 
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 9b4dd6d8212ea0fcc48f32836c4a2f654140927d..656fdfe9e8b445ee16e6f833e62f7e10bc783a20 100644 (file)
@@ -22,8 +22,6 @@
 
 #define L1_CACHE_ALIGN(x)      (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 
-#define L1_CACHE_SHIFT_MAX     5       /* largest L1 which this arch supports */
-
 struct cache_info {
        unsigned int ways;
        unsigned int sets;
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index f54e85e8a47028a2e401b75ecad50e85e69d420a..a4f36f0036e1fd7f1f9e689a9faa38a690a5ea61 100644 (file)
@@ -20,8 +20,6 @@
 #define L1_CACHE_ALIGN_MASK    (~(L1_CACHE_BYTES - 1))
 #define L1_CACHE_ALIGN(x)      (((x)+(L1_CACHE_BYTES - 1)) & L1_CACHE_ALIGN_MASK)
 #define L1_CACHE_SIZE_BYTES    (L1_CACHE_BYTES << 10)
-/* Largest L1 which this arch supports */
-#define L1_CACHE_SHIFT_MAX     5
 
 #ifdef MODULE
 #define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index a10522cb21b7d311b698f48b7a751b216a10dad6..cb971e88aea4f7b3a355a1b2505df188d432fec2 100644 (file)
@@ -13,7 +13,6 @@
 #define L1_CACHE_SHIFT 5
 #define L1_CACHE_BYTES 32
 #define L1_CACHE_ALIGN(x) ((((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)))
-#define L1_CACHE_SHIFT_MAX 5   /* largest L1 which this arch supports */
 
 #define SMP_CACHE_BYTES 32
 
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index ade5ec3bfd5a23ca18e08acc4185ed3d908589b1..f7d35a2ae9b8a41401b73f70b74080080ddfcba4 100644 (file)
@@ -9,7 +9,6 @@
 #define        L1_CACHE_BYTES  32 /* Two 16-byte sub-blocks per line. */
 
 #define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
-#define                L1_CACHE_SHIFT_MAX 5    /* largest L1 which this arch supports */
 
 #define        SMP_CACHE_BYTES_SHIFT   6
 #define        SMP_CACHE_BYTES         (1 << SMP_CACHE_BYTES_SHIFT) /* L2 cache line size. */
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index b5417529f6f173dac37d17e900411d9c68ea7929..309f1466b6fa1125edd34f933aa56ab645dc76b0 100644 (file)
@@ -193,11 +193,7 @@ do {                                               \
         * not preserve it's value.  Hairy, but it lets us remove 2 loads
         * and 2 stores in this critical code path.  -DaveM
         */
-#if __GNUC__ >= 3
 #define EXTRA_CLOBBER ,"%l1"
-#else
-#define EXTRA_CLOBBER
-#endif
 #define switch_to(prev, next, last)                                    \
 do {   if (test_thread_flag(TIF_PERFCTR)) {                            \
                unsigned long __tmp;                                    \
index a10602a5b2d6395ef697dbe7381278d4997ecf8f..3d0587075521ee3fb3108dfdcf3c219cb5467125 100644 (file)
@@ -13,9 +13,6 @@
 # define L1_CACHE_SHIFT                5
 #endif
 
-/* XXX: this is valid for x86 and x86_64. */
-#define L1_CACHE_SHIFT_MAX     7       /* largest L1 which this arch supports */
-
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
 #endif
index 142ee2d8e0fdd176f89991825479f44885411538..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,12 +1,6 @@
-#ifndef __UM_FUTEX_H
-#define __UM_FUTEX_H
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-
-#include "asm/arch/futex.h"
+#include <asm-generic/futex.h>
 
 #endif
index 661c0e54702bee0a74eeec958e02ba9ed8337066..b5fc449dc86b3ff4a845c08b129c0eb29574a5e1 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef __UM_RWSEM_H__
 #define __UM_RWSEM_H__
 
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
-#define __builtin_expect(exp,c) (exp)
-#endif
-
 #include "asm/arch/rwsem.h"
 
 #endif
index cbf9096e8517bb3a9698c1284e177210cbee5654..8832c7ea3242b08bf99993fe67f47a06fe8d9b70 100644 (file)
@@ -23,6 +23,4 @@
 #define L1_CACHE_SHIFT         4
 #endif
 
-#define L1_CACHE_SHIFT_MAX     L1_CACHE_SHIFT
-
 #endif /* __V850_CACHE_H__ */
index 9feff4ce1424bc390608326240be369eb13aa648..6a332a9f099c2eafbf78ee5f79056a349d41a775 100644 (file)
@@ -1,53 +1,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifdef __KERNEL__
+#include <asm-generic/futex.h>
 
-#include <linux/futex.h>
-#include <asm/errno.h>
-#include <asm/uaccess.h>
-
-static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
-{
-       int op = (encoded_op >> 28) & 7;
-       int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
-       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-               oparg = 1 << oparg;
-
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
-               return -EFAULT;
-
-       inc_preempt_count();
-
-       switch (op) {
-       case FUTEX_OP_SET:
-       case FUTEX_OP_ADD:
-       case FUTEX_OP_OR:
-       case FUTEX_OP_ANDN:
-       case FUTEX_OP_XOR:
-       default:
-               ret = -ENOSYS;
-       }
-
-       dec_preempt_count();
-
-       if (!ret) {
-               switch (cmp) {
-               case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-               case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-               default: ret = -ENOSYS;
-               }
-       }
-       return ret;
-}
-
-#endif
 #endif
index 5a86f8e976ec35b26182abe9c06b366b37949b37..82460a7bb233fbc6f4354fafb903197ae7c0ca16 100644 (file)
 /* User programs sometimes end up including this header file
    (indirectly, via uClibc header files), so I'm a bit nervous just
    including <linux/compiler.h>.  */
-#if !defined(__builtin_expect) && __GNUC__ == 2 && __GNUC_MINOR__ < 96
-#define __builtin_expect(x, expected_value) (x)
-#endif
 
 #define __syscall_return(type, res)                                          \
   do {                                                                       \
@@ -346,20 +343,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e)                          \
   __syscall_return (type, __ret);                                            \
 }
 
-#if __GNUC__ < 3
-/* In older versions of gcc, `asm' statements with more than 10
-   input/output arguments produce a fatal error.  To work around this
-   problem, we use two versions, one for gcc-3.x and one for earlier
-   versions of gcc (the `earlier gcc' version doesn't work with gcc-3.x
-   because gcc-3.x doesn't allow clobbers to also be input arguments).  */
-#define __SYSCALL6_TRAP(syscall, ret, a, b, c, d, e, f)                              \
-  __asm__ __volatile__ ("trap " SYSCALL_LONG_TRAP                            \
-                       : "=r" (ret), "=r" (syscall)                          \
-                       : "1" (syscall),                                      \
-                       "r" (a), "r" (b), "r" (c), "r" (d),                   \
-                       "r" (e), "r" (f)                                      \
-                       : SYSCALL_CLOBBERS, SYSCALL_ARG4, SYSCALL_ARG5);
-#else /* __GNUC__ >= 3 */
 #define __SYSCALL6_TRAP(syscall, ret, a, b, c, d, e, f)                              \
   __asm__ __volatile__ ("trap " SYSCALL_LONG_TRAP                            \
                        : "=r" (ret), "=r" (syscall),                         \
@@ -368,7 +351,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e)                           \
                        "r" (a), "r" (b), "r" (c), "r" (d),                   \
                        "2" (e), "3" (f)                                      \
                        : SYSCALL_CLOBBERS);
-#endif
 
 #define _syscall6(type, name, atype, a, btype, b, ctype, c, dtype, d, etype, e, ftype, f) \
 type name (atype a, btype b, ctype c, dtype d, etype e, ftype f)             \
index 33e53424128b33a4096162bfe29848b2885a8b16..b4a2401de77b5824239f1ec8b38d9b578d839e68 100644 (file)
@@ -9,6 +9,5 @@
 /* L1 cache line size */
 #define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT)
 #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
-#define L1_CACHE_SHIFT_MAX 7   /* largest L1 which this arch supports */
 
 #endif
index d5166ec3868dd143dbe211fc35aa29402be7b831..e8843362a6ccda6011d5ca607ebde4193eab540d 100644 (file)
 #define __NR_ia32_inotify_init         291
 #define __NR_ia32_inotify_add_watch    292
 #define __NR_ia32_inotify_rm_watch     293
+#define __NR_ia32_migrate_pages                294
 
-#define IA32_NR_syscalls 294   /* must be > than biggest syscall! */
+#define IA32_NR_syscalls 295   /* must be > than biggest syscall! */
 
 #endif /* _ASM_X86_64_IA32_UNISTD_H_ */
index 2c42150bce0c372e651f6736ae14f3cf70829ccb..e6f896161c1193d60043db9ff6ffebb372e63385 100644 (file)
@@ -571,8 +571,10 @@ __SYSCALL(__NR_inotify_init, sys_inotify_init)
 __SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch)
 #define __NR_inotify_rm_watch  255
 __SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch)
+#define __NR_migrate_pages     256
+__SYSCALL(__NR_migrate_pages, sys_migrate_pages)
 
-#define __NR_syscall_max __NR_inotify_rm_watch
+#define __NR_syscall_max __NR_migrate_pages
 #ifndef __NO_STUBS
 
 /* user-visible error numbers are in the range -1 - -4095 */
index 49fd37629ee475a64a7f82a84e74e5e1e204f9cc..00c8efa95cc3ade224b9e7b61033c414f3dfb464 100644 (file)
@@ -94,26 +94,27 @@ struct kiocb {
        ssize_t                 (*ki_retry)(struct kiocb *);
        void                    (*ki_dtor)(struct kiocb *);
 
-       struct list_head        ki_list;        /* the aio core uses this
-                                                * for cancellation */
-
        union {
                void __user             *user;
                struct task_struct      *tsk;
        } ki_obj;
+
        __u64                   ki_user_data;   /* user's data for completion */
+       wait_queue_t            ki_wait;
        loff_t                  ki_pos;
+
+       void                    *private;
        /* State that we remember to be able to restart/retry  */
        unsigned short          ki_opcode;
        size_t                  ki_nbytes;      /* copy of iocb->aio_nbytes */
        char                    __user *ki_buf; /* remaining iocb->aio_buf */
        size_t                  ki_left;        /* remaining bytes */
-       wait_queue_t            ki_wait;
        long                    ki_retried;     /* just for testing */
        long                    ki_kicked;      /* just for testing */
        long                    ki_queued;      /* just for testing */
 
-       void                    *private;
+       struct list_head        ki_list;        /* the aio core uses this
+                                                * for cancellation */
 };
 
 #define is_sync_kiocb(iocb)    ((iocb)->ki_key == KIOCB_SYNC_KEY)
@@ -126,6 +127,7 @@ struct kiocb {
                (x)->ki_filp = (filp);                  \
                (x)->ki_ctx = NULL;                     \
                (x)->ki_cancel = NULL;                  \
+               (x)->ki_retry = NULL;                   \
                (x)->ki_dtor = NULL;                    \
                (x)->ki_obj.tsk = tsk;                  \
                (x)->ki_user_data = 0;                  \
index 911c09cb9bf922ea48583dfd7dbac8ee330cfc88..6ba3aa8a81f4953b84cb1ef0edf093ed1b7af8ad 100644 (file)
@@ -155,15 +155,15 @@ struct elapaarp {
 #define AARP_REQUEST                   1
 #define AARP_REPLY                     2
 #define AARP_PROBE                     3
-       __u8    hw_src[ETH_ALEN]        __attribute__ ((packed));
-       __u8    pa_src_zero             __attribute__ ((packed));
-       __be16  pa_src_net              __attribute__ ((packed));
-       __u8    pa_src_node             __attribute__ ((packed));
-       __u8    hw_dst[ETH_ALEN]        __attribute__ ((packed));
-       __u8    pa_dst_zero             __attribute__ ((packed));
-       __be16  pa_dst_net              __attribute__ ((packed));
-       __u8    pa_dst_node             __attribute__ ((packed));       
-};
+       __u8    hw_src[ETH_ALEN];
+       __u8    pa_src_zero;
+       __be16  pa_src_net;
+       __u8    pa_src_node;
+       __u8    hw_dst[ETH_ALEN];
+       __u8    pa_dst_zero;
+       __be16  pa_dst_net;
+       __u8    pa_dst_node;
+} __attribute__ ((packed));
 
 static __inline__ struct elapaarp *aarp_hdr(struct sk_buff *skb)
 {
index fb098537742116a71067fa6af70abac17dc055e8..02a585faa62cfd689510b943717cc6f79101184b 100644 (file)
@@ -118,9 +118,9 @@ struct request_list {
  * try to put the fields that are referenced together in the same cacheline
  */
 struct request {
-       struct list_head queuelist; /* looking for ->queue? you must _not_
-                                    * access it directly, use
-                                    * blkdev_dequeue_request! */
+       struct list_head queuelist;
+       struct list_head donelist;
+
        unsigned long flags;            /* see REQ_ bits below */
 
        /* Maintain bio traversal state for part by part I/O submission.
@@ -141,6 +141,7 @@ struct request {
        struct bio *biotail;
 
        void *elevator_private;
+       void *completion_data;
 
        unsigned short ioprio;
 
@@ -291,6 +292,7 @@ typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
 typedef void (activity_fn) (void *data, int rw);
 typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *);
 typedef void (prepare_flush_fn) (request_queue_t *, struct request *);
+typedef void (softirq_done_fn)(struct request *);
 
 enum blk_queue_state {
        Queue_down,
@@ -332,6 +334,7 @@ struct request_queue
        activity_fn             *activity_fn;
        issue_flush_fn          *issue_flush_fn;
        prepare_flush_fn        *prepare_flush_fn;
+       softirq_done_fn         *softirq_done_fn;
 
        /*
         * Dispatch queue sorting
@@ -592,7 +595,6 @@ extern void generic_make_request(struct bio *bio);
 extern void blk_put_request(struct request *);
 extern void __blk_put_request(request_queue_t *, struct request *);
 extern void blk_end_sync_rq(struct request *rq, int error);
-extern void blk_attempt_remerge(request_queue_t *, struct request *);
 extern struct request *blk_get_request(request_queue_t *, int, gfp_t);
 extern void blk_insert_request(request_queue_t *, struct request *, int, void *);
 extern void blk_requeue_request(request_queue_t *, struct request *);
@@ -646,6 +648,17 @@ extern int end_that_request_first(struct request *, int, int);
 extern int end_that_request_chunk(struct request *, int, int);
 extern void end_that_request_last(struct request *, int);
 extern void end_request(struct request *req, int uptodate);
+extern void blk_complete_request(struct request *);
+
+static inline int rq_all_done(struct request *rq, unsigned int nr_bytes)
+{
+       if (blk_fs_request(rq))
+               return (nr_bytes >= (rq->hard_nr_sectors << 9));
+       else if (blk_pc_request(rq))
+               return nr_bytes >= rq->data_len;
+
+       return 0;
+}
 
 /*
  * end_that_request_first/chunk() takes an uptodate argument. we account
@@ -694,6 +707,7 @@ extern void blk_queue_segment_boundary(request_queue_t *, unsigned long);
 extern void blk_queue_prep_rq(request_queue_t *, prep_rq_fn *pfn);
 extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(request_queue_t *, int);
+extern void blk_queue_softirq_done(request_queue_t *, softirq_done_fn *);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(request_queue_t *, unsigned, prepare_flush_fn *);
 extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *);
index 1db061bb6b08d6278e6eaea43a2493e58bb8165e..9f159baf153fbcc12a4c7889d92597e35d205391 100644 (file)
@@ -197,7 +197,8 @@ int block_read_full_page(struct page*, get_block_t*);
 int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
 int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
                                loff_t *);
-int generic_cont_expand(struct inode *inode, loff_t size) ;
+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_sync_page(struct page *);
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
index 04bd756efc6740e2b16385d4047f2ebb7ec1a86b..e86e4a938373e15a3a8edcbb07802a5c9274bb02 100644 (file)
@@ -156,7 +156,7 @@ extern __be32                       htonl(__u32);
 extern __u16                   ntohs(__be16);
 extern __be16                  htons(__u16);
 
-#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__)
+#if defined(__GNUC__) && defined(__OPTIMIZE__)
 
 #define ___htonl(x) __cpu_to_be32(x)
 #define ___htons(x) __cpu_to_be16(x)
index 2f1cb775125abe39eef09908078a287bb763ec29..25f7f32883ec8667c4c464c2ff43f36a73aad27c 100644 (file)
 /*
  * Allow constant folding
  */
-#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__)
+#if defined(__GNUC__) && defined(__OPTIMIZE__)
 #  define __swab16(x) \
 (__builtin_constant_p((__u16)(x)) ? \
  ___swab16((x)) : \
index d5f2a320510930ce7d673ed11ed2f30c96d5994f..ae5e5f914bf4a082b1f12e3956f4e868011710db 100644 (file)
@@ -77,7 +77,7 @@
 /*
  * Allow constant folding
  */
-#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__)
+#if defined(__GNUC__) && defined(__OPTIMIZE__)
 #  define __swahw32(x) \
 (__builtin_constant_p((__u32)(x)) ? \
  ___swahw32((x)) : \
index 0b7ecf3af78a70a854cefbac1d7e814a5000baf5..ffe52210fc4f6d31141d48fed83e790c1c3c7875 100644 (file)
 #endif /* CONFIG_SMP */
 #endif
 
-#if !defined(____cacheline_maxaligned_in_smp)
+/*
+ * The maximum alignment needed for some critical structures
+ * These could be inter-node cacheline sizes/L3 cacheline
+ * size etc.  Define this in asm/cache.h for your arch
+ */
+#ifndef INTERNODE_CACHE_SHIFT
+#define INTERNODE_CACHE_SHIFT L1_CACHE_SHIFT
+#endif
+
+#if !defined(____cacheline_internodealigned_in_smp)
 #if defined(CONFIG_SMP)
-#define ____cacheline_maxaligned_in_smp \
-       __attribute__((__aligned__(1 << (L1_CACHE_SHIFT_MAX))))
+#define ____cacheline_internodealigned_in_smp \
+       __attribute__((__aligned__(1 << (INTERNODE_CACHE_SHIFT))))
 #else
-#define ____cacheline_maxaligned_in_smp
+#define ____cacheline_internodealigned_in_smp
 #endif
 #endif
 
index 119f9d064cc6100a1671af7e127bdab31e9cce64..339878952f12f7fe4e3b81ff86691a6923344a34 100644 (file)
@@ -218,32 +218,6 @@ COMPATIBLE_IOCTL(VT_RESIZE)
 COMPATIBLE_IOCTL(VT_RESIZEX)
 COMPATIBLE_IOCTL(VT_LOCKSWITCH)
 COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-/* Little v */
-/* Little v, the video4linux ioctls (conflict?) */
-COMPATIBLE_IOCTL(VIDIOCGCAP)
-COMPATIBLE_IOCTL(VIDIOCGCHAN)
-COMPATIBLE_IOCTL(VIDIOCSCHAN)
-COMPATIBLE_IOCTL(VIDIOCGPICT)
-COMPATIBLE_IOCTL(VIDIOCSPICT)
-COMPATIBLE_IOCTL(VIDIOCCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCKEY)
-COMPATIBLE_IOCTL(VIDIOCGAUDIO)
-COMPATIBLE_IOCTL(VIDIOCSAUDIO)
-COMPATIBLE_IOCTL(VIDIOCSYNC)
-COMPATIBLE_IOCTL(VIDIOCMCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCGMBUF)
-COMPATIBLE_IOCTL(VIDIOCGUNIT)
-COMPATIBLE_IOCTL(VIDIOCGCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCSCAPTURE)
-/* BTTV specific... */
-COMPATIBLE_IOCTL(_IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]))
-COMPATIBLE_IOCTL(_IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int))
-COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int))
 /* Little p (/dev/rtc, /dev/envctrl, etc.) */
 COMPATIBLE_IOCTL(RTC_AIE_ON)
 COMPATIBLE_IOCTL(RTC_AIE_OFF)
index 1527340554035850282979e5912ea02e0000f27d..2e05e1e6b0e652e471a5bff40c071dc2d40ffb14 100644 (file)
   ({ unsigned long __ptr;                                      \
     __asm__ ("" : "=g"(__ptr) : "0"(ptr));             \
     (typeof(ptr)) (__ptr + (off)); })
+
+
+#define inline         inline          __attribute__((always_inline))
+#define __inline__     __inline__      __attribute__((always_inline))
+#define __inline       __inline        __attribute__((always_inline))
+#define __deprecated                   __attribute__((deprecated))
+#define  noinline                      __attribute__((noinline))
+#define __attribute_pure__             __attribute__((pure))
+#define __attribute_const__            __attribute__((__const__))
diff --git a/include/linux/compiler-gcc2.h b/include/linux/compiler-gcc2.h
deleted file mode 100644 (file)
index ebed176..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Never include this file directly.  Include <linux/compiler.h> instead.  */
-
-/* These definitions are for GCC v2.x.  */
-
-/* Somewhere in the middle of the GCC 2.96 development cycle, we implemented
-   a mechanism by which the user can annotate likely branch directions and
-   expect the blocks to be reordered appropriately.  Define __builtin_expect
-   to nothing for earlier compilers.  */
-#include <linux/compiler-gcc.h>
-
-#if __GNUC_MINOR__ < 96
-# define __builtin_expect(x, expected_value) (x)
-#endif
-
-#define __attribute_used__     __attribute__((__unused__))
-
-/*
- * The attribute `pure' is not implemented in GCC versions earlier
- * than 2.96.
- */
-#if __GNUC_MINOR__ >= 96
-# define __attribute_pure__    __attribute__((pure))
-# define __attribute_const__   __attribute__((__const__))
-#endif
-
-/* GCC 2.95.x/2.96 recognize __va_copy, but not va_copy. Actually later GCC's
- * define both va_copy and __va_copy, but the latter may go away, so limit this
- * to this header */
-#define va_copy                        __va_copy
index a6fa615afab5da1c2fe92da5509e5bab6953829e..4209082ee934bd788c8f67666360f3f39173cf5f 100644 (file)
@@ -3,29 +3,12 @@
 /* These definitions are for GCC v3.x.  */
 #include <linux/compiler-gcc.h>
 
-#if __GNUC_MINOR__ >= 1
-# define inline                inline          __attribute__((always_inline))
-# define __inline__    __inline__      __attribute__((always_inline))
-# define __inline      __inline        __attribute__((always_inline))
-#endif
-
-#if __GNUC_MINOR__ > 0
-# define __deprecated          __attribute__((deprecated))
-#endif
-
 #if __GNUC_MINOR__ >= 3
 # define __attribute_used__    __attribute__((__used__))
 #else
 # define __attribute_used__    __attribute__((__unused__))
 #endif
 
-#define __attribute_pure__     __attribute__((pure))
-#define __attribute_const__    __attribute__((__const__))
-
-#if __GNUC_MINOR__ >= 1
-#define  noinline              __attribute__((noinline))
-#endif
-
 #if __GNUC_MINOR__ >= 4
 #define __must_check           __attribute__((warn_unused_result))
 #endif
index 53686c037a062991dac3eee2101099a27b167c07..e913e9beaf6909ffbdd604f6759434de8dc213e8 100644 (file)
@@ -3,14 +3,7 @@
 /* These definitions are for GCC v4.x.  */
 #include <linux/compiler-gcc.h>
 
-#define inline                 inline          __attribute__((always_inline))
-#define __inline__             __inline__      __attribute__((always_inline))
-#define __inline               __inline        __attribute__((always_inline))
-#define __deprecated           __attribute__((deprecated))
 #define __attribute_used__     __attribute__((__used__))
-#define __attribute_pure__     __attribute__((pure))
-#define __attribute_const__    __attribute__((__const__))
-#define  noinline              __attribute__((noinline))
 #define __must_check           __attribute__((warn_unused_result))
 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
 
index d7378215b8514fdc0a960394a2b1b523fab9dda5..f23d3c6fc2c06ea9766ec18a8580f1de5234975e 100644 (file)
@@ -42,8 +42,6 @@ extern void __chk_io_ptr(void __iomem *);
 # include <linux/compiler-gcc4.h>
 #elif __GNUC__ == 3
 # include <linux/compiler-gcc3.h>
-#elif __GNUC__ == 2
-# include <linux/compiler-gcc2.h>
 #else
 # error Sorry, your compiler is too old/not recognized.
 #endif
index 6e2deef96b342c79cb8af090dc84d2463a088915..c472f972bd6d5f3f54a6e91352b28be617d0757b 100644 (file)
 
 #ifdef CONFIG_CPUSETS
 
+extern int number_of_cpusets;  /* How many cpusets are defined in system? */
+
+extern int cpuset_init_early(void);
 extern int cpuset_init(void);
 extern void cpuset_init_smp(void);
 extern void cpuset_fork(struct task_struct *p);
 extern void cpuset_exit(struct task_struct *p);
-extern cpumask_t cpuset_cpus_allowed(const struct task_struct *p);
+extern cpumask_t cpuset_cpus_allowed(struct task_struct *p);
+extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
 void cpuset_init_current_mems_allowed(void);
-void cpuset_update_current_mems_allowed(void);
-void cpuset_restrict_to_mems_allowed(unsigned long *nodes);
+void cpuset_update_task_memory_state(void);
+#define cpuset_nodes_subset_current_mems_allowed(nodes) \
+               nodes_subset((nodes), current->mems_allowed)
 int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl);
-extern int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask);
+
+extern int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask);
+static int inline cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
+{
+       return number_of_cpusets <= 1 || __cpuset_zone_allowed(z, gfp_mask);
+}
+
 extern int cpuset_excl_nodes_overlap(const struct task_struct *p);
+
+#define cpuset_memory_pressure_bump()                          \
+       do {                                                    \
+               if (cpuset_memory_pressure_enabled)             \
+                       __cpuset_memory_pressure_bump();        \
+       } while (0)
+extern int cpuset_memory_pressure_enabled;
+extern void __cpuset_memory_pressure_bump(void);
+
 extern struct file_operations proc_cpuset_operations;
 extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer);
 
 #else /* !CONFIG_CPUSETS */
 
+static inline int cpuset_init_early(void) { return 0; }
 static inline int cpuset_init(void) { return 0; }
 static inline void cpuset_init_smp(void) {}
 static inline void cpuset_fork(struct task_struct *p) {}
@@ -40,9 +61,14 @@ static inline cpumask_t cpuset_cpus_allowed(struct task_struct *p)
        return cpu_possible_map;
 }
 
+static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
+{
+       return node_possible_map;
+}
+
 static inline void cpuset_init_current_mems_allowed(void) {}
-static inline void cpuset_update_current_mems_allowed(void) {}
-static inline void cpuset_restrict_to_mems_allowed(unsigned long *nodes) {}
+static inline void cpuset_update_task_memory_state(void) {}
+#define cpuset_nodes_subset_current_mems_allowed(nodes) (1)
 
 static inline int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
 {
@@ -59,6 +85,8 @@ static inline int cpuset_excl_nodes_overlap(const struct task_struct *p)
        return 1;
 }
 
+static inline void cpuset_memory_pressure_bump(void) {}
+
 static inline char *cpuset_task_status_allowed(struct task_struct *task,
                                                        char *buffer)
 {
index b10a7f3a8cac9fba8c0db044a3ca44653d940133..f7a9065834636c5824677d274beee1fc2d5f192d 100644 (file)
@@ -38,11 +38,11 @@ extern unsigned int cycx_debug;
 /* Data Structures */
 /* X.25 Command Block. */
 struct cycx_x25_cmd {
-       u16 command PACKED;
-       u16 link    PACKED; /* values: 0 or 1 */
-       u16 len     PACKED; /* values: 0 thru 0x205 (517) */
-       u32 buf     PACKED;
-};
+       u16 command;
+       u16 link;       /* values: 0 or 1 */
+       u16 len;        /* values: 0 thru 0x205 (517) */
+       u32 buf;
+} PACKED;
 
 /* Defines for the 'command' field. */
 #define X25_CONNECT_REQUEST             0x4401
@@ -92,34 +92,34 @@ struct cycx_x25_cmd {
  *     @flags - see dosx25.doc, in portuguese, for details
  */
 struct cycx_x25_config {
-       u8  link        PACKED;
-       u8  speed       PACKED;
-       u8  clock       PACKED;
-       u8  n2          PACKED;
-       u8  n2win       PACKED;
-       u8  n3win       PACKED;
-       u8  nvc         PACKED;
-       u8  pktlen      PACKED;
-       u8  locaddr     PACKED;
-       u8  remaddr     PACKED;
-       u16 t1          PACKED;
-       u16 t2          PACKED;
-       u8  t21         PACKED;
-       u8  npvc        PACKED;
-       u8  t23         PACKED;
-       u8  flags       PACKED;
-};
+       u8  link;
+       u8  speed;
+       u8  clock;
+       u8  n2;
+       u8  n2win;
+       u8  n3win;
+       u8  nvc;
+       u8  pktlen;
+       u8  locaddr;
+       u8  remaddr;
+       u16 t1;
+       u16 t2;
+       u8  t21;
+       u8  npvc;
+       u8  t23;
+       u8  flags;
+} PACKED;
 
 struct cycx_x25_stats {
-       u16 rx_crc_errors       PACKED;
-       u16 rx_over_errors      PACKED;
-       u16 n2_tx_frames        PACKED;
-       u16 n2_rx_frames        PACKED;
-       u16 tx_timeouts         PACKED;
-       u16 rx_timeouts         PACKED;
-       u16 n3_tx_packets       PACKED;
-       u16 n3_rx_packets       PACKED;
-       u16 tx_aborts           PACKED;
-       u16 rx_aborts           PACKED;
-};
+       u16 rx_crc_errors;
+       u16 rx_over_errors;
+       u16 n2_tx_frames;
+       u16 n2_rx_frames;
+       u16 tx_timeouts;
+       u16 rx_timeouts;
+       u16 n3_tx_packets;
+       u16 n3_rx_packets;
+       u16 tx_aborts;
+       u16 rx_aborts;
+} PACKED;
 #endif /* _CYCX_X25_H */
index 46a2ba6175954880fcdfa89bc9a9a063f4e76443..a3ed5e059d479eb2ff7ee712f6adff5170c2a4be 100644 (file)
@@ -95,14 +95,19 @@ struct dentry {
        struct qstr d_name;
 
        struct list_head d_lru;         /* LRU list */
-       struct list_head d_child;       /* child of parent list */
+       /*
+        * d_child and d_rcu can share memory
+        */
+       union {
+               struct list_head d_child;       /* child of parent list */
+               struct rcu_head d_rcu;
+       } d_u;
        struct list_head d_subdirs;     /* our children */
        struct list_head d_alias;       /* inode alias list */
        unsigned long d_time;           /* used by d_revalidate */
        struct dentry_operations *d_op;
        struct super_block *d_sb;       /* The root of the dentry tree */
        void *d_fsdata;                 /* fs-specific data */
-       struct rcu_head d_rcu;
        struct dcookie_struct *d_cookie; /* cookie, if any */
        int d_mounted;
        unsigned char d_iname[DNAME_INLINE_LEN_MIN];    /* small names */
index d41df7047ed72065473f938cb63ac137b047154b..c8cbd90ba3757ace87522db09dc63ff36fbea0a0 100644 (file)
@@ -240,6 +240,15 @@ struct dvb_frontend_event {
 };
 
 
+/**
+ * When set, this flag will disable any zigzagging or other "normal" tuning
+ * behaviour. Additionally, there will be no automatic monitoring of the lock
+ * status, and hence no frontend events will be generated. If a frontend device
+ * is closed, this flag will be automatically turned off when the device is
+ * reopened read-write.
+ */
+#define FE_TUNE_MODE_ONESHOT 0x01
+
 
 #define FE_GET_INFO               _IOR('o', 61, struct dvb_frontend_info)
 
@@ -260,6 +269,7 @@ struct dvb_frontend_event {
 
 #define FE_SET_FRONTEND                   _IOW('o', 76, struct dvb_frontend_parameters)
 #define FE_GET_FRONTEND                   _IOR('o', 77, struct dvb_frontend_parameters)
+#define FE_SET_FRONTEND_TUNE_MODE  _IO('o', 81) /* unsigned int */
 #define FE_GET_EVENT              _IOR('o', 78, struct dvb_frontend_event)
 
 #define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
index fb80fa44c4dda5afe68cd06485d8014c7179be97..4a6f50e31c73191016c1813ef3e3124156d9dbcb 100644 (file)
@@ -114,8 +114,6 @@ extern ssize_t elv_iosched_store(request_queue_t *, const char *, size_t);
 extern int elevator_init(request_queue_t *, char *);
 extern void elevator_exit(elevator_t *);
 extern int elv_rq_merge_ok(struct request *, struct bio *);
-extern int elv_try_merge(struct request *, struct bio *);
-extern int elv_try_last_merge(request_queue_t *, struct bio *);
 
 /*
  * Return values from elevator merger
index ff955dbf510d918503b2f634e85e55ed8bd150c5..d3bfacb2449642f751e182977c23e482b85a8ab8 100644 (file)
@@ -151,6 +151,8 @@ typedef __s64       Elf64_Sxword;
 #define STT_FUNC    2
 #define STT_SECTION 3
 #define STT_FILE    4
+#define STT_COMMON  5
+#define STT_TLS     6
 
 #define ELF_ST_BIND(x)         ((x) >> 4)
 #define ELF_ST_TYPE(x)         (((unsigned int) x) & 0xf)
index 2c9c48d65630ed68464f377f8e2578e88f2497bf..4c82219b0faec46564dc10db396d62c92398b71d 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/config.h>
 #include <linux/limits.h>
 #include <linux/ioctl.h>
-#include <linux/rcuref.h>
 
 /*
  * It's silly to have NR_OPEN bigger than NR_FILE, but you can change
@@ -104,11 +103,11 @@ extern int dir_notify_enable;
 #define MS_MOVE                8192
 #define MS_REC         16384
 #define MS_VERBOSE     32768
+#define MS_POSIXACL    (1<<16) /* VFS does not apply the umask */
 #define MS_UNBINDABLE  (1<<17) /* change to unbindable */
 #define MS_PRIVATE     (1<<18) /* change to private */
 #define MS_SLAVE       (1<<19) /* change to slave */
 #define MS_SHARED      (1<<20) /* change to shared */
-#define MS_POSIXACL    (1<<16) /* VFS does not apply the umask */
 #define MS_ACTIVE      (1<<30)
 #define MS_NOUSER      (1<<31)
 
@@ -225,6 +224,7 @@ extern int dir_notify_enable;
 #include <asm/semaphore.h>
 #include <asm/byteorder.h>
 
+struct hd_geometry;
 struct iovec;
 struct nameidata;
 struct kiocb;
@@ -653,7 +653,7 @@ extern spinlock_t files_lock;
 #define file_list_lock() spin_lock(&files_lock);
 #define file_list_unlock() spin_unlock(&files_lock);
 
-#define get_file(x)    rcuref_inc(&(x)->f_count)
+#define get_file(x)    atomic_inc(&(x)->f_count)
 #define file_count(x)  atomic_read(&(x)->f_count)
 
 #define        MAX_NON_LFS     ((1UL<<31) - 1)
@@ -808,7 +808,6 @@ struct super_block {
        struct list_head        s_list;         /* Keep this first */
        dev_t                   s_dev;          /* search index; _not_ kdev_t */
        unsigned long           s_blocksize;
-       unsigned long           s_old_blocksize;
        unsigned char           s_blocksize_bits;
        unsigned char           s_dirt;
        unsigned long long      s_maxbytes;     /* Max file size */
@@ -963,6 +962,7 @@ struct block_device_operations {
        int (*direct_access) (struct block_device *, sector_t, unsigned long *);
        int (*media_changed) (struct gendisk *);
        int (*revalidate_disk) (struct gendisk *);
+       int (*getgeo)(struct block_device *, struct hd_geometry *);
        struct module *owner;
 };
 
@@ -1345,7 +1345,8 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
 
 /* fs/open.c */
 
-extern int do_truncate(struct dentry *, loff_t start, struct file *filp);
+extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
+                      struct file *filp);
 extern long do_sys_open(const char __user *filename, int flags, int mode);
 extern struct file *filp_open(const char *, int, int);
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
index fb46f8d56999108036ef1378f8525332b92a0fe3..6ff2d365895f550e72fc6e94a54696d3467573ea 100644 (file)
 #define I2C_DRIVERID_SAA711X   73      /* saa711x video encoders       */
 #define I2C_DRIVERID_AKITAIOEXP        74      /* IO Expander on Sharp SL-C1000 */
 #define I2C_DRIVERID_INFRARED  75      /* I2C InfraRed on Video boards */
+#define I2C_DRIVERID_TVP5150   76      /* TVP5150 video decoder        */
 
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
index 7b6a6a58e465e950f6d53ab6422851d6a6c6f70f..ef8d0cbb832f14496b0687600b5500e79e77cd99 100644 (file)
@@ -801,7 +801,7 @@ typedef struct hwif_s {
        unsigned dma;
 
        void (*led_act)(void *data, int rw);
-} ____cacheline_maxaligned_in_smp ide_hwif_t;
+} ____cacheline_internodealigned_in_smp ide_hwif_t;
 
 /*
  *  internal ide interrupt handler type
@@ -1001,6 +1001,7 @@ extern int noautodma;
 
 extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
 extern int __ide_end_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs);
+extern void ide_softirq_done(struct request *rq);
 
 /*
  * This is used on exit from the driver to designate the next irq handler
index 511999c7eedaa96149d2e44f06e0059e94c93141..395f0aad9cbf048a0650ba3e48565669a96707bd 100644 (file)
@@ -131,17 +131,17 @@ struct frad_conf
 /* these are the fields of an RFC 1490 header */
 struct frhdr
 {
-   unsigned char  control      __attribute__((packed));
+   unsigned char  control;
 
    /* for IP packets, this can be the NLPID */
-   unsigned char  pad          __attribute__((packed)); 
+   unsigned char  pad;
 
-   unsigned char  NLPID                __attribute__((packed));
-   unsigned char  OUI[3]       __attribute__((packed));
-   unsigned short PID          __attribute__((packed));
+   unsigned char  NLPID;
+   unsigned char  OUI[3];
+   unsigned short PID;
 
 #define IP_NLPID pad 
-};
+} __attribute__((packed));
 
 /* see RFC 1490 for the definition of the following */
 #define FRAD_I_UI              0x03
index 41f150a3d2dda5a2445b100d55c87a904834ccd8..2c08fdc2bdf70b5aff6a670e39299ba227f898c7 100644 (file)
@@ -79,7 +79,7 @@ static inline void __deprecated save_flags(unsigned long *x)
 {
        local_save_flags(*x);
 }
-#define save_flags(x) save_flags(&x);
+#define save_flags(x) save_flags(&x)
 static inline void __deprecated restore_flags(unsigned long x)
 {
        local_irq_restore(x);
@@ -112,7 +112,7 @@ enum
        TIMER_SOFTIRQ,
        NET_TX_SOFTIRQ,
        NET_RX_SOFTIRQ,
-       SCSI_SOFTIRQ,
+       BLOCK_SOFTIRQ,
        TASKLET_SOFTIRQ
 };
 
index 93bbed5c6cf426a61683ec8204363f75f67fc08b..9c8f4c9ed4298d35d90e08f00ec9274370acf50d 100644 (file)
@@ -191,6 +191,10 @@ struct inet6_skb_parm {
        __u16                   srcrt;
        __u16                   dst1;
        __u16                   lastopt;
+       __u32                   nhoff;
+       __u16                   flags;
+
+#define IP6SKB_XFRM_TRANSFORMED        1
 };
 
 #define IP6CB(skb)     ((struct inet6_skb_parm*)((skb)->cb))
index 7a4eacd77cb2eee1710467636d87b8b1a8b410b0..04e10f9f14f890b2cb0468f06f9c872a1a5a2803 100644 (file)
@@ -282,43 +282,43 @@ typedef struct setup_parm {
 
 typedef struct T30_s {
        /* session parameters */
-       __u8 resolution         __attribute__ ((packed));
-       __u8 rate               __attribute__ ((packed));
-       __u8 width              __attribute__ ((packed));
-       __u8 length             __attribute__ ((packed));
-       __u8 compression        __attribute__ ((packed));
-       __u8 ecm                __attribute__ ((packed));
-       __u8 binary             __attribute__ ((packed));
-       __u8 scantime           __attribute__ ((packed));
-       __u8 id[FAXIDLEN]       __attribute__ ((packed));
+       __u8 resolution;
+       __u8 rate;
+       __u8 width;
+       __u8 length;
+       __u8 compression;
+       __u8 ecm;
+       __u8 binary;
+       __u8 scantime;
+       __u8 id[FAXIDLEN];
        /* additional parameters */
-       __u8 phase              __attribute__ ((packed));
-       __u8 direction          __attribute__ ((packed));
-       __u8 code               __attribute__ ((packed));
-       __u8 badlin             __attribute__ ((packed));
-       __u8 badmul             __attribute__ ((packed));
-       __u8 bor                __attribute__ ((packed));
-       __u8 fet                __attribute__ ((packed));
-       __u8 pollid[FAXIDLEN]   __attribute__ ((packed));
-       __u8 cq                 __attribute__ ((packed));
-       __u8 cr                 __attribute__ ((packed));
-       __u8 ctcrty             __attribute__ ((packed));
-       __u8 minsp              __attribute__ ((packed));
-       __u8 phcto              __attribute__ ((packed));
-       __u8 rel                __attribute__ ((packed));
-       __u8 nbc                __attribute__ ((packed));
+       __u8 phase;
+       __u8 direction;
+       __u8 code;
+       __u8 badlin;
+       __u8 badmul;
+       __u8 bor;
+       __u8 fet;
+       __u8 pollid[FAXIDLEN];
+       __u8 cq;
+       __u8 cr;
+       __u8 ctcrty;
+       __u8 minsp;
+       __u8 phcto;
+       __u8 rel;
+       __u8 nbc;
        /* remote station parameters */
-       __u8 r_resolution       __attribute__ ((packed));
-       __u8 r_rate             __attribute__ ((packed));
-       __u8 r_width            __attribute__ ((packed));
-       __u8 r_length           __attribute__ ((packed));
-       __u8 r_compression      __attribute__ ((packed));
-       __u8 r_ecm              __attribute__ ((packed));
-       __u8 r_binary           __attribute__ ((packed));
-       __u8 r_scantime         __attribute__ ((packed));
-       __u8 r_id[FAXIDLEN]     __attribute__ ((packed));
-       __u8 r_code             __attribute__ ((packed));
-} T30_s;
+       __u8 r_resolution;
+       __u8 r_rate;
+       __u8 r_width;
+       __u8 r_length;
+       __u8 r_compression;
+       __u8 r_ecm;
+       __u8 r_binary;
+       __u8 r_scantime;
+       __u8 r_id[FAXIDLEN];
+       __u8 r_code;
+} __attribute__((packed)) T30_s;
 
 #define ISDN_TTY_FAX_CONN_IN   0
 #define ISDN_TTY_FAX_CONN_OUT  1
index b1e407a4fbda1ec9b101c5e0bd2c3c4378b7bb5b..ca7ff8fdd0907b8760fb5f656f50146beb387c42 100644 (file)
@@ -316,8 +316,6 @@ extern int randomize_va_space;
 #endif
 
 /* Trap pasters of __FUNCTION__ at compile-time */
-#if __GNUC__ > 2 || __GNUC_MINOR__ >= 95
 #define __FUNCTION__ (__func__)
-#endif
 
 #endif
index 4d189e51bc6c37aff256c16ffdf5260044d19329..cbf464ad9589526d139b369ea3c00f5b920348c9 100644 (file)
@@ -177,6 +177,8 @@ struct key {
 /*
  * kernel managed key type definition
  */
+typedef int (*request_key_actor_t)(struct key *key, struct key *authkey, const char *op);
+
 struct key_type {
        /* name of the type */
        const char *name;
@@ -218,6 +220,16 @@ struct key_type {
         */
        long (*read)(const struct key *key, char __user *buffer, size_t buflen);
 
+       /* handle request_key() for this type instead of invoking
+        * /sbin/request-key (optional)
+        * - key is the key to instantiate
+        * - authkey is the authority to assume when instantiating this key
+        * - op is the operation to be done, usually "create"
+        * - the call must not return until the instantiation process has run
+        *   its course
+        */
+       request_key_actor_t request_key;
+
        /* internal fields */
        struct list_head        link;           /* link in types list */
 };
index 8d7c59a29e094f1e040b603496f335e8d38ec86c..3365945640c9a93d907efedb5c3ca707737797d2 100644 (file)
@@ -19,6 +19,7 @@
 #define KEY_SPEC_USER_KEYRING          -4      /* - key ID for UID-specific keyring */
 #define KEY_SPEC_USER_SESSION_KEYRING  -5      /* - key ID for UID-session keyring */
 #define KEY_SPEC_GROUP_KEYRING         -6      /* - key ID for GID-specific keyring */
+#define KEY_SPEC_REQKEY_AUTH_KEY       -7      /* - key ID for assumed request_key auth key */
 
 /* request-key default keyrings */
 #define KEY_REQKEY_DEFL_NO_CHANGE              -1
@@ -46,5 +47,7 @@
 #define KEYCTL_INSTANTIATE             12      /* instantiate a partially constructed key */
 #define KEYCTL_NEGATE                  13      /* negate a partially constructed key */
 #define KEYCTL_SET_REQKEY_KEYRING      14      /* set default request-key keyring */
+#define KEYCTL_SET_TIMEOUT             15      /* set key timeout */
+#define KEYCTL_ASSUME_AUTHORITY                16      /* assume request_key() authorisation */
 
 #endif /*  _LINUX_KEYCTL_H */
index dc4081b6f161e3f697c3280bbf9547aed9bfbea1..e251dc43d0f5ab8faee980ade3cbc3780db499ea 100644 (file)
@@ -70,21 +70,15 @@ static inline void unregister_memory_notifier(struct notifier_block *nb)
 {
 }
 #else
-extern int register_memory(struct memory_block *, struct mem_section *section, struct node *);
 extern int register_new_memory(struct mem_section *);
 extern int unregister_memory_section(struct mem_section *);
 extern int memory_dev_init(void);
-extern int register_memory_notifier(struct notifier_block *nb);
-extern void unregister_memory_notifier(struct notifier_block *nb);
+extern int remove_memory_block(unsigned long, struct mem_section *, int);
 
 #define CONFIG_MEM_BLOCK_SIZE  (PAGES_PER_SECTION<<PAGE_SHIFT)
 
-extern int invalidate_phys_mapping(unsigned long, unsigned long);
 struct notifier_block;
 
-extern int register_memory_notifier(struct notifier_block *nb);
-extern void unregister_memory_notifier(struct notifier_block *nb);
-
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
 #define hotplug_memory_notifier(fn, pri) {                     \
index ed00b278cb9324935aa0bfb3f8a0b7484eb6e992..c7ac77e873b3fa800e4c4d3a3db0bd43dcaf7192 100644 (file)
@@ -22,6 +22,9 @@
 
 /* Flags for mbind */
 #define MPOL_MF_STRICT (1<<0)  /* Verify existing pages in the mapping */
+#define MPOL_MF_MOVE   (1<<1)  /* Move pages owned by this process to conform to mapping */
+#define MPOL_MF_MOVE_ALL (1<<2)        /* Move every page to conform to mapping */
+#define MPOL_MF_INTERNAL (1<<3)        /* Internal flags start here */
 
 #ifdef __KERNEL__
 
@@ -65,6 +68,7 @@ struct mempolicy {
                nodemask_t       nodes;         /* interleave */
                /* undefined for default */
        } v;
+       nodemask_t cpuset_mems_allowed; /* mempolicy relative to these nodes */
 };
 
 /*
@@ -141,12 +145,21 @@ void mpol_free_shared_policy(struct shared_policy *p);
 struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
                                            unsigned long idx);
 
-struct mempolicy *get_vma_policy(struct task_struct *task,
-                       struct vm_area_struct *vma, unsigned long addr);
-
 extern void numa_default_policy(void);
 extern void numa_policy_init(void);
-extern void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new);
+extern void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *new);
+extern void mpol_rebind_task(struct task_struct *tsk,
+                                       const nodemask_t *new);
+extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
+#define set_cpuset_being_rebound(x) (cpuset_being_rebound = (x))
+
+#ifdef CONFIG_CPUSET
+#define current_cpuset_is_being_rebound() \
+                               (cpuset_being_rebound == current->cpuset)
+#else
+#define current_cpuset_is_being_rebound() 0
+#endif
+
 extern struct mempolicy default_policy;
 extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
                unsigned long addr);
@@ -159,6 +172,11 @@ static inline void check_highest_zone(int k)
                policy_zone = k;
 }
 
+int do_migrate_pages(struct mm_struct *mm,
+       const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags);
+
+extern void *cpuset_being_rebound;     /* Trigger mpol_copy vma rebind */
+
 #else
 
 struct mempolicy {};
@@ -218,17 +236,35 @@ static inline void numa_default_policy(void)
 {
 }
 
-static inline void numa_policy_rebind(const nodemask_t *old,
+static inline void mpol_rebind_policy(struct mempolicy *pol,
                                        const nodemask_t *new)
 {
 }
 
+static inline void mpol_rebind_task(struct task_struct *tsk,
+                                       const nodemask_t *new)
+{
+}
+
+static inline void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new)
+{
+}
+
+#define set_cpuset_being_rebound(x) do {} while (0)
+
 static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma,
                unsigned long addr)
 {
        return NODE_DATA(0)->node_zonelists + gfp_zone(GFP_HIGHUSER);
 }
 
+static inline int do_migrate_pages(struct mm_struct *mm,
+                       const nodemask_t *from_nodes,
+                       const nodemask_t *to_nodes, int flags)
+{
+       return 0;
+}
+
 static inline void check_highest_zone(int k)
 {
 }
index bc01fff3aa0156a4f717e831890fbceb16be6cb8..df80e63903b570b4ee79c7b8862e14284037870d 100644 (file)
@@ -223,24 +223,27 @@ struct page {
                                         * & limit reverse map searches.
                                         */
        union {
-               unsigned long private;  /* Mapping-private opaque data:
-                                        * usually used for buffer_heads
-                                        * if PagePrivate set; used for
-                                        * swp_entry_t if PageSwapCache
-                                        * When page is free, this indicates
-                                        * order in the buddy system.
-                                        */
+           struct {
+               unsigned long private;          /* Mapping-private opaque data:
+                                                * usually used for buffer_heads
+                                                * if PagePrivate set; used for
+                                                * swp_entry_t if PageSwapCache.
+                                                * When page is free, this
+                                                * indicates order in the buddy
+                                                * system.
+                                                */
+               struct address_space *mapping;  /* If low bit clear, points to
+                                                * inode address_space, or NULL.
+                                                * If page mapped as anonymous
+                                                * memory, low bit is set, and
+                                                * it points to anon_vma object:
+                                                * see PAGE_MAPPING_ANON below.
+                                                */
+           };
 #if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
-               spinlock_t ptl;
+           spinlock_t ptl;
 #endif
-       } u;
-       struct address_space *mapping;  /* If low bit clear, points to
-                                        * inode address_space, or NULL.
-                                        * If page mapped as anonymous
-                                        * memory, low bit is set, and
-                                        * it points to anon_vma object:
-                                        * see PAGE_MAPPING_ANON below.
-                                        */
+       };
        pgoff_t index;                  /* Our offset within mapping. */
        struct list_head lru;           /* Pageout list, eg. active_list
                                         * protected by zone->lru_lock !
@@ -261,8 +264,8 @@ struct page {
 #endif /* WANT_PAGE_VIRTUAL */
 };
 
-#define page_private(page)             ((page)->u.private)
-#define set_page_private(page, v)      ((page)->u.private = (v))
+#define page_private(page)             ((page)->private)
+#define set_page_private(page, v)      ((page)->private = (v))
 
 /*
  * FIXME: take this include out, include page-flags.h in
@@ -308,7 +311,7 @@ struct page {
  */
 #define get_page_testone(p)    atomic_inc_and_test(&(p)->_count)
 
-#define set_page_count(p,v)    atomic_set(&(p)->_count, v - 1)
+#define set_page_count(p,v)    atomic_set(&(p)->_count, (v) - 1)
 #define __put_page(p)          atomic_dec(&(p)->_count)
 
 extern void FASTCALL(__page_cache_release(struct page *));
@@ -815,7 +818,7 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
  * overflow into the next struct page (as it might with DEBUG_SPINLOCK).
  * When freeing, reset page->mapping so free_pages_check won't complain.
  */
-#define __pte_lockptr(page)    &((page)->u.ptl)
+#define __pte_lockptr(page)    &((page)->ptl)
 #define pte_lock_init(_page)   do {                                    \
        spin_lock_init(__pte_lockptr(_page));                           \
 } while (0)
@@ -1036,5 +1039,12 @@ int in_gate_area_no_task(unsigned long addr);
 /* /proc/<pid>/oom_adj set to -17 protects from the oom-killer */
 #define OOM_DISABLE -17
 
+int drop_caches_sysctl_handler(struct ctl_table *, int, struct file *,
+                                       void __user *, size_t *, loff_t *);
+int shrink_slab(unsigned long scanned, gfp_t gfp_mask,
+                       unsigned long lru_pages);
+void drop_pagecache(void);
+void drop_slab(void);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
index 47762ca695a59de5e0b3b55c3b7cbd9255f07088..49cc68af01f8e6d971d870fd952d229d31810628 100644 (file)
@@ -38,3 +38,25 @@ del_page_from_lru(struct zone *zone, struct page *page)
                zone->nr_inactive--;
        }
 }
+
+/*
+ * Isolate one page from the LRU lists.
+ *
+ * - zone->lru_lock must be held
+ */
+static inline int __isolate_lru_page(struct page *page)
+{
+       if (unlikely(!TestClearPageLRU(page)))
+               return 0;
+
+       if (get_page_testone(page)) {
+               /*
+                * It is being freed elsewhere
+                */
+               __put_page(page);
+               SetPageLRU(page);
+               return -ENOENT;
+       }
+
+       return 1;
+}
index c34f4a2c62f8e252bc9c260ebad20d419a180750..7e4ae6ab197724f1010544d20ddbddefb49e4dca 100644 (file)
@@ -38,7 +38,7 @@ struct pglist_data;
 #if defined(CONFIG_SMP)
 struct zone_padding {
        char x[0];
-} ____cacheline_maxaligned_in_smp;
+} ____cacheline_internodealigned_in_smp;
 #define ZONE_PADDING(name)     struct zone_padding name;
 #else
 #define ZONE_PADDING(name)
@@ -233,7 +233,7 @@ struct zone {
         * rarely used fields:
         */
        char                    *name;
-} ____cacheline_maxaligned_in_smp;
+} ____cacheline_internodealigned_in_smp;
 
 
 /*
@@ -437,6 +437,8 @@ int min_free_kbytes_sysctl_handler(struct ctl_table *, int, struct file *,
 extern int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1];
 int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *, int, struct file *,
                                        void __user *, size_t *, loff_t *);
+int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *, int, struct file *,
+                                       void __user *, size_t *, loff_t *);
 
 #include <linux/topology.h>
 /* Returns the number of the current Node. */
index dd4e83eba933a3f345e55077b745afb7975c853a..b98a709f179406e1fec94a3679eb9184cb8f98e3 100644 (file)
@@ -22,7 +22,8 @@
 #define MNT_NOEXEC     0x04
 #define MNT_SHARED     0x10    /* if the vfsmount is a shared mount */
 #define MNT_UNBINDABLE 0x20    /* if the vfsmount is a unbindable mount */
-#define MNT_PNODE_MASK 0x30    /* propogation flag mask */
+
+#define MNT_PNODE_MASK (MNT_SHARED | MNT_UNBINDABLE)
 
 struct vfsmount {
        struct list_head mnt_hash;
index 941da5c016a01e1434d3291fe1ec466c16adbb45..e933e2a355adcea8331913ca5aec0bc6cdf9d3ce 100644 (file)
@@ -329,7 +329,8 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
 extern void fat_cache_inval_inode(struct inode *inode);
 extern int fat_get_cluster(struct inode *inode, int cluster,
                           int *fclus, int *dclus);
-extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys);
+extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
+                   unsigned long *mapped_blocks);
 
 /* fat/dir.c */
 extern struct file_operations fat_dir_operations;
index 99f77876b716648070b526639c899f3677ef483c..99f0adeeb3f348e58c65312133217055a6ccf3c0 100644 (file)
 #define NCP_DEALLOC_SLOT_REQUEST (0x5555)
 
 struct ncp_request_header {
-       __u16 type __attribute__((packed));
-       __u8 sequence __attribute__((packed));
-       __u8 conn_low __attribute__((packed));
-       __u8 task __attribute__((packed));
-       __u8 conn_high __attribute__((packed));
-       __u8 function __attribute__((packed));
-       __u8 data[0] __attribute__((packed));
-};
+       __u16 type;
+       __u8 sequence;
+       __u8 conn_low;
+       __u8 task;
+       __u8 conn_high;
+       __u8 function;
+       __u8 data[0];
+} __attribute__((packed));
 
 #define NCP_REPLY                (0x3333)
 #define NCP_WATCHDOG            (0x3E3E)
 #define NCP_POSITIVE_ACK         (0x9999)
 
 struct ncp_reply_header {
-       __u16 type __attribute__((packed));
-       __u8 sequence __attribute__((packed));
-       __u8 conn_low __attribute__((packed));
-       __u8 task __attribute__((packed));
-       __u8 conn_high __attribute__((packed));
-       __u8 completion_code __attribute__((packed));
-       __u8 connection_state __attribute__((packed));
-       __u8 data[0] __attribute__((packed));
-};
+       __u16 type;
+       __u8 sequence;
+       __u8 conn_low;
+       __u8 task;
+       __u8 conn_high;
+       __u8 completion_code;
+       __u8 connection_state;
+       __u8 data[0];
+} __attribute__((packed));
 
 #define NCP_VOLNAME_LEN (16)
 #define NCP_NUMBER_OF_VOLUMES (256)
@@ -128,37 +128,37 @@ struct nw_nfs_info {
 };
 
 struct nw_info_struct {
-       __u32 spaceAlloc __attribute__((packed));
-       __le32 attributes __attribute__((packed));
-       __u16 flags __attribute__((packed));
-       __le32 dataStreamSize __attribute__((packed));
-       __le32 totalStreamSize __attribute__((packed));
-       __u16 numberOfStreams __attribute__((packed));
-       __le16 creationTime __attribute__((packed));
-       __le16 creationDate __attribute__((packed));
-       __u32 creatorID __attribute__((packed));
-       __le16 modifyTime __attribute__((packed));
-       __le16 modifyDate __attribute__((packed));
-       __u32 modifierID __attribute__((packed));
-       __le16 lastAccessDate __attribute__((packed));
-       __u16 archiveTime __attribute__((packed));
-       __u16 archiveDate __attribute__((packed));
-       __u32 archiverID __attribute__((packed));
-       __u16 inheritedRightsMask __attribute__((packed));
-       __le32 dirEntNum __attribute__((packed));
-       __le32 DosDirNum __attribute__((packed));
-       __u32 volNumber __attribute__((packed));
-       __u32 EADataSize __attribute__((packed));
-       __u32 EAKeyCount __attribute__((packed));
-       __u32 EAKeySize __attribute__((packed));
-       __u32 NSCreator __attribute__((packed));
-       __u8 nameLen __attribute__((packed));
-       __u8 entryName[256] __attribute__((packed));
+       __u32 spaceAlloc;
+       __le32 attributes;
+       __u16 flags;
+       __le32 dataStreamSize;
+       __le32 totalStreamSize;
+       __u16 numberOfStreams;
+       __le16 creationTime;
+       __le16 creationDate;
+       __u32 creatorID;
+       __le16 modifyTime;
+       __le16 modifyDate;
+       __u32 modifierID;
+       __le16 lastAccessDate;
+       __u16 archiveTime;
+       __u16 archiveDate;
+       __u32 archiverID;
+       __u16 inheritedRightsMask;
+       __le32 dirEntNum;
+       __le32 DosDirNum;
+       __u32 volNumber;
+       __u32 EADataSize;
+       __u32 EAKeyCount;
+       __u32 EAKeySize;
+       __u32 NSCreator;
+       __u8 nameLen;
+       __u8 entryName[256];
        /* libncp may depend on there being nothing after entryName */
 #ifdef __KERNEL__
        struct nw_nfs_info nfs;
 #endif
-};
+} __attribute__((packed));
 
 /* modify mask - use with MODIFY_DOS_INFO structure */
 #define DM_ATTRIBUTES            (cpu_to_le32(0x02))
@@ -176,26 +176,26 @@ struct nw_info_struct {
 #define DM_MAXIMUM_SPACE         (cpu_to_le32(0x2000))
 
 struct nw_modify_dos_info {
-       __le32 attributes __attribute__((packed));
-       __le16 creationDate __attribute__((packed));
-       __le16 creationTime __attribute__((packed));
-       __u32 creatorID __attribute__((packed));
-       __le16 modifyDate __attribute__((packed));
-       __le16 modifyTime __attribute__((packed));
-       __u32 modifierID __attribute__((packed));
-       __u16 archiveDate __attribute__((packed));
-       __u16 archiveTime __attribute__((packed));
-       __u32 archiverID __attribute__((packed));
-       __le16 lastAccessDate __attribute__((packed));
-       __u16 inheritanceGrantMask __attribute__((packed));
-       __u16 inheritanceRevokeMask __attribute__((packed));
-       __u32 maximumSpace __attribute__((packed));
-};
+       __le32 attributes;
+       __le16 creationDate;
+       __le16 creationTime;
+       __u32 creatorID;
+       __le16 modifyDate;
+       __le16 modifyTime;
+       __u32 modifierID;
+       __u16 archiveDate;
+       __u16 archiveTime;
+       __u32 archiverID;
+       __le16 lastAccessDate;
+       __u16 inheritanceGrantMask;
+       __u16 inheritanceRevokeMask;
+       __u32 maximumSpace;
+} __attribute__((packed));
 
 struct nw_search_sequence {
-       __u8 volNumber __attribute__((packed));
-       __u32 dirBase __attribute__((packed));
-       __u32 sequence __attribute__((packed));
-};
+       __u8 volNumber;
+       __u32 dirBase;
+       __u32 sequence;
+} __attribute__((packed));
 
 #endif                         /* _LINUX_NCP_H */
index be365e70ee998a25865e4504fd853aa9b2bde2a3..4cf6088625c1c6d9bb3c70a3fa820c854e0bae4e 100644 (file)
@@ -168,6 +168,37 @@ void nf_log_packet(int pf,
                   const struct net_device *out,
                   struct nf_loginfo *li,
                   const char *fmt, ...);
+
+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
+                struct net_device *indev, struct net_device *outdev,
+                int (*okfn)(struct sk_buff *), int thresh);
+
+/**
+ *     nf_hook_thresh - call a netfilter hook
+ *     
+ *     Returns 1 if the hook has allowed the packet to pass.  The function
+ *     okfn must be invoked by the caller in this case.  Any other return
+ *     value indicates the packet has been consumed by the hook.
+ */
+static inline int nf_hook_thresh(int pf, unsigned int hook,
+                                struct sk_buff **pskb,
+                                struct net_device *indev,
+                                struct net_device *outdev,
+                                int (*okfn)(struct sk_buff *), int thresh)
+{
+#ifndef CONFIG_NETFILTER_DEBUG
+       if (list_empty(&nf_hooks[pf][hook]))
+               return 1;
+#endif
+       return nf_hook_slow(pf, hook, pskb, indev, outdev, okfn, thresh);
+}
+
+static inline int nf_hook(int pf, unsigned int hook, struct sk_buff **pskb,
+                         struct net_device *indev, struct net_device *outdev,
+                         int (*okfn)(struct sk_buff *))
+{
+       return nf_hook_thresh(pf, hook, pskb, indev, outdev, okfn, INT_MIN);
+}
                    
 /* Activate hook; either okfn or kfree_skb called, unless a hook
    returns NF_STOLEN (in which case, it's up to the hook to deal with
@@ -188,35 +219,17 @@ void nf_log_packet(int pf,
 
 /* This is gross, but inline doesn't cut it for avoiding the function
    call in fast path: gcc doesn't inline (needs value tracking?). --RR */
-#ifdef CONFIG_NETFILTER_DEBUG
-#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                           \
-({int __ret;                                                                  \
-if ((__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1) \
-       __ret = (okfn)(skb);                                                   \
-__ret;})
-#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)            \
-({int __ret;                                                                  \
-if ((__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1)  \
-       __ret = (okfn)(skb);                                                   \
-__ret;})
-#else
-#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                           \
-({int __ret;                                                                  \
-if (list_empty(&nf_hooks[pf][hook]) ||                                        \
-    (__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1) \
-       __ret = (okfn)(skb);                                                   \
-__ret;})
+
+/* HX: It's slightly less gross now. */
+
 #define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)            \
 ({int __ret;                                                                  \
-if (list_empty(&nf_hooks[pf][hook]) ||                                        \
-    (__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1)  \
+if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1)\
        __ret = (okfn)(skb);                                                   \
 __ret;})
-#endif
 
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
-                struct net_device *indev, struct net_device *outdev,
-                int (*okfn)(struct sk_buff *), int thresh);
+#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
+       NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)
 
 /* Call setsockopt() */
 int nf_setsockopt(struct sock *sk, int pf, int optval, char __user *opt, 
@@ -261,6 +274,20 @@ struct nf_queue_rerouter {
 extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
 extern int nf_unregister_queue_rerouter(int pf);
 
+#include <net/flow.h>
+extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
+
+static inline void
+nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family)
+{
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+       void (*decodefn)(struct sk_buff *, struct flowi *);
+
+       if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL)
+               decodefn(skb, fl);
+#endif
+}
+
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 extern struct proc_dir_entry *proc_net_netfilter;
@@ -268,7 +295,24 @@ extern struct proc_dir_entry *proc_net_netfilter;
 
 #else /* !CONFIG_NETFILTER */
 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
+static inline int nf_hook_thresh(int pf, unsigned int hook,
+                                struct sk_buff **pskb,
+                                struct net_device *indev,
+                                struct net_device *outdev,
+                                int (*okfn)(struct sk_buff *), int thresh)
+{
+       return okfn(*pskb);
+}
+static inline int nf_hook(int pf, unsigned int hook, struct sk_buff **pskb,
+                         struct net_device *indev, struct net_device *outdev,
+                         int (*okfn)(struct sk_buff *))
+{
+       return okfn(*pskb);
+}
 static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
+struct flowi;
+static inline void
+nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) {}
 #endif /*CONFIG_NETFILTER*/
 
 #endif /*__KERNEL__*/
diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h
new file mode 100644 (file)
index 0000000..7fd1bec
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _IPT_POLICY_H
+#define _IPT_POLICY_H
+
+#define IPT_POLICY_MAX_ELEM    4
+
+enum ipt_policy_flags
+{
+       IPT_POLICY_MATCH_IN     = 0x1,
+       IPT_POLICY_MATCH_OUT    = 0x2,
+       IPT_POLICY_MATCH_NONE   = 0x4,
+       IPT_POLICY_MATCH_STRICT = 0x8,
+};
+
+enum ipt_policy_modes
+{
+       IPT_POLICY_MODE_TRANSPORT,
+       IPT_POLICY_MODE_TUNNEL
+};
+
+struct ipt_policy_spec
+{
+       u_int8_t        saddr:1,
+                       daddr:1,
+                       proto:1,
+                       mode:1,
+                       spi:1,
+                       reqid:1;
+};
+
+struct ipt_policy_elem
+{
+       u_int32_t       saddr;
+       u_int32_t       smask;
+       u_int32_t       daddr;
+       u_int32_t       dmask;
+       u_int32_t       spi;
+       u_int32_t       reqid;
+       u_int8_t        proto;
+       u_int8_t        mode;
+
+       struct ipt_policy_spec  match;
+       struct ipt_policy_spec  invert;
+};
+
+struct ipt_policy_info
+{
+       struct ipt_policy_elem pol[IPT_POLICY_MAX_ELEM];
+       u_int16_t flags;
+       u_int16_t len;
+};
+
+#endif /* _IPT_POLICY_H */
diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h
new file mode 100644 (file)
index 0000000..5a93afc
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _IP6T_POLICY_H
+#define _IP6T_POLICY_H
+
+#define IP6T_POLICY_MAX_ELEM   4
+
+enum ip6t_policy_flags
+{
+       IP6T_POLICY_MATCH_IN            = 0x1,
+       IP6T_POLICY_MATCH_OUT           = 0x2,
+       IP6T_POLICY_MATCH_NONE          = 0x4,
+       IP6T_POLICY_MATCH_STRICT        = 0x8,
+};
+
+enum ip6t_policy_modes
+{
+       IP6T_POLICY_MODE_TRANSPORT,
+       IP6T_POLICY_MODE_TUNNEL
+};
+
+struct ip6t_policy_spec
+{
+       u_int8_t        saddr:1,
+                       daddr:1,
+                       proto:1,
+                       mode:1,
+                       spi:1,
+                       reqid:1;
+};
+
+struct ip6t_policy_elem
+{
+       struct in6_addr saddr;
+       struct in6_addr smask;
+       struct in6_addr daddr;
+       struct in6_addr dmask;
+       u_int32_t       spi;
+       u_int32_t       reqid;
+       u_int8_t        proto;
+       u_int8_t        mode;
+
+       struct ip6t_policy_spec match;
+       struct ip6t_policy_spec invert;
+};
+
+struct ip6t_policy_info
+{
+       struct ip6t_policy_elem pol[IP6T_POLICY_MAX_ELEM];
+       u_int16_t flags;
+       u_int16_t len;
+};
+
+#endif /* _IP6T_POLICY_H */
index def32c5715bea2a257c398ce1e3eaa847d760667..8eb7fa76c1d025055683c6428388213e9ae2af2c 100644 (file)
@@ -5,6 +5,9 @@
  * pages.  A pagevec is a multipage container which is used for that.
  */
 
+#ifndef _LINUX_PAGEVEC_H
+#define _LINUX_PAGEVEC_H
+
 /* 14 pointers + two long's align the pagevec structure to a power of two */
 #define PAGEVEC_SIZE   14
 
@@ -83,3 +86,5 @@ static inline void pagevec_lru_add(struct pagevec *pvec)
        if (pagevec_count(pvec))
                __pagevec_lru_add(pvec);
 }
+
+#endif /* _LINUX_PAGEVEC_H */
index f7ff0b0c40319b48e6b285c9cc89a12af65d4616..f67f838a3a1f27390711aa90259723ea951f771a 100644 (file)
@@ -236,12 +236,14 @@ struct pardevice {
 
 /* IEEE1284 information */
 
-/* IEEE1284 phases */
+/* IEEE1284 phases. These are exposed to userland through ppdev IOCTL
+ * PP[GS]ETPHASE, so do not change existing values. */
 enum ieee1284_phase {
        IEEE1284_PH_FWD_DATA,
        IEEE1284_PH_FWD_IDLE,
        IEEE1284_PH_TERMINATE,
        IEEE1284_PH_NEGOTIATION,
+       IEEE1284_PH_HBUSY_DNA,
        IEEE1284_PH_REV_IDLE,
        IEEE1284_PH_HBUSY_DAVAIL,
        IEEE1284_PH_REV_DATA,
index e2a089b051edddbc272b4673e18070fdb5f073b0..d27a78b71297058158af0760aa666cd60567480f 100644 (file)
 #define  PCI_CAP_ID_MSI                0x05    /* Message Signalled Interrupts */
 #define  PCI_CAP_ID_CHSWP      0x06    /* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX       0x07    /* PCI-X */
+#define  PCI_CAP_ID_HT_IRQCONF 0x08    /* HyperTransport IRQ Configuration */
 #define  PCI_CAP_ID_SHPC       0x0C    /* PCI Standard Hot-Plug Controller */
 #define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
 #define  PCI_CAP_ID_MSIX       0x11    /* MSI-X */
index fb8d2d24e4bb1d855b4d6017202c6dca2882dfa1..cb9039a21f2a7da99b05f9e8d00b930ab7108a6f 100644 (file)
@@ -19,7 +19,6 @@
 
 struct percpu_data {
        void *ptrs[NR_CPUS];
-       void *blkp;
 };
 
 /* 
@@ -33,14 +32,14 @@ struct percpu_data {
         (__typeof__(ptr))__p->ptrs[(cpu)];     \
 })
 
-extern void *__alloc_percpu(size_t size, size_t align);
+extern void *__alloc_percpu(size_t size);
 extern void free_percpu(const void *);
 
 #else /* CONFIG_SMP */
 
 #define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
 
-static inline void *__alloc_percpu(size_t size, size_t align)
+static inline void *__alloc_percpu(size_t size)
 {
        void *ret = kmalloc(size, GFP_KERNEL);
        if (ret)
@@ -55,7 +54,6 @@ static inline void free_percpu(const void *ptr)
 #endif /* CONFIG_SMP */
 
 /* Simple wrapper for the common case: zeros memory. */
-#define alloc_percpu(type) \
-       ((type *)(__alloc_percpu(sizeof(type), __alignof__(type))))
+#define alloc_percpu(type)     ((type *)(__alloc_percpu(sizeof(type))))
 
 #endif /* __LINUX_PERCPU_H */
index 373bd3b9b330f2db82c06d3ef59ec0f9e1829834..217d3daf73363e98cc5a9674470d080f41dcc16b 100644 (file)
@@ -140,7 +140,7 @@ extern int find_via_pmu(void);
 
 extern int pmu_request(struct adb_request *req,
                void (*done)(struct adb_request *), int nbytes, ...);
-
+extern int pmu_queue_request(struct adb_request *req);
 extern void pmu_poll(void);
 extern void pmu_poll_adb(void); /* For use by xmon */
 extern void pmu_wait_complete(struct adb_request *req);
@@ -160,12 +160,6 @@ extern void pmu_unlock(void);
 extern int pmu_present(void);
 extern int pmu_get_model(void);
 
-extern int pmu_i2c_combined_read(int bus, int addr, int subaddr,  u8* data, int len);
-extern int pmu_i2c_stdsub_write(int bus, int addr, int subaddr,  u8* data, int len);
-extern int pmu_i2c_simple_read(int bus, int addr,  u8* data, int len);
-extern int pmu_i2c_simple_write(int bus, int addr,  u8* data, int len);
-
-
 #ifdef CONFIG_PM
 /*
  * Stuff for putting the powerbook to sleep and waking it again.
index b2b3dba1298d1fef7f1b4e4ecfba22fe142c88d2..9d5cd106b344bc7a316bfb712cbc9509a8920075 100644 (file)
@@ -20,8 +20,6 @@
 #define PTRACE_DETACH          0x11
 
 #define PTRACE_SYSCALL           24
-#define PTRACE_SYSEMU            31
-#define PTRACE_SYSEMU_SINGLESTEP  32
 
 /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
 #define PTRACE_SETOPTIONS      0x4200
@@ -80,6 +78,8 @@
 
 
 extern long arch_ptrace(struct task_struct *child, long request, long addr, long data);
+extern struct task_struct *ptrace_get_task_struct(pid_t pid);
+extern int ptrace_traceme(void);
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
 extern int ptrace_attach(struct task_struct *tsk);
index 36e5d269612fec7ce193f2edee5fd816af353650..c57ff2fcb30a8d27990a2d4f5acc516714203b99 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef _LINUX_RADIX_TREE_H
 #define _LINUX_RADIX_TREE_H
 
+#include <linux/sched.h>
 #include <linux/preempt.h>
 #include <linux/types.h>
 
index a471f3bb713ee1045fb0cddb71d2dc9fcacb54ab..a1d26cb28925dea07283800ff4a3888f79face2b 100644 (file)
@@ -65,7 +65,7 @@ struct rcu_ctrlblk {
        long    cur;            /* Current batch number.                      */
        long    completed;      /* Number of the last completed batch         */
        int     next_pending;   /* Is the next batch already waiting?         */
-} ____cacheline_maxaligned_in_smp;
+} ____cacheline_internodealigned_in_smp;
 
 /* Is batch a before batch b ? */
 static inline int rcu_batch_before(long a, long b)
@@ -125,36 +125,7 @@ static inline void rcu_bh_qsctr_inc(int cpu)
        rdp->passed_quiesc = 1;
 }
 
-static inline int __rcu_pending(struct rcu_ctrlblk *rcp,
-                                               struct rcu_data *rdp)
-{
-       /* This cpu has pending rcu entries and the grace period
-        * for them has completed.
-        */
-       if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
-               return 1;
-
-       /* This cpu has no pending entries, but there are new entries */
-       if (!rdp->curlist && rdp->nxtlist)
-               return 1;
-
-       /* This cpu has finished callbacks to invoke */
-       if (rdp->donelist)
-               return 1;
-
-       /* The rcu core waits for a quiescent state from the cpu */
-       if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
-               return 1;
-
-       /* nothing to do */
-       return 0;
-}
-
-static inline int rcu_pending(int cpu)
-{
-       return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
-               __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
-}
+extern int rcu_pending(int cpu);
 
 /**
  * rcu_read_lock - mark the beginning of an RCU read-side critical section.
diff --git a/include/linux/rcuref.h b/include/linux/rcuref.h
deleted file mode 100644 (file)
index e1adbba..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * rcuref.h
- *
- * Reference counting for elements of lists/arrays protected by
- * RCU.
- *
- * 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.
- *
- * Copyright (C) IBM Corporation, 2005
- *
- * Author: Dipankar Sarma <dipankar@in.ibm.com>
- *        Ravikiran Thirumalai <kiran_th@gmail.com>
- *
- * See Documentation/RCU/rcuref.txt for detailed user guide.
- *
- */
-
-#ifndef _RCUREF_H_
-#define _RCUREF_H_
-
-#ifdef __KERNEL__
-
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <asm/atomic.h>
-
-/*
- * These APIs work on traditional atomic_t counters used in the
- * kernel for reference counting. Under special circumstances
- * where a lock-free get() operation races with a put() operation
- * these APIs can be used. See Documentation/RCU/rcuref.txt.
- */
-
-#ifdef __HAVE_ARCH_CMPXCHG
-
-/**
- * rcuref_inc - increment refcount for object.
- * @rcuref: reference counter in the object in question.
- *
- * This should be used only for objects where we use RCU and
- * use the rcuref_inc_lf() api to acquire a reference
- * in a lock-free reader-side critical section.
- */
-static inline void rcuref_inc(atomic_t *rcuref)
-{
-       atomic_inc(rcuref);
-}
-
-/**
- * rcuref_dec - decrement refcount for object.
- * @rcuref: reference counter in the object in question.
- *
- * This should be used only for objects where we use RCU and
- * use the rcuref_inc_lf() api to acquire a reference
- * in a lock-free reader-side critical section.
- */
-static inline void rcuref_dec(atomic_t *rcuref)
-{
-       atomic_dec(rcuref);
-}
-
-/**
- * rcuref_dec_and_test - decrement refcount for object and test
- * @rcuref: reference counter in the object.
- * @release: pointer to the function that will clean up the object
- *          when the last reference to the object is released.
- *          This pointer is required.
- *
- * Decrement the refcount, and if 0, return 1. Else return 0.
- *
- * This should be used only for objects where we use RCU and
- * use the rcuref_inc_lf() api to acquire a reference
- * in a lock-free reader-side critical section.
- */
-static inline int rcuref_dec_and_test(atomic_t *rcuref)
-{
-       return atomic_dec_and_test(rcuref);
-}
-
-/*
- * cmpxchg is needed on UP too, if deletions to the list/array can happen
- * in interrupt context.
- */
-
-/**
- * rcuref_inc_lf - Take reference to an object in a read-side
- * critical section protected by RCU.
- * @rcuref: reference counter in the object in question.
- *
- * Try and increment the refcount by 1.  The increment might fail if
- * the reference counter has been through a 1 to 0 transition and
- * is no longer part of the lock-free list.
- * Returns non-zero on successful increment and zero otherwise.
- */
-static inline int rcuref_inc_lf(atomic_t *rcuref)
-{
-       int c, old;
-       c = atomic_read(rcuref);
-       while (c && (old = cmpxchg(&rcuref->counter, c, c + 1)) != c)
-               c = old;
-       return c;
-}
-
-#else                          /* !__HAVE_ARCH_CMPXCHG */
-
-extern spinlock_t __rcuref_hash[];
-
-/*
- * Use a hash table of locks to protect the reference count
- * since cmpxchg is not available in this arch.
- */
-#ifdef CONFIG_SMP
-#define RCUREF_HASH_SIZE       4
-#define RCUREF_HASH(k) \
-       (&__rcuref_hash[(((unsigned long)k)>>8) & (RCUREF_HASH_SIZE-1)])
-#else
-#define        RCUREF_HASH_SIZE        1
-#define RCUREF_HASH(k)         &__rcuref_hash[0]
-#endif                         /* CONFIG_SMP */
-
-/**
- * rcuref_inc - increment refcount for object.
- * @rcuref: reference counter in the object in question.
- *
- * This should be used only for objects where we use RCU and
- * use the rcuref_inc_lf() api to acquire a reference in a lock-free
- * reader-side critical section.
- */
-static inline void rcuref_inc(atomic_t *rcuref)
-{
-       unsigned long flags;
-       spin_lock_irqsave(RCUREF_HASH(rcuref), flags);
-       rcuref->counter += 1;
-       spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
-}
-
-/**
- * rcuref_dec - decrement refcount for object.
- * @rcuref: reference counter in the object in question.
- *
- * This should be used only for objects where we use RCU and
- * use the rcuref_inc_lf() api to acquire a reference in a lock-free
- * reader-side critical section.
- */
-static inline void rcuref_dec(atomic_t *rcuref)
-{
-       unsigned long flags;
-       spin_lock_irqsave(RCUREF_HASH(rcuref), flags);
-       rcuref->counter -= 1;
-       spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
-}
-
-/**
- * rcuref_dec_and_test - decrement refcount for object and test
- * @rcuref: reference counter in the object.
- * @release: pointer to the function that will clean up the object
- *          when the last reference to the object is released.
- *          This pointer is required.
- *
- * Decrement the refcount, and if 0, return 1. Else return 0.
- *
- * This should be used only for objects where we use RCU and
- * use the rcuref_inc_lf() api to acquire a reference in a lock-free
- * reader-side critical section.
- */
-static inline int rcuref_dec_and_test(atomic_t *rcuref)
-{
-       unsigned long flags;
-       spin_lock_irqsave(RCUREF_HASH(rcuref), flags);
-       rcuref->counter--;
-       if (!rcuref->counter) {
-               spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
-               return 1;
-       } else {
-               spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
-               return 0;
-       }
-}
-
-/**
- * rcuref_inc_lf - Take reference to an object of a lock-free collection
- * by traversing a lock-free list/array.
- * @rcuref: reference counter in the object in question.
- *
- * Try and increment the refcount by 1.  The increment might fail if
- * the reference counter has been through a 1 to 0 transition and
- * object is no longer part of the lock-free list.
- * Returns non-zero on successful increment and zero otherwise.
- */
-static inline int rcuref_inc_lf(atomic_t *rcuref)
-{
-       int ret;
-       unsigned long flags;
-       spin_lock_irqsave(RCUREF_HASH(rcuref), flags);
-       if (rcuref->counter)
-               ret = rcuref->counter++;
-       else
-               ret = 0;
-       spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
-       return ret;
-}
-
-
-#endif /* !__HAVE_ARCH_CMPXCHG */
-
-#endif /* __KERNEL__ */
-#endif /* _RCUREF_H_ */
index fb7e8073732583515c2b41843e1c691848cbd98e..7342e66247fbe120b2a2f0fcb6ffd63ebb20d004 100644 (file)
@@ -64,20 +64,6 @@ struct rchan
        struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */
 };
 
-/*
- * Relayfs inode
- */
-struct relayfs_inode_info
-{
-       struct inode vfs_inode;
-       struct rchan_buf *buf;
-};
-
-static inline struct relayfs_inode_info *RELAYFS_I(struct inode *inode)
-{
-       return container_of(inode, struct relayfs_inode_info, vfs_inode);
-}
-
 /*
  * Relay channel client callbacks
  */
@@ -124,6 +110,46 @@ struct rchan_callbacks
         */
         void (*buf_unmapped)(struct rchan_buf *buf,
                             struct file *filp);
+       /*
+        * create_buf_file - create file to represent a relayfs channel buffer
+        * @filename: the name of the file to create
+        * @parent: the parent of the file to create
+        * @mode: the mode of the file to create
+        * @buf: the channel buffer
+        * @is_global: outparam - set non-zero if the buffer should be global
+        *
+        * Called during relay_open(), once for each per-cpu buffer,
+        * to allow the client to create a file to be used to
+        * represent the corresponding channel buffer.  If the file is
+        * created outside of relayfs, the parent must also exist in
+        * that filesystem.
+        *
+        * The callback should return the dentry of the file created
+        * to represent the relay buffer.
+        *
+        * Setting the is_global outparam to a non-zero value will
+        * cause relay_open() to create a single global buffer rather
+        * than the default set of per-cpu buffers.
+        *
+        * See Documentation/filesystems/relayfs.txt for more info.
+        */
+       struct dentry *(*create_buf_file)(const char *filename,
+                                         struct dentry *parent,
+                                         int mode,
+                                         struct rchan_buf *buf,
+                                         int *is_global);
+
+       /*
+        * remove_buf_file - remove file representing a relayfs channel buffer
+        * @dentry: the dentry of the file to remove
+        *
+        * Called during relay_close(), once for each per-cpu buffer,
+        * to allow the client to remove a file used to represent a
+        * channel buffer.
+        *
+        * The callback should return 0 if successful, negative if not.
+        */
+       int (*remove_buf_file)(struct dentry *dentry);
 };
 
 /*
@@ -148,6 +174,12 @@ extern size_t relay_switch_subbuf(struct rchan_buf *buf,
 extern struct dentry *relayfs_create_dir(const char *name,
                                         struct dentry *parent);
 extern int relayfs_remove_dir(struct dentry *dentry);
+extern struct dentry *relayfs_create_file(const char *name,
+                                         struct dentry *parent,
+                                         int mode,
+                                         struct file_operations *fops,
+                                         void *data);
+extern int relayfs_remove_file(struct dentry *dentry);
 
 /**
  *     relay_write - write data into the channel
@@ -247,10 +279,9 @@ static inline void subbuf_start_reserve(struct rchan_buf *buf,
 }
 
 /*
- * exported relayfs file operations, fs/relayfs/inode.c
+ * exported relay file operations, fs/relayfs/inode.c
  */
-
-extern struct file_operations relayfs_file_operations;
+extern struct file_operations relay_file_operations;
 
 #endif /* _LINUX_RELAYFS_FS_H */
 
index 3bd7cce19e2645cd32e240471230d84910c945a7..157d7e3236b59c7f114540d6ff32e37aa84b7141 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/device.h>
+#include <linux/string.h>
 #include <linux/rio.h>
 
 extern int __rio_local_read_config_32(struct rio_mport *port, u32 offset,
index e1aaf1fac8e0e7aadb5c4745462af1623a8d41fb..0b2ba67ff13c73e37ca0d54ba71f0bd3a0056b1e 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef _LINUX_RTC_H_
 #define _LINUX_RTC_H_
 
+#include <linux/interrupt.h>
+
 /*
  * The struct used to pass data via the following ioctl. Similar to the
  * struct tm in <time.h>, but it needs to be here so that the kernel 
@@ -102,6 +104,7 @@ int rtc_register(rtc_task_t *task);
 int rtc_unregister(rtc_task_t *task);
 int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
 void rtc_get_rtc_time(struct rtc_time *rtc_tm);
+irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 #endif /* __KERNEL__ */
 
index 7da33619d5d02c78a8f86be4c2e26ca55f3801c2..78eb92ae4d94b34240d457498ffb9c6dda6f34b6 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/percpu.h>
 #include <linux/topology.h>
 #include <linux/seccomp.h>
+#include <linux/rcupdate.h>
 
 #include <linux/auxvec.h>      /* For AT_VECTOR_SIZE */
 
@@ -350,8 +351,16 @@ struct sighand_struct {
        atomic_t                count;
        struct k_sigaction      action[_NSIG];
        spinlock_t              siglock;
+       struct rcu_head         rcu;
 };
 
+extern void sighand_free_cb(struct rcu_head *rhp);
+
+static inline void sighand_free(struct sighand_struct *sp)
+{
+       call_rcu(&sp->rcu, sighand_free_cb);
+}
+
 /*
  * NOTE! "signal_struct" does not have it's own
  * locking, because a shared signal_struct always
@@ -762,6 +771,7 @@ struct task_struct {
        unsigned keep_capabilities:1;
        struct user_struct *user;
 #ifdef CONFIG_KEYS
+       struct key *request_key_auth;   /* assumed request_key authority */
        struct key *thread_keyring;     /* keyring private to this thread */
        unsigned char jit_keyring;      /* default keyring to attach requested keys to */
 #endif
@@ -844,6 +854,7 @@ struct task_struct {
        int cpuset_mems_generation;
 #endif
        atomic_t fs_excl;       /* holding fs exclusive resources */
+       struct rcu_head rcu;
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
@@ -867,8 +878,14 @@ static inline int pid_alive(struct task_struct *p)
 extern void free_task(struct task_struct *tsk);
 extern void __put_task_struct(struct task_struct *tsk);
 #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0)
-#define put_task_struct(tsk) \
-do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
+
+extern void __put_task_struct_cb(struct rcu_head *rhp);
+
+static inline void put_task_struct(struct task_struct *t)
+{
+       if (atomic_dec_and_test(&t->usage))
+               call_rcu(&t->rcu, __put_task_struct_cb);
+}
 
 /*
  * Per process flags
@@ -895,6 +912,7 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
 #define PF_SYNCWRITE   0x00200000      /* I am doing a sync write */
 #define PF_BORROWED_MM 0x00400000      /* I am a kthread doing use_mm */
 #define PF_RANDOMIZE   0x00800000      /* randomize virtual address space */
+#define PF_SWAPWRITE   0x01000000      /* Allowed to write to swap */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
new file mode 100644 (file)
index 0000000..76850b7
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _SCREEN_INFO_H
+#define _SCREEN_INFO_H
+
+#include <linux/types.h>
+
+/*
+ * These are set up by the setup-routine at boot-time:
+ */
+
+struct screen_info {
+       u8  orig_x;             /* 0x00 */
+       u8  orig_y;             /* 0x01 */
+       u16 dontuse1;           /* 0x02 -- EXT_MEM_K sits here */
+       u16 orig_video_page;    /* 0x04 */
+       u8  orig_video_mode;    /* 0x06 */
+       u8  orig_video_cols;    /* 0x07 */
+       u16 unused2;            /* 0x08 */
+       u16 orig_video_ega_bx;  /* 0x0a */
+       u16 unused3;            /* 0x0c */
+       u8  orig_video_lines;   /* 0x0e */
+       u8  orig_video_isVGA;   /* 0x0f */
+       u16 orig_video_points;  /* 0x10 */
+
+       /* VESA graphic mode -- linear frame buffer */
+       u16 lfb_width;          /* 0x12 */
+       u16 lfb_height;         /* 0x14 */
+       u16 lfb_depth;          /* 0x16 */
+       u32 lfb_base;           /* 0x18 */
+       u32 lfb_size;           /* 0x1c */
+       u16 dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
+       u16 lfb_linelength;     /* 0x24 */
+       u8  red_size;           /* 0x26 */
+       u8  red_pos;            /* 0x27 */
+       u8  green_size;         /* 0x28 */
+       u8  green_pos;          /* 0x29 */
+       u8  blue_size;          /* 0x2a */
+       u8  blue_pos;           /* 0x2b */
+       u8  rsvd_size;          /* 0x2c */
+       u8  rsvd_pos;           /* 0x2d */
+       u16 vesapm_seg;         /* 0x2e */
+       u16 vesapm_off;         /* 0x30 */
+       u16 pages;              /* 0x32 */
+       u16 vesa_attributes;    /* 0x34 */
+       u32  capabilities;      /* 0x36 */
+                               /* 0x3a -- 0x3f reserved for future expansion */
+};
+
+extern struct screen_info screen_info;
+
+#define ORIG_X                 (screen_info.orig_x)
+#define ORIG_Y                 (screen_info.orig_y)
+#define ORIG_VIDEO_MODE                (screen_info.orig_video_mode)
+#define ORIG_VIDEO_COLS        (screen_info.orig_video_cols)
+#define ORIG_VIDEO_EGA_BX      (screen_info.orig_video_ega_bx)
+#define ORIG_VIDEO_LINES       (screen_info.orig_video_lines)
+#define ORIG_VIDEO_ISVGA       (screen_info.orig_video_isVGA)
+#define ORIG_VIDEO_POINTS       (screen_info.orig_video_points)
+
+#define VIDEO_TYPE_MDA         0x10    /* Monochrome Text Display      */
+#define VIDEO_TYPE_CGA         0x11    /* CGA Display                  */
+#define VIDEO_TYPE_EGAM                0x20    /* EGA/VGA in Monochrome Mode   */
+#define VIDEO_TYPE_EGAC                0x21    /* EGA in Color Mode            */
+#define VIDEO_TYPE_VGAC                0x22    /* VGA+ in Color Mode           */
+#define VIDEO_TYPE_VLFB                0x23    /* VESA VGA in graphic mode     */
+
+#define VIDEO_TYPE_PICA_S3     0x30    /* ACER PICA-61 local S3 video  */
+#define VIDEO_TYPE_MIPS_G364   0x31    /* MIPS Magnum 4000 G364 video  */
+#define VIDEO_TYPE_SGI          0x33    /* Various SGI graphics hardware */
+
+#define VIDEO_TYPE_TGAC                0x40    /* DEC TGA */
+
+#define VIDEO_TYPE_SUN          0x50    /* Sun frame buffer. */
+#define VIDEO_TYPE_SUNPCI       0x51    /* Sun PCI based frame buffer. */
+
+#define VIDEO_TYPE_PMAC                0x60    /* PowerMacintosh frame buffer. */
+
+#endif /* _SCREEN_INFO_H */
index 3b6afb8caa4234447f504d38ba1eeb19e9ebab00..564acd3a71c1a89b0dcc9175b8f3068cf9e086c7 100644 (file)
@@ -293,46 +293,46 @@ void sdla(void *cfg_info, char *dev, struct frad_conf *conf, int quiet);
 #define SDLA_S508_INTEN                        0x10
 
 struct sdla_cmd {
-   char  opp_flag              __attribute__((packed));
-   char  cmd                   __attribute__((packed));
-   short length                        __attribute__((packed));
-   char  retval                        __attribute__((packed));
-   short dlci                  __attribute__((packed));
-   char  flags                 __attribute__((packed));
-   short rxlost_int            __attribute__((packed));
-   long  rxlost_app            __attribute__((packed));
-   char  reserve[2]            __attribute__((packed));
-   char  data[SDLA_MAX_DATA]   __attribute__((packed));        /* transfer data buffer */
-};
+   char  opp_flag;
+   char  cmd;
+   short length;
+   char  retval;
+   short dlci;
+   char  flags;
+   short rxlost_int;
+   long  rxlost_app;
+   char  reserve[2];
+   char  data[SDLA_MAX_DATA];  /* transfer data buffer */
+} __attribute__((packed));
 
 struct intr_info {
-   char  flags         __attribute__((packed));
-   short txlen         __attribute__((packed));
-   char  irq           __attribute__((packed));
-   char  flags2                __attribute__((packed));
-   short timeout       __attribute__((packed));
-};
+   char  flags;
+   short txlen;
+   char  irq;
+   char  flags2;
+   short timeout;
+} __attribute__((packed));
 
 /* found in the 508's control window at RXBUF_INFO */
 struct buf_info {
-   unsigned short rse_num      __attribute__((packed));
-   unsigned long  rse_base     __attribute__((packed));
-   unsigned long  rse_next     __attribute__((packed));
-   unsigned long  buf_base     __attribute__((packed));
-   unsigned short reserved     __attribute__((packed));
-   unsigned long  buf_top      __attribute__((packed));
-};
+   unsigned short rse_num;
+   unsigned long  rse_base;
+   unsigned long  rse_next;
+   unsigned long  buf_base;
+   unsigned short reserved;
+   unsigned long  buf_top;
+} __attribute__((packed));
 
 /* structure pointed to by rse_base in RXBUF_INFO struct */
 struct buf_entry {
-   char  opp_flag      __attribute__((packed));
-   short length                __attribute__((packed));
-   short dlci          __attribute__((packed));
-   char  flags         __attribute__((packed));
-   short timestamp     __attribute__((packed));
-   short reserved[2]   __attribute__((packed));
-   long  buf_addr      __attribute__((packed));
-};
+   char  opp_flag;
+   short length;
+   short dlci;
+   char  flags;
+   short timestamp;
+   short reserved[2];
+   long  buf_addr;
+} __attribute__((packed));
 
 #endif
 
index dc89116bb1ca997bef56f6e938f4f6080ee4f878..cd2773b29a642bb53c73e7c0dfe798b662b6733c 100644 (file)
@@ -26,11 +26,7 @@ static inline int has_secure_computing(struct thread_info *ti)
 
 #else /* CONFIG_SECCOMP */
 
-#if (__GNUC__ > 2)
-  typedef struct { } seccomp_t;
-#else
-  typedef struct { int gcc_is_buggy; } seccomp_t;
-#endif
+typedef struct { } seccomp_t;
 
 #define secure_computing(x) do { } while (0)
 /* static inline to preserve typechecking */
index 5dd5f02c5c5fd6b1c3f192f13b6b28373763061f..b7d093520bb6c0011b385c4ab4faaddbd6c50e6e 100644 (file)
 #define SA_PROBE               SA_ONESHOT
 #define SA_SAMPLE_RANDOM       SA_RESTART
 #define SA_SHIRQ               0x04000000
+/*
+ * As above, these correspond to the IORESOURCE_IRQ_* defines in
+ * linux/ioport.h to select the interrupt line behaviour.  When
+ * requesting an interrupt without specifying a SA_TRIGGER, the
+ * setting should be assumed to be "as already configured", which
+ * may be as per machine or firmware initialisation.
+ */
+#define SA_TRIGGER_LOW         0x00000008
+#define SA_TRIGGER_HIGH                0x00000004
+#define SA_TRIGGER_FALLING     0x00000002
+#define SA_TRIGGER_RISING      0x00000001
+#define SA_TRIGGER_MASK        (SA_TRIGGER_HIGH|SA_TRIGGER_LOW|\
+                                SA_TRIGGER_RISING|SA_TRIGGER_FALLING)
 
 /*
  * Real Time signals may be queued.
@@ -81,6 +94,23 @@ static inline int sigfindinword(unsigned long word)
 
 #endif /* __HAVE_ARCH_SIG_BITOPS */
 
+static inline int sigisemptyset(sigset_t *set)
+{
+       extern void _NSIG_WORDS_is_unsupported_size(void);
+       switch (_NSIG_WORDS) {
+       case 4:
+               return (set->sig[3] | set->sig[2] |
+                       set->sig[1] | set->sig[0]) == 0;
+       case 2:
+               return (set->sig[1] | set->sig[0]) == 0;
+       case 1:
+               return set->sig[0] == 0;
+       default:
+               _NSIG_WORDS_is_unsupported_size();
+               return 0;
+       }
+}
+
 #define sigmask(sig)   (1UL << ((sig) - 1))
 
 #ifndef __HAVE_ARCH_SIG_SETOPS
index 483cfc47ec34203535f2fe0f0ed776c95da7c077..e5fd66c5650b53fd1354aab69591ede2d6ea8794 100644 (file)
@@ -251,7 +251,7 @@ struct sk_buff {
         * want to keep them across layers you have to do a skb_clone()
         * first. This is owned by whoever has the skb queued ATM.
         */
-       char                    cb[40];
+       char                    cb[48];
 
        unsigned int            len,
                                data_len,
index d1ea4051b99618b1f12a6a31291353cd9cf3ce69..1fb77a9cc148d2a61e3e2f1d1b0b469b01620703 100644 (file)
@@ -53,6 +53,8 @@ typedef struct kmem_cache kmem_cache_t;
 #define SLAB_CTOR_ATOMIC       0x002UL         /* tell constructor it can't sleep */
 #define        SLAB_CTOR_VERIFY        0x004UL         /* tell constructor it's a verify call */
 
+#ifndef CONFIG_SLOB
+
 /* prototypes */
 extern void __init kmem_cache_init(void);
 
@@ -134,6 +136,39 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
 extern int FASTCALL(kmem_cache_reap(int));
 extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr));
 
+#else /* CONFIG_SLOB */
+
+/* SLOB allocator routines */
+
+void kmem_cache_init(void);
+struct kmem_cache *kmem_find_general_cachep(size_t, gfp_t gfpflags);
+struct kmem_cache *kmem_cache_create(const char *c, size_t, size_t,
+       unsigned long,
+       void (*)(void *, struct kmem_cache *, unsigned long),
+       void (*)(void *, struct kmem_cache *, unsigned long));
+int kmem_cache_destroy(struct kmem_cache *c);
+void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags);
+void kmem_cache_free(struct kmem_cache *c, void *b);
+const char *kmem_cache_name(struct kmem_cache *);
+void *kmalloc(size_t size, gfp_t flags);
+void *kzalloc(size_t size, gfp_t flags);
+void kfree(const void *m);
+unsigned int ksize(const void *m);
+unsigned int kmem_cache_size(struct kmem_cache *c);
+
+static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
+{
+       return kzalloc(n * size, flags);
+}
+
+#define kmem_cache_shrink(d) (0)
+#define kmem_cache_reap(a)
+#define kmem_ptr_validate(a, b) (0)
+#define kmem_cache_alloc_node(c, f, n) kmem_cache_alloc(c, f)
+#define kmalloc_node(s, f, n) kmalloc(s, f)
+
+#endif /* CONFIG_SLOB */
+
 /* System wide caches */
 extern kmem_cache_t    *vm_area_cachep;
 extern kmem_cache_t    *names_cachep;
index def2d173a8db049db0b24c7ed6c2f1d26ee03038..04135b0e198e31bfca6c3d1bea508d9af638f4b4 100644 (file)
@@ -22,30 +22,16 @@ typedef struct {
 
 #else
 
-/*
- * All gcc 2.95 versions and early versions of 2.96 have a nasty bug
- * with empty initializers.
- */
-#if (__GNUC__ > 2)
 typedef struct { } raw_spinlock_t;
 
 #define __RAW_SPIN_LOCK_UNLOCKED { }
-#else
-typedef struct { int gcc_is_buggy; } raw_spinlock_t;
-#define __RAW_SPIN_LOCK_UNLOCKED (raw_spinlock_t) { 0 }
-#endif
 
 #endif
 
-#if (__GNUC__ > 2)
 typedef struct {
        /* no debug version on UP */
 } raw_rwlock_t;
 
 #define __RAW_RW_LOCK_UNLOCKED { }
-#else
-typedef struct { int gcc_is_buggy; } raw_rwlock_t;
-#define __RAW_RW_LOCK_UNLOCKED (raw_rwlock_t) { 0 }
-#endif
 
 #endif /* __LINUX_SPINLOCK_TYPES_UP_H */
index 556617bcf7accb79a763eda248e4075df6330e1a..389d1c382e208c2f05cabf86367624a9feb73b12 100644 (file)
@@ -175,6 +175,13 @@ extern int try_to_free_pages(struct zone **, gfp_t);
 extern int shrink_all_memory(int);
 extern int vm_swappiness;
 
+#ifdef CONFIG_MIGRATION
+extern int isolate_lru_page(struct page *p);
+extern int putback_lru_pages(struct list_head *l);
+extern int migrate_pages(struct list_head *l, struct list_head *t,
+               struct list_head *moved, struct list_head *failed);
+#endif
+
 #ifdef CONFIG_MMU
 /* linux/mm/shmem.c */
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
@@ -192,7 +199,7 @@ extern int rw_swap_page_sync(int, swp_entry_t, struct page *);
 extern struct address_space swapper_space;
 #define total_swapcache_pages  swapper_space.nrpages
 extern void show_swap_cache_info(void);
-extern int add_to_swap(struct page *);
+extern int add_to_swap(struct page *, gfp_t);
 extern void __delete_from_swap_cache(struct page *);
 extern void delete_from_swap_cache(struct page *);
 extern int move_to_swap_cache(struct page *, swp_entry_t);
index 763bd290f28da788b3d510eeda0057814d70e076..1b7cd8d1a71b0e107651a1dce30ec303d3b0ae7b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * $Id: synclink.h,v 3.6 2002/02/20 21:58:20 paulkf Exp $
+ * $Id: synclink.h,v 3.10 2005/11/08 19:50:54 paulkf Exp $
  *
  * Copyright (C) 1998-2000 by Microgate Corporation
  *
 #define MGSL_BUS_TYPE_EISA     2
 #define MGSL_BUS_TYPE_PCI      5
 
+#define MGSL_INTERFACE_MASK     0xf
 #define MGSL_INTERFACE_DISABLE  0
 #define MGSL_INTERFACE_RS232    1
 #define MGSL_INTERFACE_V35      2
 #define MGSL_INTERFACE_RS422    3
+#define MGSL_INTERFACE_RTS_EN   0x10
+#define MGSL_INTERFACE_LL       0x20
+#define MGSL_INTERFACE_RL       0x40
 
 typedef struct _MGSL_PARAMS
 {
@@ -163,6 +167,9 @@ typedef struct _MGSL_PARAMS
 #define SYNCLINK_DEVICE_ID 0x0010
 #define MGSCC_DEVICE_ID 0x0020
 #define SYNCLINK_SCA_DEVICE_ID 0x0030
+#define SYNCLINK_GT_DEVICE_ID 0x0070
+#define SYNCLINK_GT4_DEVICE_ID 0x0080
+#define SYNCLINK_AC_DEVICE_ID  0x0090
 #define MGSL_MAX_SERIAL_NUMBER 30
 
 /*
index c7007b1db91d6beece5fd0143c0f519304e629c4..3eed47347013357c01f852222a07c5746fbdec5f 100644 (file)
@@ -511,5 +511,12 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio);
 asmlinkage long sys_ioprio_get(int which, int who);
 asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask,
                                        unsigned long maxnode);
+asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
+                       const unsigned long __user *from, const unsigned long __user *to);
+
+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);
 
 #endif
index a9b80fc7f0f38d31f19e0573797a91a6735a935c..7f472127b7b59d2d3a85e99b15ffea69f670e071 100644 (file)
@@ -180,6 +180,8 @@ enum
        VM_VFS_CACHE_PRESSURE=26, /* dcache/icache reclaim pressure */
        VM_LEGACY_VA_LAYOUT=27, /* legacy/compatibility virtual address space layout */
        VM_SWAP_TOKEN_TIMEOUT=28, /* default time for token time out */
+       VM_DROP_PAGECACHE=29,   /* int: nuke lots of pagecache */
+       VM_PERCPU_PAGELIST_FRACTION=30,/* int: fraction of pages in each percpu_pagelist */
 };
 
 
index 1267f88ece6eae9616453c1128859cbf49754000..57449704a47be99355e1b467692ee7efe7cf2228 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/workqueue.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_ldisc.h>
+#include <linux/screen_info.h>
 
 #include <asm/system.h>
 
 #define NR_UNIX98_PTY_MAX      (1 << MINORBITS) /* Absolute limit */
 #define NR_LDISCS              16
 
-/*
- * These are set up by the setup-routine at boot-time:
- */
-
-struct screen_info {
-       u8  orig_x;             /* 0x00 */
-       u8  orig_y;             /* 0x01 */
-       u16 dontuse1;           /* 0x02 -- EXT_MEM_K sits here */
-       u16 orig_video_page;    /* 0x04 */
-       u8  orig_video_mode;    /* 0x06 */
-       u8  orig_video_cols;    /* 0x07 */
-       u16 unused2;            /* 0x08 */
-       u16 orig_video_ega_bx;  /* 0x0a */
-       u16 unused3;            /* 0x0c */
-       u8  orig_video_lines;   /* 0x0e */
-       u8  orig_video_isVGA;   /* 0x0f */
-       u16 orig_video_points;  /* 0x10 */
-
-       /* VESA graphic mode -- linear frame buffer */
-       u16 lfb_width;          /* 0x12 */
-       u16 lfb_height;         /* 0x14 */
-       u16 lfb_depth;          /* 0x16 */
-       u32 lfb_base;           /* 0x18 */
-       u32 lfb_size;           /* 0x1c */
-       u16 dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
-       u16 lfb_linelength;     /* 0x24 */
-       u8  red_size;           /* 0x26 */
-       u8  red_pos;            /* 0x27 */
-       u8  green_size;         /* 0x28 */
-       u8  green_pos;          /* 0x29 */
-       u8  blue_size;          /* 0x2a */
-       u8  blue_pos;           /* 0x2b */
-       u8  rsvd_size;          /* 0x2c */
-       u8  rsvd_pos;           /* 0x2d */
-       u16 vesapm_seg;         /* 0x2e */
-       u16 vesapm_off;         /* 0x30 */
-       u16 pages;              /* 0x32 */
-       u16 vesa_attributes;    /* 0x34 */
-       u32  capabilities;      /* 0x36 */
-                               /* 0x3a -- 0x3f reserved for future expansion */
-};
-
-extern struct screen_info screen_info;
-
-#define ORIG_X                 (screen_info.orig_x)
-#define ORIG_Y                 (screen_info.orig_y)
-#define ORIG_VIDEO_MODE                (screen_info.orig_video_mode)
-#define ORIG_VIDEO_COLS        (screen_info.orig_video_cols)
-#define ORIG_VIDEO_EGA_BX      (screen_info.orig_video_ega_bx)
-#define ORIG_VIDEO_LINES       (screen_info.orig_video_lines)
-#define ORIG_VIDEO_ISVGA       (screen_info.orig_video_isVGA)
-#define ORIG_VIDEO_POINTS       (screen_info.orig_video_points)
-
-#define VIDEO_TYPE_MDA         0x10    /* Monochrome Text Display      */
-#define VIDEO_TYPE_CGA         0x11    /* CGA Display                  */
-#define VIDEO_TYPE_EGAM                0x20    /* EGA/VGA in Monochrome Mode   */
-#define VIDEO_TYPE_EGAC                0x21    /* EGA in Color Mode            */
-#define VIDEO_TYPE_VGAC                0x22    /* VGA+ in Color Mode           */
-#define VIDEO_TYPE_VLFB                0x23    /* VESA VGA in graphic mode     */
-
-#define VIDEO_TYPE_PICA_S3     0x30    /* ACER PICA-61 local S3 video  */
-#define VIDEO_TYPE_MIPS_G364   0x31    /* MIPS Magnum 4000 G364 video  */
-#define VIDEO_TYPE_SGI          0x33    /* Various SGI graphics hardware */
-
-#define VIDEO_TYPE_TGAC                0x40    /* DEC TGA */
-
-#define VIDEO_TYPE_SUN          0x50    /* Sun frame buffer. */
-#define VIDEO_TYPE_SUNPCI       0x51    /* Sun PCI based frame buffer. */
-
-#define VIDEO_TYPE_PMAC                0x60    /* PowerMacintosh frame buffer. */
-
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
  * a c_cc[] character, but indicates that a particular special character
index 0e9e48b83e3b72dff430fcb3550e9f73e8833767..121e26da2c1869b6447423649d38af8591389060 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _LINUX_VIDEO_DECODER_H
 #define _LINUX_VIDEO_DECODER_H
 
+#define HAVE_VIDEO_DECODER 1
+
 struct video_decoder_capability { /* this name is too long */
        __u32   flags;
 #define        VIDEO_DECODER_PAL       1       /* can decode PAL signal */
index 1cded681eb6d2a1041270441f99dd4473e7c6c96..ce40675324bd5edb738c339bc56f61b01f1212bf 100644 (file)
@@ -642,6 +642,12 @@ typedef __u64 v4l2_std_id;
 #define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
 #define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
 
+/* some merged standards */
+#define V4L2_STD_MN    (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
+#define V4L2_STD_B     (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
+#define V4L2_STD_GH    (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
+#define V4L2_STD_DK    (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
+
 /* some common needed stuff */
 #define V4L2_STD_PAL_BG                (V4L2_STD_PAL_B         |\
                                 V4L2_STD_PAL_B1        |\
@@ -662,7 +668,8 @@ typedef __u64 v4l2_std_id;
                                 V4L2_STD_SECAM_G       |\
                                 V4L2_STD_SECAM_H       |\
                                 V4L2_STD_SECAM_DK      |\
-                                V4L2_STD_SECAM_L)
+                                V4L2_STD_SECAM_L       |\
+                                V4L2_STD_SECAM_LC)
 
 #define V4L2_STD_525_60                (V4L2_STD_PAL_M         |\
                                 V4L2_STD_PAL_60        |\
@@ -888,7 +895,6 @@ struct v4l2_audio
 
 /*  Flags for the 'mode' field */
 #define V4L2_AUDMODE_AVL               0x00001
-#define V4L2_AUDMODE_32BITS            0x00002
 
 struct v4l2_audioout
 {
@@ -1110,7 +1116,6 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
 /* names for fancy debug output */
 extern char *v4l2_field_names[];
 extern char *v4l2_type_names[];
-extern char *v4l2_ioctl_names[];
 
 /*  Compatibility layer interface  --  v4l1-compat module */
 typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
@@ -1118,6 +1123,11 @@ typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
 int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
                               int cmd, void *arg, v4l2_kioctl driver_ioctl);
 
+/* 32 Bits compatibility layer for 64 bits processors */
+extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
+                               unsigned long arg);
+
+
 #endif /* __KERNEL__ */
 #endif /* __LINUX_VIDEODEV2_H */
 
index 61bd0fd352403525d9914b736ccddf7c546166bd..51ab3c933acd0d5e68b422039e0a0960d26c5bb5 100644 (file)
@@ -434,22 +434,22 @@ typedef struct wf_multisample {
 } wavefront_multisample;
 
 typedef struct wf_alias {
-    INT16 OriginalSample __attribute__ ((packed));
-
-    struct wf_sample_offset sampleStartOffset __attribute__ ((packed));
-    struct wf_sample_offset loopStartOffset __attribute__ ((packed));
-    struct wf_sample_offset sampleEndOffset __attribute__ ((packed));
-    struct wf_sample_offset loopEndOffset __attribute__ ((packed));
-
-    INT16  FrequencyBias __attribute__ ((packed));
-
-    UCHAR8 SampleResolution:2  __attribute__ ((packed));
-    UCHAR8 Unused1:1  __attribute__ ((packed));
-    UCHAR8 Loop:1 __attribute__ ((packed));
-    UCHAR8 Bidirectional:1  __attribute__ ((packed));
-    UCHAR8 Unused2:1 __attribute__ ((packed));
-    UCHAR8 Reverse:1 __attribute__ ((packed));
-    UCHAR8 Unused3:1 __attribute__ ((packed)); 
+    INT16 OriginalSample;
+
+    struct wf_sample_offset sampleStartOffset;
+    struct wf_sample_offset loopStartOffset;
+    struct wf_sample_offset sampleEndOffset;
+    struct wf_sample_offset loopEndOffset;
+
+    INT16  FrequencyBias;
+
+    UCHAR8 SampleResolution:2;
+    UCHAR8 Unused1:1;
+    UCHAR8 Loop:1;
+    UCHAR8 Bidirectional:1;
+    UCHAR8 Unused2:1;
+    UCHAR8 Reverse:1;
+    UCHAR8 Unused3:1;
     
     /* This structure is meant to be padded only to 16 bits on their
        original. Of course, whoever wrote their documentation didn't
@@ -460,8 +460,8 @@ typedef struct wf_alias {
        standard 16->32 bit issues.
     */
 
-    UCHAR8 sixteen_bit_padding __attribute__ ((packed));
-} wavefront_alias;
+    UCHAR8 sixteen_bit_padding;
+} __attribute__((packed)) wavefront_alias;
 
 typedef struct wf_drum {
     UCHAR8 PatchNumber;
index ac39d04d027cd6affbe914b914eed138fa1dab89..86b1113002319b5b9db5f765426d3ef2a35c687d 100644 (file)
@@ -65,6 +65,7 @@ extern int FASTCALL(schedule_work(struct work_struct *work));
 extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay));
 
 extern int schedule_delayed_work_on(int cpu, struct work_struct *work, unsigned long delay);
+extern int schedule_on_each_cpu(void (*func)(void *info), void *info);
 extern void flush_scheduled_work(void);
 extern int current_is_keventd(void);
 extern int keventd_up(void);
index b096159086e8c772ab4ef8fc5931ecb35a137021..beaef5c7a0eacaadfb0d2f590dbf75c498f81eb0 100644 (file)
@@ -103,7 +103,9 @@ void balance_dirty_pages_ratelimited(struct address_space *mapping);
 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
 int sync_page_range(struct inode *inode, struct address_space *mapping,
-                       loff_t pos, size_t count);
+                       loff_t pos, loff_t count);
+int sync_page_range_nolock(struct inode *inode, struct address_space *mapping,
+                          loff_t pos, loff_t count);
 
 /* pdflush.c */
 extern int nr_pdflush_threads; /* Global so it can be exported to sysctl
index b7d4b0930408c3e366e28de0a196387bd03a743d..295d256ee811c63f5b533906851926d63a2ab1e8 100644 (file)
@@ -23,11 +23,6 @@ enum audiochip {
 
 /* ---------------------------------------------------------------------- */
 
-/* v4l device was opened in Radio mode */
-#define AUDC_SET_RADIO        _IO('m',2)
-/* select from TV,radio,extern,MUTE */
-#define AUDC_SET_INPUT        _IOW('m',17,int)
-
 /* audio inputs */
 #define AUDIO_TUNER        0x00
 #define AUDIO_RADIO        0x01
@@ -40,15 +35,4 @@ enum audiochip {
 #define AUDIO_MUTE         0x80
 #define AUDIO_UNMUTE       0x81
 
-/* all the stuff below is obsolete and just here for reference.  I'll
- * remove it once the driver is tested and works fine.
- *
- * Instead creating alot of tiny API's for all kinds of different
- * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not
- * yet...).  It is a bit less flexible, but most/all used i2c chips
- * make sense in v4l context only.  So I think that's acceptable...
- */
-
-/* misc stuff to pass around config info to i2c chips */
-#define AUDC_CONFIG_PINNACLE  _IOW('m',32,int)
 #endif /* AUDIOCHIP_H */
index 16af9299315f3da06ba07a722fb9bdaa7627e520..e5e749e984ee7baf4864ac0ceea926130ec72c75 100644 (file)
@@ -178,6 +178,8 @@ struct saa7146_ext_vv
 
        struct saa7146_extension_ioctls *ioctls;
        int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg);
+
+       struct file_operations vbi_fops;
 };
 
 struct saa7146_use_ops  {
index b37cde6066929ea5481857462c2a919831800148..7674b121ce8bb4c4005f601ea867d4584b0f24c5 100644 (file)
@@ -82,9 +82,9 @@
 #define TUNER_PHILIPS_FM1236_MK3       43
 
 #define TUNER_PHILIPS_4IN1             44      /* ATI TV Wonder Pro - Conexant */
-/* Microtune mergeged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */
+/* Microtune merged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */
 #define TUNER_MICROTUNE_4049FM5        45
-#define TUNER_MICROTUNE_4042_FI5       46
+#define TUNER_PANASONIC_VP27           46
 #define TUNER_LG_NTSC_TAPE             47
 
 #define TUNER_TNF_8831BGFF             48
 #define TUNER_YMEC_TVF_8531MF          58
 #define TUNER_YMEC_TVF_5533MF          59      /* Pixelview Pro Ultra NTSC */
 
-#define TUNER_THOMSON_DTT7611          60      /* DViCO FusionHDTV 3 Gold-T */
+#define TUNER_THOMSON_DTT761X          60      /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
 #define TUNER_TENA_9533_DI             61
 #define TUNER_TEA5767                  62      /* Only FM Radio Tuner */
 #define TUNER_PHILIPS_FMD1216ME_MK3    63
 #define TUNER_PHILIPS_TUV1236D         68      /* ATI HDTV Wonder */
 #define TUNER_TNF_5335MF                69     /* Sabrent Bt848   */
 
-#define NOTUNER 0
-#define PAL     1      /* PAL_BG */
-#define PAL_I   2
-#define NTSC    3
-#define SECAM   4
-#define ATSC    5
-#define RADIO   6
-
-#define NoTuner 0
-#define Philips 1
-#define TEMIC   2
-#define Sony    3
-#define Alps    4
-#define LGINNOTEK 5
-#define SHARP   6
-#define Samsung 7
-#define Microtune 8
-#define HITACHI 9
-#define Panasonic 10
-#define TCL     11
-#define THOMSON 12
-
-#define TUNER_SET_TYPE_ADDR          _IOW('T',3,int)
-#define TUNER_SET_STANDBY            _IOW('T',4,int)
-#define TDA9887_SET_CONFIG           _IOW('t',5,int)
-
 /* tv card specific */
-# define TDA9887_PRESENT             (1<<0)
-# define TDA9887_PORT1_INACTIVE      (1<<1)
-# define TDA9887_PORT2_INACTIVE      (1<<2)
-# define TDA9887_QSS                 (1<<3)
-# define TDA9887_INTERCARRIER        (1<<4)
-# define TDA9887_PORT1_ACTIVE        (1<<5)
-# define TDA9887_PORT2_ACTIVE        (1<<6)
-# define TDA9887_INTERCARRIER_NTSC   (1<<7)
+#define TDA9887_PRESENT                (1<<0)
+#define TDA9887_PORT1_INACTIVE                 (1<<1)
+#define TDA9887_PORT2_INACTIVE                 (1<<2)
+#define TDA9887_QSS                    (1<<3)
+#define TDA9887_INTERCARRIER           (1<<4)
+#define TDA9887_PORT1_ACTIVE           (1<<5)
+#define TDA9887_PORT2_ACTIVE           (1<<6)
+#define TDA9887_INTERCARRIER_NTSC      (1<<7)
+/* Tuner takeover point adjustment, in dB, -16 <= top <= 15 */
+#define TDA9887_TOP_MASK               (0x3f << 8)
+#define TDA9887_TOP_SET                (1 << 13)
+#define TDA9887_TOP(top)               (TDA9887_TOP_SET | (((16 + (top)) & 0x1f) << 8))
+
 /* config options */
-# define TDA9887_DEEMPHASIS_MASK     (3<<16)
-# define TDA9887_DEEMPHASIS_NONE     (1<<16)
-# define TDA9887_DEEMPHASIS_50       (2<<16)
-# define TDA9887_DEEMPHASIS_75       (3<<16)
-# define TDA9887_AUTOMUTE            (1<<18)
+#define TDA9887_DEEMPHASIS_MASK        (3<<16)
+#define TDA9887_DEEMPHASIS_NONE        (1<<16)
+#define TDA9887_DEEMPHASIS_50          (2<<16)
+#define TDA9887_DEEMPHASIS_75          (3<<16)
+#define TDA9887_AUTOMUTE               (1<<18)
 
 #ifdef __KERNEL__
 
@@ -167,10 +146,26 @@ enum tuner_mode {
        T_STANDBY       = 1 << 31
 };
 
+/* Older boards only had a single tuner device. Nowadays multiple tuner
+   devices may be present on a single board. Using TUNER_SET_TYPE_ADDR
+   to pass the tuner_setup structure it is possible to setup each tuner
+   device in turn.
+
+   Since multiple devices may be present it is no longer sufficient to
+   send a command to a single i2c device. Instead you should broadcast
+   the command to all i2c devices.
+
+   By setting the mode_mask correctly you can select which commands are
+   accepted by a specific tuner device. For example, set mode_mask to
+   T_RADIO if the device is a radio-only tuner. That specific tuner will
+   only accept commands when the tuner is in radio mode and ignore them
+   when the tuner is set to TV mode.
+ */
+
 struct tuner_setup {
-       unsigned short  addr;
-       unsigned int    type;
-       unsigned int    mode_mask;
+       unsigned short  addr;   /* I2C address */
+       unsigned int    type;   /* Tuner type */
+       unsigned int    mode_mask;  /* Allowed tuner modes */
 };
 
 struct tuner {
@@ -207,7 +202,6 @@ struct tuner {
        void (*standby)(struct i2c_client *c);
 };
 
-extern unsigned int tuner_debug;
 extern unsigned const int tuner_count;
 
 extern int microtune_init(struct i2c_client *c);
@@ -219,15 +213,15 @@ extern int tea5767_autodetection(struct i2c_client *c);
 
 #define tuner_warn(fmt, arg...) do {\
        printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+                       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, \
-                       t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 #define tuner_dbg(fmt, arg...) do {\
-       if (tuner_debug) \
-               printk(KERN_DEBUG "%s %d-%04x: " fmt, \
-                       t->i2c.driver->driver.name, \
-                       t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+       extern int debug; \
+       if (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__ */
 
index d3fd48157eb8bb87205e41fd82abdb9d8f89afd9..3cc3132f391ec967839f39ff8423f1d8502b2b6b 100644 (file)
 #ifndef V4L2_COMMON_H_
 #define V4L2_COMMON_H_
 
-/* VIDIOC_INT_AUDIO_CLOCK_FREQ */
-enum v4l2_audio_clock_freq {
-       V4L2_AUDCLK_32_KHZ  = 32000,
-       V4L2_AUDCLK_441_KHZ = 44100,
-       V4L2_AUDCLK_48_KHZ  = 48000,
-};
+/* v4l debugging and diagnostics */
+
+/* Common printk constucts for v4l-i2c drivers. These macros create a unique
+   prefix consisting of the driver name, the adapter number and the i2c
+   address. */
+#define v4l_printk(level, name, adapter, addr, fmt, arg...) \
+       printk(level "%s %d-%04x: " fmt, name, i2c_adapter_id(adapter), addr , ## arg)
+
+#define v4l_client_printk(level, client, fmt, arg...)                      \
+       v4l_printk(level, (client)->driver->driver.name, (client)->adapter, \
+                  (client)->addr, fmt , ## arg)
+
+#define v4l_err(client, fmt, arg...) \
+       v4l_client_printk(KERN_ERR, client, fmt , ## arg)
+
+#define v4l_warn(client, fmt, arg...) \
+       v4l_client_printk(KERN_WARNING, client, fmt , ## arg)
+
+#define v4l_info(client, fmt, arg...) \
+       v4l_client_printk(KERN_INFO, client, fmt , ## arg)
+
+/* These three macros assume that the debug level is set with a module
+   parameter called 'debug'. */
+#define v4l_dbg(level, client, fmt, arg...)                                 \
+       do {                                                                 \
+               extern int debug;                                            \
+               if (debug >= (level))                                        \
+                       v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \
+       } while (0)
+
+/* Prints the ioctl in a human-readable format */
+extern void v4l_printk_ioctl(unsigned int cmd);
+
+/* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */
+#define v4l_print_ioctl(name, cmd)              \
+       do {                                     \
+               printk(KERN_DEBUG "%s: ", name); \
+               v4l_printk_ioctl(cmd);           \
+       } while (0)
+
+/* Use this macro in I2C drivers where 'client' is the struct i2c_client
+   pointer */
+#define v4l_i2c_print_ioctl(client, cmd)                  \
+       do {                                               \
+               v4l_client_printk(KERN_DEBUG, client, ""); \
+               v4l_printk_ioctl(cmd);                     \
+       } while (0)
+
+/* ------------------------------------------------------------------------- */
+
+/* Internal ioctls */
 
 /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
 struct v4l2_register {
@@ -70,6 +115,20 @@ enum v4l2_chip_ident {
        V4L2_IDENT_CX25843 = 243,
 };
 
+/* audio ioctls */
+/* v4l device was opened in Radio mode */
+#define AUDC_SET_RADIO        _IO('d',88)
+/* select from TV,radio,extern,MUTE */
+#define AUDC_SET_INPUT        _IOW('d',89,int)
+
+/* tuner ioctls */
+/* Sets tuner type and its I2C addr */
+#define TUNER_SET_TYPE_ADDR          _IOW('d',90,int)
+/* Puts tuner on powersaving state, disabling it, except for i2c */
+#define TUNER_SET_STANDBY            _IOW('d',91,int)
+/* Sets tda9887 specific stuff, like port1, port2 and qss */
+#define TDA9887_SET_CONFIG           _IOW('d',92,int)
+
 /* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
 #define        VIDIOC_INT_S_REGISTER           _IOR ('d', 100, struct v4l2_register)
 #define        VIDIOC_INT_G_REGISTER           _IOWR('d', 101, struct v4l2_register)
@@ -77,10 +136,12 @@ enum v4l2_chip_ident {
 /* Reset the I2C chip */
 #define VIDIOC_INT_RESET               _IO  ('d', 102)
 
-/* Set the frequency of the audio clock output.
+/* Set the frequency (in Hz) of the audio clock output.
    Used to slave an audio processor to the video decoder, ensuring that audio
-   and video remain synchronized. */
-#define VIDIOC_INT_AUDIO_CLOCK_FREQ    _IOR ('d', 103, enum v4l2_audio_clock_freq)
+   and video remain synchronized.
+   Usual values for the frequency are 48000, 44100 or 32000 Hz.
+   If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_AUDIO_CLOCK_FREQ    _IOW ('d', 103, u32)
 
 /* Video decoders that support sliced VBI need to implement this ioctl.
    Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI
@@ -107,4 +168,10 @@ enum v4l2_chip_ident {
    be made. */
 #define VIDIOC_INT_G_CHIP_IDENT                _IOR ('d', 107, enum v4l2_chip_ident *)
 
+/* Sets I2S speed in bps. This is used to provide a standard way to select I2S
+   clock used by driving digital audio streams at some board designs.
+   Usual values for the frequency are 1024000 and 2048000.
+   If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_I2S_CLOCK_FREQ      _IOW ('d', 108, u32)
+
 #endif /* V4L2_COMMON_H_ */
index 86e8e86e624a3fc735a5955c8357fc6f4f4eea03..5a86e78081bf0d01685bc64ba58d559ce1442240 100644 (file)
@@ -88,8 +88,8 @@ struct dn_dev {
        struct net_device *dev;
        struct dn_dev_parms parms;
        char use_long;
-        struct timer_list timer;
-        unsigned long t3;
+       struct timer_list timer;
+       unsigned long t3;
        struct neigh_parms *neigh_parms;
        unsigned char addr[ETH_ALEN];
        struct neighbour *router; /* Default router on circuit */
@@ -99,57 +99,57 @@ struct dn_dev {
 
 struct dn_short_packet
 {
-       unsigned char   msgflg          __attribute__((packed));
-        unsigned short  dstnode         __attribute__((packed));
-        unsigned short  srcnode         __attribute__((packed));
-        unsigned char   forward         __attribute__((packed));
-};
+       unsigned char   msgflg;
+       unsigned short  dstnode;
+       unsigned short  srcnode;
+       unsigned char   forward;
+} __attribute__((packed));
 
 struct dn_long_packet
 {
-       unsigned char   msgflg          __attribute__((packed));
-        unsigned char   d_area          __attribute__((packed));
-        unsigned char   d_subarea       __attribute__((packed));
-        unsigned char   d_id[6]         __attribute__((packed));
-        unsigned char   s_area          __attribute__((packed));
-        unsigned char   s_subarea       __attribute__((packed));
-        unsigned char   s_id[6]         __attribute__((packed));
-        unsigned char   nl2             __attribute__((packed));
-        unsigned char   visit_ct        __attribute__((packed));
-        unsigned char   s_class         __attribute__((packed));
-        unsigned char   pt              __attribute__((packed));
-};
+       unsigned char   msgflg;
+       unsigned char   d_area;
+       unsigned char   d_subarea;
+       unsigned char   d_id[6];
+       unsigned char   s_area;
+       unsigned char   s_subarea;
+       unsigned char   s_id[6];
+       unsigned char   nl2;
+       unsigned char   visit_ct;
+       unsigned char   s_class;
+       unsigned char   pt;
+} __attribute__((packed));
 
 /*------------------------- DRP - Routing messages ---------------------*/
 
 struct endnode_hello_message
 {
-       unsigned char   msgflg          __attribute__((packed));
-        unsigned char   tiver[3]        __attribute__((packed));
-        unsigned char   id[6]           __attribute__((packed));
-        unsigned char   iinfo           __attribute__((packed));
-        unsigned short  blksize         __attribute__((packed));
-        unsigned char   area            __attribute__((packed));
-        unsigned char   seed[8]         __attribute__((packed));
-        unsigned char   neighbor[6]     __attribute__((packed));
-        unsigned short  timer           __attribute__((packed));
-        unsigned char   mpd             __attribute__((packed));
-        unsigned char   datalen         __attribute__((packed));
-        unsigned char   data[2]         __attribute__((packed));
-};
+       unsigned char   msgflg;
+       unsigned char   tiver[3];
+       unsigned char   id[6];
+       unsigned char   iinfo;
+       unsigned short  blksize;
+       unsigned char   area;
+       unsigned char   seed[8];
+       unsigned char   neighbor[6];
+       unsigned short  timer;
+       unsigned char   mpd;
+       unsigned char   datalen;
+       unsigned char   data[2];
+} __attribute__((packed));
 
 struct rtnode_hello_message
 {
-       unsigned char   msgflg          __attribute__((packed));
-        unsigned char   tiver[3]        __attribute__((packed));
-        unsigned char   id[6]           __attribute__((packed));
-        unsigned char   iinfo           __attribute__((packed));
-        unsigned short  blksize         __attribute__((packed));
-        unsigned char   priority        __attribute__((packed));
-        unsigned char   area            __attribute__((packed));
-        unsigned short  timer           __attribute__((packed));
-        unsigned char   mpd             __attribute__((packed));
-};
+       unsigned char   msgflg;
+       unsigned char   tiver[3];
+       unsigned char   id[6];
+       unsigned char   iinfo;
+       unsigned short  blksize;
+       unsigned char   priority;
+       unsigned char   area;
+       unsigned short  timer;
+       unsigned char   mpd;
+} __attribute__((packed));
 
 
 extern void dn_dev_init(void);
index 1ba03be0af3ac68a8bda1feb451b0da489576850..e6182b86262b837d637ea3d3eebc2fccf44a2a99 100644 (file)
@@ -72,78 +72,78 @@ extern struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int nobl
 
 struct nsp_data_seg_msg
 {
-       unsigned char   msgflg          __attribute__((packed));
-       unsigned short  dstaddr         __attribute__((packed));
-       unsigned short  srcaddr         __attribute__((packed));
-};
+       unsigned char   msgflg;
+       unsigned short  dstaddr;
+       unsigned short  srcaddr;
+} __attribute__((packed));
 
 struct nsp_data_opt_msg
 {
-       unsigned short  acknum          __attribute__((packed));
-       unsigned short  segnum          __attribute__((packed));
-       unsigned short  lsflgs          __attribute__((packed));
-};
+       unsigned short  acknum;
+       unsigned short  segnum;
+       unsigned short  lsflgs;
+} __attribute__((packed));
 
 struct nsp_data_opt_msg1
 {
-       unsigned short  acknum          __attribute__((packed));
-       unsigned short  segnum          __attribute__((packed));
-};
+       unsigned short  acknum;
+       unsigned short  segnum;
+} __attribute__((packed));
 
 
 /* Acknowledgment Message (data/other data)                             */
 struct nsp_data_ack_msg
 {
-       unsigned char   msgflg          __attribute__((packed));
-       unsigned short  dstaddr         __attribute__((packed));
-       unsigned short  srcaddr         __attribute__((packed));
-       unsigned short  acknum          __attribute__((packed));
-};
+       unsigned char   msgflg;
+       unsigned short  dstaddr;
+       unsigned short  srcaddr;
+       unsigned short  acknum;
+} __attribute__((packed));
 
 /* Connect Acknowledgment Message */
 struct  nsp_conn_ack_msg
 {
-       unsigned char   msgflg          __attribute__((packed));
-       unsigned short  dstaddr         __attribute__((packed));
-};
+       unsigned char   msgflg;
+       unsigned short  dstaddr;
+} __attribute__((packed));
 
 
 /* Connect Initiate/Retransmit Initiate/Connect Confirm */
 struct  nsp_conn_init_msg
 {
-       unsigned char   msgflg          __attribute__((packed));
+       unsigned char   msgflg;
 #define NSP_CI      0x18            /* Connect Initiate     */
 #define NSP_RCI     0x68            /* Retrans. Conn Init   */
-       unsigned short  dstaddr         __attribute__((packed));
-        unsigned short  srcaddr         __attribute__((packed));
-        unsigned char   services        __attribute__((packed));
+       unsigned short  dstaddr;
+       unsigned short  srcaddr;
+       unsigned char   services;
 #define NSP_FC_NONE   0x00            /* Flow Control None    */
 #define NSP_FC_SRC    0x04            /* Seg Req. Count       */
 #define NSP_FC_SCMC   0x08            /* Sess. Control Mess   */
 #define NSP_FC_MASK   0x0c            /* FC type mask         */
-       unsigned char   info            __attribute__((packed));
-        unsigned short  segsize         __attribute__((packed));
-};
+       unsigned char   info;
+       unsigned short  segsize;
+} __attribute__((packed));
 
 /* Disconnect Initiate/Disconnect Confirm */
 struct  nsp_disconn_init_msg
 {
-       unsigned char   msgflg          __attribute__((packed));
-        unsigned short  dstaddr         __attribute__((packed));
-        unsigned short  srcaddr         __attribute__((packed));
-        unsigned short  reason          __attribute__((packed));
-};
+       unsigned char   msgflg;
+       unsigned short  dstaddr;
+       unsigned short  srcaddr;
+       unsigned short  reason;
+} __attribute__((packed));
 
 
 
 struct  srcobj_fmt
 {
-       char            format          __attribute__((packed));
-        unsigned char   task            __attribute__((packed));
-        unsigned short  grpcode         __attribute__((packed));
-        unsigned short  usrcode         __attribute__((packed));
-        char            dlen            __attribute__((packed));
-};
+       char            format;
+       unsigned char   task;
+       unsigned short  grpcode;
+       unsigned short  usrcode;
+       char            dlen;
+} __attribute__((packed));
 
 /*
  * A collection of functions for manipulating the sequence
index bee8b84d329db3522f0e9fc7f3991e4579f7963c..5161e89017f934cb6be31560961b52906a56dbdd 100644 (file)
@@ -225,16 +225,7 @@ static inline void dst_set_expires(struct dst_entry *dst, int timeout)
 /* Output packet to network from transport.  */
 static inline int dst_output(struct sk_buff *skb)
 {
-       int err;
-
-       for (;;) {
-               err = skb->dst->output(skb);
-
-               if (likely(err == 0))
-                       return err;
-               if (unlikely(err != NET_XMIT_BYPASS))
-                       return err;
-       }
+       return skb->dst->output(skb);
 }
 
 /* Input packet from network to transport.  */
index 7bb5804847f29d2ea457383cdce7b0929e16a65a..8de0697b364c9853592657d6b6d62a244ede011b 100644 (file)
@@ -37,11 +37,10 @@ struct inet_skb_parm
        struct ip_options       opt;            /* Compiled IP options          */
        unsigned char           flags;
 
-#define IPSKB_MASQUERADED      1
-#define IPSKB_TRANSLATED       2
-#define IPSKB_FORWARDED                4
-#define IPSKB_XFRM_TUNNEL_SIZE 8
-#define IPSKB_FRAG_COMPLETE    16
+#define IPSKB_FORWARDED                1
+#define IPSKB_XFRM_TUNNEL_SIZE 2
+#define IPSKB_XFRM_TRANSFORMED 4
+#define IPSKB_FRAG_COMPLETE    8
 };
 
 struct ipcm_cookie
@@ -95,7 +94,6 @@ extern int            ip_local_deliver(struct sk_buff *skb);
 extern int             ip_mr_input(struct sk_buff *skb);
 extern int             ip_output(struct sk_buff *skb);
 extern int             ip_mc_output(struct sk_buff *skb);
-extern int             ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*));
 extern int             ip_do_nat(struct sk_buff *skb);
 extern void            ip_send_check(struct iphdr *ip);
 extern int             ip_queue_xmit(struct sk_buff *skb, int ipfragok);
index 860bbac4c4ee37dd0d3431c120f9ddf5a8fd3746..3b1d963d396caacb46c5be018aac0a89ea82d4a2 100644 (file)
@@ -418,6 +418,8 @@ extern int                  ipv6_rcv(struct sk_buff *skb,
                                         struct packet_type *pt,
                                         struct net_device *orig_dev);
 
+extern int                     ip6_rcv_finish(struct sk_buff *skb);
+
 /*
  *     upper-layer output functions
  */
index 63f7db99c2a67c526dffd96a090621f5542e6765..6dc5970612d74eb822e39e2c50659286df4215ee 100644 (file)
@@ -43,7 +43,7 @@ struct net_protocol {
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 struct inet6_protocol 
 {
-       int     (*handler)(struct sk_buff **skb, unsigned int *nhoffp);
+       int     (*handler)(struct sk_buff **skb);
 
        void    (*err_handler)(struct sk_buff *skb,
                               struct inet6_skb_parm *opt,
index 07d7b50cdd76fc9ed52d1f98609898703e807161..d09ca0e7d139632f92ae49c7c46f82d4bfce2795 100644 (file)
@@ -668,7 +668,7 @@ static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *s
        return xfrm_policy_check(sk, dir, skb, AF_INET6);
 }
 
-
+extern int xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family);
 extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family);
 
 static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family)
@@ -831,7 +831,7 @@ struct xfrm_tunnel {
 };
 
 struct xfrm6_tunnel {
-       int (*handler)(struct sk_buff **pskb, unsigned int *nhoffp);
+       int (*handler)(struct sk_buff **pskb);
        void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
                            int type, int code, int offset, __u32 info);
 };
@@ -866,10 +866,11 @@ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
 extern int xfrm_init_state(struct xfrm_state *x);
 extern int xfrm4_rcv(struct sk_buff *skb);
 extern int xfrm4_output(struct sk_buff *skb);
+extern int xfrm4_output_finish(struct sk_buff *skb);
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
-extern int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi);
-extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
+extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
+extern int xfrm6_rcv(struct sk_buff **pskb);
 extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
 extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
 extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
index 9e572aed243580f2d0b421031c81485c76022651..15d82e594b564e10a2deb4626843d54b321b9ed4 100644 (file)
@@ -454,22 +454,22 @@ typedef struct wf_multisample {
 } wavefront_multisample;
 
 typedef struct wf_alias {
-    s16 OriginalSample __attribute__ ((packed));
-
-    struct wf_sample_offset sampleStartOffset __attribute__ ((packed));
-    struct wf_sample_offset loopStartOffset __attribute__ ((packed));
-    struct wf_sample_offset sampleEndOffset __attribute__ ((packed));
-    struct wf_sample_offset loopEndOffset __attribute__ ((packed));
-
-    s16  FrequencyBias __attribute__ ((packed));
-
-    u8 SampleResolution:2  __attribute__ ((packed));
-    u8 Unused1:1  __attribute__ ((packed));
-    u8 Loop:1 __attribute__ ((packed));
-    u8 Bidirectional:1  __attribute__ ((packed));
-    u8 Unused2:1 __attribute__ ((packed));
-    u8 Reverse:1 __attribute__ ((packed));
-    u8 Unused3:1 __attribute__ ((packed)); 
+    s16 OriginalSample;
+
+    struct wf_sample_offset sampleStartOffset;
+    struct wf_sample_offset loopStartOffset;
+    struct wf_sample_offset sampleEndOffset;
+    struct wf_sample_offset loopEndOffset;
+
+    s16  FrequencyBias;
+
+    u8 SampleResolution:2;
+    u8 Unused1:1;
+    u8 Loop:1;
+    u8 Bidirectional:1;
+    u8 Unused2:1;
+    u8 Reverse:1;
+    u8 Unused3:1;
     
     /* This structure is meant to be padded only to 16 bits on their
        original. Of course, whoever wrote their documentation didn't
@@ -480,8 +480,8 @@ typedef struct wf_alias {
        standard 16->32 bit issues.
     */
 
-    u8 sixteen_bit_padding __attribute__ ((packed));
-} wavefront_alias;
+    u8 sixteen_bit_padding;
+} __attribute__((packed)) wavefront_alias;
 
 typedef struct wf_drum {
     u8 PatchNumber;
index a9948232b13165f74f6558e66a1b108bc67ddc53..717440575380e3a0af91b230eac8f33bad15893a 100644 (file)
 #define GE04   (GEBase+0x04)   // source 2, p 111
 #define GE08   (GEBase+0x08)   // destination 1, p 111
 #define GE0C   (GEBase+0x0C)   // destination 2, p 112
+#define GE10   (GEBase+0x10)   // right view base & enable, p 112
+#define GE13   (GEBase+0x13)   // left view base & enable, p 112
+#define GE18   (GEBase+0x18)   // block write start address, p 112
+#define GE1C   (GEBase+0x1C)   // block write end address, p 112
 #define GE20   (GEBase+0x20)   // engine status, p 113
 #define GE24   (GEBase+0x24)   // reset all GE pointers
 #define GE44   (GEBase+0x44)   // command register, p 126
index ba42f3793a84332dcbe6cdb5e4594d193997f59c..f8f6929d8f254ea70422589d916d3cb2fc796766 100644 (file)
@@ -228,6 +228,25 @@ config CPUSETS
 
 source "usr/Kconfig"
 
+config UID16
+       bool "Enable 16-bit UID system calls" if EMBEDDED
+       depends !ALPHA && !PPC && !PPC64 && !PARISC && !V850 && !ARCH_S390X
+       depends !X86_64 || IA32_EMULATION
+       depends !SPARC64 || SPARC32_COMPAT
+       default y
+       help
+         This enables the legacy 16-bit UID syscall wrappers.
+
+config VM86
+       depends X86
+       default y
+       bool "Enable VM86 support" if EMBEDDED
+       help
+          This option is required by programs like DOSEMU to run 16-bit legacy
+         code on X86 processors. It also may be needed by software like
+          XFree86 to initialize some video cards via BIOS. Disabling this
+          option saves about 6k.
+
 config CC_OPTIMIZE_FOR_SIZE
        bool "Optimize for size (Look out for broken compilers!)"
        default y
@@ -309,6 +328,21 @@ config BUG
           option for embedded systems with no facilities for reporting errors.
           Just say Y.
 
+config DOUBLEFAULT
+       depends X86
+       default y if X86
+       bool "Enable doublefault exception handler" if EMBEDDED
+       help
+          This option allows trapping of rare doublefault exceptions that
+          would otherwise cause a system to silently reboot. Disabling this
+          option saves about 4k.
+
+config ELF_CORE
+       default y
+       bool "Enable ELF core dumps" if EMBEDDED
+       help
+         Enable support for generating core dumps. Disabling saves about 4k.
+
 config BASE_FULL
        default y
        bool "Enable full-sized data structures for core" if EMBEDDED
@@ -380,6 +414,15 @@ config CC_ALIGN_JUMPS
          no dummy operations need be executed.
          Zero means use compiler's default.
 
+config SLAB
+       default y
+       bool "Use full SLAB allocator" if EMBEDDED
+       help
+         Disabling this replaces the advanced SLAB allocator and
+         kmalloc support with the drastically simpler SLOB allocator.
+         SLOB is more space efficient but does not scale well and is
+         more susceptible to fragmentation.
+
 endmenu                # General setup
 
 config TINY_SHMEM
@@ -391,6 +434,10 @@ config BASE_SMALL
        default 0 if BASE_FULL
        default 1 if !BASE_FULL
 
+config SLOB
+       default !SLAB
+       bool
+
 menu "Loadable module support"
 
 config MODULES
index 2ed3638deec7c996a5807c1ff18494ab5b576850..8342c2890b16dd364f9222855e9a6bb7b5b8fc7d 100644 (file)
  * This is one of the first .c files built. Error out early
  * if we have compiler trouble..
  */
-#if __GNUC__ == 2 && __GNUC_MINOR__ == 96
-#ifdef CONFIG_FRAME_POINTER
-#error This compiler cannot compile correctly with frame pointers enabled
-#endif
-#endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
@@ -74,7 +69,7 @@
  * To avoid associated bogus bug reports, we flatly refuse to compile
  * with a gcc that is known to be too old from the very beginning.
  */
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
+#if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 2)
 #error Sorry, your GCC is too old. It builds incorrect kernels.
 #endif
 
@@ -512,6 +507,7 @@ asmlinkage void __init start_kernel(void)
        }
 #endif
        vfs_caches_init_early();
+       cpuset_init_early();
        mem_init();
        kmem_cache_init();
        setup_per_cpu_pageset();
index 0ef4a1cf3e27246b54a2e31865e85d9ccded7398..0b92e874fc068fb1bc34f3e5940cfb45542f29f7 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -34,8 +34,6 @@
 
 #include "util.h"
 
-#define shm_flags      shm_perm.mode
-
 static struct file_operations shm_file_operations;
 static struct vm_operations_struct shm_vm_ops;
 
@@ -148,7 +146,7 @@ static void shm_close (struct vm_area_struct *shmd)
        shp->shm_dtim = get_seconds();
        shp->shm_nattch--;
        if(shp->shm_nattch == 0 &&
-          shp->shm_flags & SHM_DEST)
+          shp->shm_perm.mode & SHM_DEST)
                shm_destroy (shp);
        else
                shm_unlock(shp);
@@ -205,7 +203,7 @@ static int newseg (key_t key, int shmflg, size_t size)
                return -ENOMEM;
 
        shp->shm_perm.key = key;
-       shp->shm_flags = (shmflg & S_IRWXUGO);
+       shp->shm_perm.mode = (shmflg & S_IRWXUGO);
        shp->mlock_user = NULL;
 
        shp->shm_perm.security = NULL;
@@ -345,7 +343,7 @@ static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __
 
                out->uid        = tbuf.shm_perm.uid;
                out->gid        = tbuf.shm_perm.gid;
-               out->mode       = tbuf.shm_flags;
+               out->mode       = tbuf.shm_perm.mode;
 
                return 0;
            }
@@ -358,7 +356,7 @@ static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __
 
                out->uid        = tbuf_old.shm_perm.uid;
                out->gid        = tbuf_old.shm_perm.gid;
-               out->mode       = tbuf_old.shm_flags;
+               out->mode       = tbuf_old.shm_perm.mode;
 
                return 0;
            }
@@ -560,13 +558,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
                        if (!is_file_hugepages(shp->shm_file)) {
                                err = shmem_lock(shp->shm_file, 1, user);
                                if (!err) {
-                                       shp->shm_flags |= SHM_LOCKED;
+                                       shp->shm_perm.mode |= SHM_LOCKED;
                                        shp->mlock_user = user;
                                }
                        }
                } else if (!is_file_hugepages(shp->shm_file)) {
                        shmem_lock(shp->shm_file, 0, shp->mlock_user);
-                       shp->shm_flags &= ~SHM_LOCKED;
+                       shp->shm_perm.mode &= ~SHM_LOCKED;
                        shp->mlock_user = NULL;
                }
                shm_unlock(shp);
@@ -605,7 +603,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
                        goto out_unlock_up;
 
                if (shp->shm_nattch){
-                       shp->shm_flags |= SHM_DEST;
+                       shp->shm_perm.mode |= SHM_DEST;
                        /* Do not find it any more */
                        shp->shm_perm.key = IPC_PRIVATE;
                        shm_unlock(shp);
@@ -644,7 +642,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
                
                shp->shm_perm.uid = setbuf.uid;
                shp->shm_perm.gid = setbuf.gid;
-               shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO)
+               shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
                        | (setbuf.mode & S_IRWXUGO);
                shp->shm_ctim = get_seconds();
                break;
@@ -777,7 +775,7 @@ invalid:
                BUG();
        shp->shm_nattch--;
        if(shp->shm_nattch == 0 &&
-          shp->shm_flags & SHM_DEST)
+          shp->shm_perm.mode & SHM_DEST)
                shm_destroy (shp);
        else
                shm_unlock(shp);
@@ -902,7 +900,7 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
        return seq_printf(s, format,
                          shp->shm_perm.key,
                          shp->id,
-                         shp->shm_flags,
+                         shp->shm_perm.mode,
                          shp->shm_segsz,
                          shp->shm_cprid,
                          shp->shm_lprid,
index 32fa03ad1984da1395386d99deee3b98e073648d..d13ab7d2d8994f38fb9bf422d873152fd4417057 100644 (file)
@@ -267,7 +267,7 @@ static int audit_set_failure(int state, uid_t loginuid)
        return old;
 }
 
-int kauditd_thread(void *dummy)
+static int kauditd_thread(void *dummy)
 {
        struct sk_buff *skb;
 
index 7430640f9816dcf7e82c9aad6b445f6678e9be1f..eab64e23bcae82a2e729e135d73c140ee21e8ef0 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/namei.h>
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
+#include <linux/rcupdate.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 
-#define CPUSET_SUPER_MAGIC             0x27e0eb
+#define CPUSET_SUPER_MAGIC             0x27e0eb
+
+/*
+ * Tracks how many cpusets are currently defined in system.
+ * When there is only one cpuset (the root cpuset) we can
+ * short circuit some hooks.
+ */
+int number_of_cpusets __read_mostly;
+
+/* See "Frequency meter" comments, below. */
+
+struct fmeter {
+       int cnt;                /* unprocessed events count */
+       int val;                /* most recent output value */
+       time_t time;            /* clock (secs) when val computed */
+       spinlock_t lock;        /* guards read or write of above */
+};
 
 struct cpuset {
        unsigned long flags;            /* "unsigned long" so bitops work */
@@ -80,13 +97,16 @@ struct cpuset {
         * Copy of global cpuset_mems_generation as of the most
         * recent time this cpuset changed its mems_allowed.
         */
-        int mems_generation;
+       int mems_generation;
+
+       struct fmeter fmeter;           /* memory_pressure filter */
 };
 
 /* bits in struct cpuset flags field */
 typedef enum {
        CS_CPU_EXCLUSIVE,
        CS_MEM_EXCLUSIVE,
+       CS_MEMORY_MIGRATE,
        CS_REMOVED,
        CS_NOTIFY_ON_RELEASE
 } cpuset_flagbits_t;
@@ -112,6 +132,11 @@ static inline int notify_on_release(const struct cpuset *cs)
        return !!test_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);
 }
 
+static inline int is_memory_migrate(const struct cpuset *cs)
+{
+       return !!test_bit(CS_MEMORY_MIGRATE, &cs->flags);
+}
+
 /*
  * Increment this atomic integer everytime any cpuset changes its
  * mems_allowed value.  Users of cpusets can track this generation
@@ -137,13 +162,10 @@ static struct cpuset top_cpuset = {
        .count = ATOMIC_INIT(0),
        .sibling = LIST_HEAD_INIT(top_cpuset.sibling),
        .children = LIST_HEAD_INIT(top_cpuset.children),
-       .parent = NULL,
-       .dentry = NULL,
-       .mems_generation = 0,
 };
 
 static struct vfsmount *cpuset_mount;
-static struct super_block *cpuset_sb = NULL;
+static struct super_block *cpuset_sb;
 
 /*
  * We have two global cpuset semaphores below.  They can nest.
@@ -227,6 +249,11 @@ static struct super_block *cpuset_sb = NULL;
  * a tasks cpuset pointer we use task_lock(), which acts on a spinlock
  * (task->alloc_lock) already in the task_struct routinely used for
  * such matters.
+ *
+ * P.S.  One more locking exception.  RCU is used to guard the
+ * update of a tasks cpuset pointer by attach_task() and the
+ * access of task->cpuset->mems_generation via that pointer in
+ * the routine cpuset_update_task_memory_state().
  */
 
 static DECLARE_MUTEX(manage_sem);
@@ -304,7 +331,7 @@ static void cpuset_d_remove_dir(struct dentry *dentry)
        spin_lock(&dcache_lock);
        node = dentry->d_subdirs.next;
        while (node != &dentry->d_subdirs) {
-               struct dentry *d = list_entry(node, struct dentry, d_child);
+               struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
                list_del_init(node);
                if (d->d_inode) {
                        d = dget_locked(d);
@@ -316,7 +343,7 @@ static void cpuset_d_remove_dir(struct dentry *dentry)
                }
                node = dentry->d_subdirs.next;
        }
-       list_del_init(&dentry->d_child);
+       list_del_init(&dentry->d_u.d_child);
        spin_unlock(&dcache_lock);
        remove_dir(dentry);
 }
@@ -570,20 +597,43 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
        BUG_ON(!nodes_intersects(*pmask, node_online_map));
 }
 
-/*
- * Refresh current tasks mems_allowed and mems_generation from current
- * tasks cpuset.
+/**
+ * cpuset_update_task_memory_state - update task memory placement
  *
- * Call without callback_sem or task_lock() held.  May be called with
- * or without manage_sem held.  Will acquire task_lock() and might
- * acquire callback_sem during call.
+ * If the current tasks cpusets mems_allowed changed behind our
+ * backs, update current->mems_allowed, mems_generation and task NUMA
+ * mempolicy to the new value.
+ *
+ * Task mempolicy is updated by rebinding it relative to the
+ * current->cpuset if a task has its memory placement changed.
+ * Do not call this routine if in_interrupt().
  *
- * The task_lock() is required to dereference current->cpuset safely.
- * Without it, we could pick up the pointer value of current->cpuset
- * in one instruction, and then attach_task could give us a different
- * cpuset, and then the cpuset we had could be removed and freed,
- * and then on our next instruction, we could dereference a no longer
- * valid cpuset pointer to get its mems_generation field.
+ * Call without callback_sem or task_lock() held.  May be called
+ * with or without manage_sem held.  Doesn't need task_lock to guard
+ * against another task changing a non-NULL cpuset pointer to NULL,
+ * as that is only done by a task on itself, and if the current task
+ * is here, it is not simultaneously in the exit code NULL'ing its
+ * cpuset pointer.  This routine also might acquire callback_sem and
+ * current->mm->mmap_sem during call.
+ *
+ * Reading current->cpuset->mems_generation doesn't need task_lock
+ * to guard the current->cpuset derefence, because it is guarded
+ * from concurrent freeing of current->cpuset by attach_task(),
+ * using RCU.
+ *
+ * The rcu_dereference() is technically probably not needed,
+ * as I don't actually mind if I see a new cpuset pointer but
+ * an old value of mems_generation.  However this really only
+ * matters on alpha systems using cpusets heavily.  If I dropped
+ * that rcu_dereference(), it would save them a memory barrier.
+ * For all other arch's, rcu_dereference is a no-op anyway, and for
+ * alpha systems not using cpusets, another planned optimization,
+ * avoiding the rcu critical section for tasks in the root cpuset
+ * which is statically allocated, so can't vanish, will make this
+ * irrelevant.  Better to use RCU as intended, than to engage in
+ * some cute trick to save a memory barrier that is impossible to
+ * test, for alpha systems using cpusets heavily, which might not
+ * even exist.
  *
  * This routine is needed to update the per-task mems_allowed data,
  * within the tasks context, when it is trying to allocate memory
@@ -591,27 +641,31 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
  * task has been modifying its cpuset.
  */
 
-static void refresh_mems(void)
+void cpuset_update_task_memory_state()
 {
        int my_cpusets_mem_gen;
+       struct task_struct *tsk = current;
+       struct cpuset *cs;
 
-       task_lock(current);
-       my_cpusets_mem_gen = current->cpuset->mems_generation;
-       task_unlock(current);
-
-       if (current->cpuset_mems_generation != my_cpusets_mem_gen) {
-               struct cpuset *cs;
-               nodemask_t oldmem = current->mems_allowed;
+       if (tsk->cpuset == &top_cpuset) {
+               /* Don't need rcu for top_cpuset.  It's never freed. */
+               my_cpusets_mem_gen = top_cpuset.mems_generation;
+       } else {
+               rcu_read_lock();
+               cs = rcu_dereference(tsk->cpuset);
+               my_cpusets_mem_gen = cs->mems_generation;
+               rcu_read_unlock();
+       }
 
+       if (my_cpusets_mem_gen != tsk->cpuset_mems_generation) {
                down(&callback_sem);
-               task_lock(current);
-               cs = current->cpuset;
-               guarantee_online_mems(cs, &current->mems_allowed);
-               current->cpuset_mems_generation = cs->mems_generation;
-               task_unlock(current);
+               task_lock(tsk);
+               cs = tsk->cpuset;       /* Maybe changed when task not locked */
+               guarantee_online_mems(cs, &tsk->mems_allowed);
+               tsk->cpuset_mems_generation = cs->mems_generation;
+               task_unlock(tsk);
                up(&callback_sem);
-               if (!nodes_equal(oldmem, current->mems_allowed))
-                       numa_policy_rebind(&oldmem, &current->mems_allowed);
+               mpol_rebind_task(tsk, &tsk->mems_allowed);
        }
 }
 
@@ -766,36 +820,150 @@ static int update_cpumask(struct cpuset *cs, char *buf)
 }
 
 /*
+ * Handle user request to change the 'mems' memory placement
+ * of a cpuset.  Needs to validate the request, update the
+ * cpusets mems_allowed and mems_generation, and for each
+ * task in the cpuset, rebind any vma mempolicies and if
+ * the cpuset is marked 'memory_migrate', migrate the tasks
+ * pages to the new memory.
+ *
  * Call with manage_sem held.  May take callback_sem during call.
+ * Will take tasklist_lock, scan tasklist for tasks in cpuset cs,
+ * lock each such tasks mm->mmap_sem, scan its vma's and rebind
+ * their mempolicies to the cpusets new mems_allowed.
  */
 
 static int update_nodemask(struct cpuset *cs, char *buf)
 {
        struct cpuset trialcs;
+       nodemask_t oldmem;
+       struct task_struct *g, *p;
+       struct mm_struct **mmarray;
+       int i, n, ntasks;
+       int migrate;
+       int fudge;
        int retval;
 
        trialcs = *cs;
        retval = nodelist_parse(buf, trialcs.mems_allowed);
        if (retval < 0)
-               return retval;
+               goto done;
        nodes_and(trialcs.mems_allowed, trialcs.mems_allowed, node_online_map);
-       if (nodes_empty(trialcs.mems_allowed))
-               return -ENOSPC;
+       oldmem = cs->mems_allowed;
+       if (nodes_equal(oldmem, trialcs.mems_allowed)) {
+               retval = 0;             /* Too easy - nothing to do */
+               goto done;
+       }
+       if (nodes_empty(trialcs.mems_allowed)) {
+               retval = -ENOSPC;
+               goto done;
+       }
        retval = validate_change(cs, &trialcs);
-       if (retval == 0) {
-               down(&callback_sem);
-               cs->mems_allowed = trialcs.mems_allowed;
-               atomic_inc(&cpuset_mems_generation);
-               cs->mems_generation = atomic_read(&cpuset_mems_generation);
-               up(&callback_sem);
+       if (retval < 0)
+               goto done;
+
+       down(&callback_sem);
+       cs->mems_allowed = trialcs.mems_allowed;
+       atomic_inc(&cpuset_mems_generation);
+       cs->mems_generation = atomic_read(&cpuset_mems_generation);
+       up(&callback_sem);
+
+       set_cpuset_being_rebound(cs);           /* causes mpol_copy() rebind */
+
+       fudge = 10;                             /* spare mmarray[] slots */
+       fudge += cpus_weight(cs->cpus_allowed); /* imagine one fork-bomb/cpu */
+       retval = -ENOMEM;
+
+       /*
+        * Allocate mmarray[] to hold mm reference for each task
+        * in cpuset cs.  Can't kmalloc GFP_KERNEL while holding
+        * tasklist_lock.  We could use GFP_ATOMIC, but with a
+        * few more lines of code, we can retry until we get a big
+        * enough mmarray[] w/o using GFP_ATOMIC.
+        */
+       while (1) {
+               ntasks = atomic_read(&cs->count);       /* guess */
+               ntasks += fudge;
+               mmarray = kmalloc(ntasks * sizeof(*mmarray), GFP_KERNEL);
+               if (!mmarray)
+                       goto done;
+               write_lock_irq(&tasklist_lock);         /* block fork */
+               if (atomic_read(&cs->count) <= ntasks)
+                       break;                          /* got enough */
+               write_unlock_irq(&tasklist_lock);       /* try again */
+               kfree(mmarray);
        }
+
+       n = 0;
+
+       /* Load up mmarray[] with mm reference for each task in cpuset. */
+       do_each_thread(g, p) {
+               struct mm_struct *mm;
+
+               if (n >= ntasks) {
+                       printk(KERN_WARNING
+                               "Cpuset mempolicy rebind incomplete.\n");
+                       continue;
+               }
+               if (p->cpuset != cs)
+                       continue;
+               mm = get_task_mm(p);
+               if (!mm)
+                       continue;
+               mmarray[n++] = mm;
+       } while_each_thread(g, p);
+       write_unlock_irq(&tasklist_lock);
+
+       /*
+        * Now that we've dropped the tasklist spinlock, we can
+        * rebind the vma mempolicies of each mm in mmarray[] to their
+        * new cpuset, and release that mm.  The mpol_rebind_mm()
+        * call takes mmap_sem, which we couldn't take while holding
+        * tasklist_lock.  Forks can happen again now - the mpol_copy()
+        * cpuset_being_rebound check will catch such forks, and rebind
+        * their vma mempolicies too.  Because we still hold the global
+        * cpuset manage_sem, we know that no other rebind effort will
+        * be contending for the global variable cpuset_being_rebound.
+        * It's ok if we rebind the same mm twice; mpol_rebind_mm()
+        * is idempotent.  Also migrate pages in each mm to new nodes.
+        */
+       migrate = is_memory_migrate(cs);
+       for (i = 0; i < n; i++) {
+               struct mm_struct *mm = mmarray[i];
+
+               mpol_rebind_mm(mm, &cs->mems_allowed);
+               if (migrate) {
+                       do_migrate_pages(mm, &oldmem, &cs->mems_allowed,
+                                                       MPOL_MF_MOVE_ALL);
+               }
+               mmput(mm);
+       }
+
+       /* We're done rebinding vma's to this cpusets new mems_allowed. */
+       kfree(mmarray);
+       set_cpuset_being_rebound(NULL);
+       retval = 0;
+done:
        return retval;
 }
 
+/*
+ * Call with manage_sem held.
+ */
+
+static int update_memory_pressure_enabled(struct cpuset *cs, char *buf)
+{
+       if (simple_strtoul(buf, NULL, 10) != 0)
+               cpuset_memory_pressure_enabled = 1;
+       else
+               cpuset_memory_pressure_enabled = 0;
+       return 0;
+}
+
 /*
  * update_flag - read a 0 or a 1 in a file and update associated flag
  * bit:        the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE,
- *                                             CS_NOTIFY_ON_RELEASE)
+ *                             CS_NOTIFY_ON_RELEASE, CS_MEMORY_MIGRATE)
  * cs: the cpuset to update
  * buf:        the buffer where we read the 0 or 1
  *
@@ -833,6 +1001,104 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
        return 0;
 }
 
+/*
+ * Frequency meter - How fast is some event occuring?
+ *
+ * These routines manage a digitally filtered, constant time based,
+ * event frequency meter.  There are four routines:
+ *   fmeter_init() - initialize a frequency meter.
+ *   fmeter_markevent() - called each time the event happens.
+ *   fmeter_getrate() - returns the recent rate of such events.
+ *   fmeter_update() - internal routine used to update fmeter.
+ *
+ * A common data structure is passed to each of these routines,
+ * which is used to keep track of the state required to manage the
+ * frequency meter and its digital filter.
+ *
+ * The filter works on the number of events marked per unit time.
+ * The filter is single-pole low-pass recursive (IIR).  The time unit
+ * is 1 second.  Arithmetic is done using 32-bit integers scaled to
+ * simulate 3 decimal digits of precision (multiplied by 1000).
+ *
+ * With an FM_COEF of 933, and a time base of 1 second, the filter
+ * has a half-life of 10 seconds, meaning that if the events quit
+ * happening, then the rate returned from the fmeter_getrate()
+ * will be cut in half each 10 seconds, until it converges to zero.
+ *
+ * It is not worth doing a real infinitely recursive filter.  If more
+ * than FM_MAXTICKS ticks have elapsed since the last filter event,
+ * just compute FM_MAXTICKS ticks worth, by which point the level
+ * will be stable.
+ *
+ * Limit the count of unprocessed events to FM_MAXCNT, so as to avoid
+ * arithmetic overflow in the fmeter_update() routine.
+ *
+ * Given the simple 32 bit integer arithmetic used, this meter works
+ * best for reporting rates between one per millisecond (msec) and
+ * one per 32 (approx) seconds.  At constant rates faster than one
+ * per msec it maxes out at values just under 1,000,000.  At constant
+ * rates between one per msec, and one per second it will stabilize
+ * to a value N*1000, where N is the rate of events per second.
+ * At constant rates between one per second and one per 32 seconds,
+ * it will be choppy, moving up on the seconds that have an event,
+ * and then decaying until the next event.  At rates slower than
+ * about one in 32 seconds, it decays all the way back to zero between
+ * each event.
+ */
+
+#define FM_COEF 933            /* coefficient for half-life of 10 secs */
+#define FM_MAXTICKS ((time_t)99) /* useless computing more ticks than this */
+#define FM_MAXCNT 1000000      /* limit cnt to avoid overflow */
+#define FM_SCALE 1000          /* faux fixed point scale */
+
+/* Initialize a frequency meter */
+static void fmeter_init(struct fmeter *fmp)
+{
+       fmp->cnt = 0;
+       fmp->val = 0;
+       fmp->time = 0;
+       spin_lock_init(&fmp->lock);
+}
+
+/* Internal meter update - process cnt events and update value */
+static void fmeter_update(struct fmeter *fmp)
+{
+       time_t now = get_seconds();
+       time_t ticks = now - fmp->time;
+
+       if (ticks == 0)
+               return;
+
+       ticks = min(FM_MAXTICKS, ticks);
+       while (ticks-- > 0)
+               fmp->val = (FM_COEF * fmp->val) / FM_SCALE;
+       fmp->time = now;
+
+       fmp->val += ((FM_SCALE - FM_COEF) * fmp->cnt) / FM_SCALE;
+       fmp->cnt = 0;
+}
+
+/* Process any previous ticks, then bump cnt by one (times scale). */
+static void fmeter_markevent(struct fmeter *fmp)
+{
+       spin_lock(&fmp->lock);
+       fmeter_update(fmp);
+       fmp->cnt = min(FM_MAXCNT, fmp->cnt + FM_SCALE);
+       spin_unlock(&fmp->lock);
+}
+
+/* Process any previous ticks, then return current value. */
+static int fmeter_getrate(struct fmeter *fmp)
+{
+       int val;
+
+       spin_lock(&fmp->lock);
+       fmeter_update(fmp);
+       val = fmp->val;
+       spin_unlock(&fmp->lock);
+       return val;
+}
+
 /*
  * Attack task specified by pid in 'pidbuf' to cpuset 'cs', possibly
  * writing the path of the old cpuset in 'ppathbuf' if it needs to be
@@ -848,6 +1114,8 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf)
        struct task_struct *tsk;
        struct cpuset *oldcs;
        cpumask_t cpus;
+       nodemask_t from, to;
+       struct mm_struct *mm;
 
        if (sscanf(pidbuf, "%d", &pid) != 1)
                return -EIO;
@@ -887,14 +1155,27 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf)
                return -ESRCH;
        }
        atomic_inc(&cs->count);
-       tsk->cpuset = cs;
+       rcu_assign_pointer(tsk->cpuset, cs);
        task_unlock(tsk);
 
        guarantee_online_cpus(cs, &cpus);
        set_cpus_allowed(tsk, cpus);
 
+       from = oldcs->mems_allowed;
+       to = cs->mems_allowed;
+
        up(&callback_sem);
+
+       mm = get_task_mm(tsk);
+       if (mm) {
+               mpol_rebind_mm(mm, &to);
+               mmput(mm);
+       }
+
+       if (is_memory_migrate(cs))
+               do_migrate_pages(tsk->mm, &from, &to, MPOL_MF_MOVE_ALL);
        put_task_struct(tsk);
+       synchronize_rcu();
        if (atomic_dec_and_test(&oldcs->count))
                check_for_release(oldcs, ppathbuf);
        return 0;
@@ -905,11 +1186,14 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf)
 typedef enum {
        FILE_ROOT,
        FILE_DIR,
+       FILE_MEMORY_MIGRATE,
        FILE_CPULIST,
        FILE_MEMLIST,
        FILE_CPU_EXCLUSIVE,
        FILE_MEM_EXCLUSIVE,
        FILE_NOTIFY_ON_RELEASE,
+       FILE_MEMORY_PRESSURE_ENABLED,
+       FILE_MEMORY_PRESSURE,
        FILE_TASKLIST,
 } cpuset_filetype_t;
 
@@ -960,6 +1244,15 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us
        case FILE_NOTIFY_ON_RELEASE:
                retval = update_flag(CS_NOTIFY_ON_RELEASE, cs, buffer);
                break;
+       case FILE_MEMORY_MIGRATE:
+               retval = update_flag(CS_MEMORY_MIGRATE, cs, buffer);
+               break;
+       case FILE_MEMORY_PRESSURE_ENABLED:
+               retval = update_memory_pressure_enabled(cs, buffer);
+               break;
+       case FILE_MEMORY_PRESSURE:
+               retval = -EACCES;
+               break;
        case FILE_TASKLIST:
                retval = attach_task(cs, buffer, &pathbuf);
                break;
@@ -1060,6 +1353,15 @@ static ssize_t cpuset_common_file_read(struct file *file, char __user *buf,
        case FILE_NOTIFY_ON_RELEASE:
                *s++ = notify_on_release(cs) ? '1' : '0';
                break;
+       case FILE_MEMORY_MIGRATE:
+               *s++ = is_memory_migrate(cs) ? '1' : '0';
+               break;
+       case FILE_MEMORY_PRESSURE_ENABLED:
+               *s++ = cpuset_memory_pressure_enabled ? '1' : '0';
+               break;
+       case FILE_MEMORY_PRESSURE:
+               s += sprintf(s, "%d", fmeter_getrate(&cs->fmeter));
+               break;
        default:
                retval = -EINVAL;
                goto out;
@@ -1178,7 +1480,7 @@ static int cpuset_create_file(struct dentry *dentry, int mode)
 
 /*
  *     cpuset_create_dir - create a directory for an object.
- *     cs:     the cpuset we create the directory for.
+ *     cs:     the cpuset we create the directory for.
  *             It must have a valid ->parent field
  *             And we are going to fill its ->dentry field.
  *     name:   The name to give to the cpuset directory. Will be copied.
@@ -1408,6 +1710,21 @@ static struct cftype cft_notify_on_release = {
        .private = FILE_NOTIFY_ON_RELEASE,
 };
 
+static struct cftype cft_memory_migrate = {
+       .name = "memory_migrate",
+       .private = FILE_MEMORY_MIGRATE,
+};
+
+static struct cftype cft_memory_pressure_enabled = {
+       .name = "memory_pressure_enabled",
+       .private = FILE_MEMORY_PRESSURE_ENABLED,
+};
+
+static struct cftype cft_memory_pressure = {
+       .name = "memory_pressure",
+       .private = FILE_MEMORY_PRESSURE,
+};
+
 static int cpuset_populate_dir(struct dentry *cs_dentry)
 {
        int err;
@@ -1422,6 +1739,10 @@ static int cpuset_populate_dir(struct dentry *cs_dentry)
                return err;
        if ((err = cpuset_add_file(cs_dentry, &cft_notify_on_release)) < 0)
                return err;
+       if ((err = cpuset_add_file(cs_dentry, &cft_memory_migrate)) < 0)
+               return err;
+       if ((err = cpuset_add_file(cs_dentry, &cft_memory_pressure)) < 0)
+               return err;
        if ((err = cpuset_add_file(cs_dentry, &cft_tasks)) < 0)
                return err;
        return 0;
@@ -1446,7 +1767,7 @@ static long cpuset_create(struct cpuset *parent, const char *name, int mode)
                return -ENOMEM;
 
        down(&manage_sem);
-       refresh_mems();
+       cpuset_update_task_memory_state();
        cs->flags = 0;
        if (notify_on_release(parent))
                set_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);
@@ -1457,11 +1778,13 @@ static long cpuset_create(struct cpuset *parent, const char *name, int mode)
        INIT_LIST_HEAD(&cs->children);
        atomic_inc(&cpuset_mems_generation);
        cs->mems_generation = atomic_read(&cpuset_mems_generation);
+       fmeter_init(&cs->fmeter);
 
        cs->parent = parent;
 
        down(&callback_sem);
        list_add(&cs->sibling, &cs->parent->children);
+       number_of_cpusets++;
        up(&callback_sem);
 
        err = cpuset_create_dir(cs, name, mode);
@@ -1503,7 +1826,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry)
        /* the vfs holds both inode->i_sem already */
 
        down(&manage_sem);
-       refresh_mems();
+       cpuset_update_task_memory_state();
        if (atomic_read(&cs->count) > 0) {
                up(&manage_sem);
                return -EBUSY;
@@ -1524,6 +1847,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry)
        spin_unlock(&d->d_lock);
        cpuset_d_remove_dir(d);
        dput(d);
+       number_of_cpusets--;
        up(&callback_sem);
        if (list_empty(&parent->children))
                check_for_release(parent, &pathbuf);
@@ -1532,6 +1856,21 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry)
        return 0;
 }
 
+/*
+ * cpuset_init_early - just enough so that the calls to
+ * cpuset_update_task_memory_state() in early init code
+ * are harmless.
+ */
+
+int __init cpuset_init_early(void)
+{
+       struct task_struct *tsk = current;
+
+       tsk->cpuset = &top_cpuset;
+       tsk->cpuset->mems_generation = atomic_read(&cpuset_mems_generation);
+       return 0;
+}
+
 /**
  * cpuset_init - initialize cpusets at system boot
  *
@@ -1546,6 +1885,7 @@ int __init cpuset_init(void)
        top_cpuset.cpus_allowed = CPU_MASK_ALL;
        top_cpuset.mems_allowed = NODE_MASK_ALL;
 
+       fmeter_init(&top_cpuset.fmeter);
        atomic_inc(&cpuset_mems_generation);
        top_cpuset.mems_generation = atomic_read(&cpuset_mems_generation);
 
@@ -1566,7 +1906,11 @@ int __init cpuset_init(void)
        root->d_inode->i_nlink++;
        top_cpuset.dentry = root;
        root->d_inode->i_op = &cpuset_dir_inode_operations;
+       number_of_cpusets = 1;
        err = cpuset_populate_dir(root);
+       /* memory_pressure_enabled is in root cpuset only */
+       if (err == 0)
+               err = cpuset_add_file(root, &cft_memory_pressure_enabled);
 out:
        return err;
 }
@@ -1632,15 +1976,13 @@ void cpuset_fork(struct task_struct *child)
  *
  * We don't need to task_lock() this reference to tsk->cpuset,
  * because tsk is already marked PF_EXITING, so attach_task() won't
- * mess with it.
+ * mess with it, or task is a failed fork, never visible to attach_task.
  **/
 
 void cpuset_exit(struct task_struct *tsk)
 {
        struct cpuset *cs;
 
-       BUG_ON(!(tsk->flags & PF_EXITING));
-
        cs = tsk->cpuset;
        tsk->cpuset = NULL;
 
@@ -1667,14 +2009,14 @@ void cpuset_exit(struct task_struct *tsk)
  * tasks cpuset.
  **/
 
-cpumask_t cpuset_cpus_allowed(const struct task_struct *tsk)
+cpumask_t cpuset_cpus_allowed(struct task_struct *tsk)
 {
        cpumask_t mask;
 
        down(&callback_sem);
-       task_lock((struct task_struct *)tsk);
+       task_lock(tsk);
        guarantee_online_cpus(tsk->cpuset, &mask);
-       task_unlock((struct task_struct *)tsk);
+       task_unlock(tsk);
        up(&callback_sem);
 
        return mask;
@@ -1686,43 +2028,26 @@ void cpuset_init_current_mems_allowed(void)
 }
 
 /**
- * cpuset_update_current_mems_allowed - update mems parameters to new values
- *
- * If the current tasks cpusets mems_allowed changed behind our backs,
- * update current->mems_allowed and mems_generation to the new value.
- * Do not call this routine if in_interrupt().
+ * cpuset_mems_allowed - return mems_allowed mask from a tasks cpuset.
+ * @tsk: pointer to task_struct from which to obtain cpuset->mems_allowed.
  *
- * Call without callback_sem or task_lock() held.  May be called
- * with or without manage_sem held.  Unless exiting, it will acquire
- * task_lock().  Also might acquire callback_sem during call to
- * refresh_mems().
- */
+ * Description: Returns the nodemask_t mems_allowed of the cpuset
+ * attached to the specified @tsk.  Guaranteed to return some non-empty
+ * subset of node_online_map, even if this means going outside the
+ * tasks cpuset.
+ **/
 
-void cpuset_update_current_mems_allowed(void)
+nodemask_t cpuset_mems_allowed(struct task_struct *tsk)
 {
-       struct cpuset *cs;
-       int need_to_refresh = 0;
+       nodemask_t mask;
 
-       task_lock(current);
-       cs = current->cpuset;
-       if (!cs)
-               goto done;
-       if (current->cpuset_mems_generation != cs->mems_generation)
-               need_to_refresh = 1;
-done:
-       task_unlock(current);
-       if (need_to_refresh)
-               refresh_mems();
-}
+       down(&callback_sem);
+       task_lock(tsk);
+       guarantee_online_mems(tsk->cpuset, &mask);
+       task_unlock(tsk);
+       up(&callback_sem);
 
-/**
- * cpuset_restrict_to_mems_allowed - limit nodes to current mems_allowed
- * @nodes: pointer to a node bitmap that is and-ed with mems_allowed
- */
-void cpuset_restrict_to_mems_allowed(unsigned long *nodes)
-{
-       bitmap_and(nodes, nodes, nodes_addr(current->mems_allowed),
-                                                       MAX_NUMNODES);
+       return mask;
 }
 
 /**
@@ -1795,7 +2120,7 @@ static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
  *     GFP_USER     - only nodes in current tasks mems allowed ok.
  **/
 
-int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
+int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
 {
        int node;                       /* node that zone z is on */
        const struct cpuset *cs;        /* current cpuset ancestors */
@@ -1866,6 +2191,42 @@ done:
        return overlap;
 }
 
+/*
+ * Collection of memory_pressure is suppressed unless
+ * this flag is enabled by writing "1" to the special
+ * cpuset file 'memory_pressure_enabled' in the root cpuset.
+ */
+
+int cpuset_memory_pressure_enabled __read_mostly;
+
+/**
+ * cpuset_memory_pressure_bump - keep stats of per-cpuset reclaims.
+ *
+ * Keep a running average of the rate of synchronous (direct)
+ * page reclaim efforts initiated by tasks in each cpuset.
+ *
+ * This represents the rate at which some task in the cpuset
+ * ran low on memory on all nodes it was allowed to use, and
+ * had to enter the kernels page reclaim code in an effort to
+ * create more free memory by tossing clean pages or swapping
+ * or writing dirty pages.
+ *
+ * Display to user space in the per-cpuset read-only file
+ * "memory_pressure".  Value displayed is an integer
+ * representing the recent rate of entry into the synchronous
+ * (direct) page reclaim by any task attached to the cpuset.
+ **/
+
+void __cpuset_memory_pressure_bump(void)
+{
+       struct cpuset *cs;
+
+       task_lock(current);
+       cs = current->cpuset;
+       fmeter_markevent(&cs->fmeter);
+       task_unlock(current);
+}
+
 /*
  * proc_cpuset_show()
  *  - Print tasks cpuset path into seq_file.
index 334c37f5218aa39a2f7851a73181f01b401539b8..fccb27dbc623b95405d2a6defaaf38696d2269d5 100644 (file)
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/kexec.h>
 
 /* Stores the physical address of elf header of crash image. */
 unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
 
+#ifndef HAVE_ARCH_COPY_OLDMEM_PAGE
 /**
  * copy_oldmem_page - copy one page from "oldmem"
  * @pfn: page frame number to be copied
@@ -59,3 +61,4 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
        kfree(page);
        return csize;
 }
+#endif
index ee515683b92db35decaaeea608d9be919bb73f33..caceabf3f2305a0b1c6679b72c9abbf74528dfa7 100644 (file)
@@ -72,7 +72,6 @@ repeat:
                __ptrace_unlink(p);
        BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children));
        __exit_signal(p);
-       __exit_sighand(p);
        /*
         * Note that the fastpath in sys_times depends on __exit_signal having
         * updated the counters before a task is removed from the tasklist of
@@ -258,7 +257,7 @@ static inline void reparent_to_init(void)
 
 void __set_special_pids(pid_t session, pid_t pgrp)
 {
-       struct task_struct *curr = current;
+       struct task_struct *curr = current->group_leader;
 
        if (curr->signal->session != session) {
                detach_pid(curr, PIDTYPE_SID);
@@ -926,7 +925,6 @@ do_group_exit(int exit_code)
                        /* Another thread got here before we took the lock.  */
                        exit_code = sig->group_exit_code;
                else {
-                       sig->flags = SIGNAL_GROUP_EXIT;
                        sig->group_exit_code = exit_code;
                        zap_other_threads(current);
                }
index fb8572a4229743baef22241dbab6ae8356f633c7..72e3252c6763400fea40a4f387a780627d2cbbf7 100644 (file)
@@ -743,6 +743,14 @@ int unshare_files(void)
 
 EXPORT_SYMBOL(unshare_files);
 
+void sighand_free_cb(struct rcu_head *rhp)
+{
+       struct sighand_struct *sp;
+
+       sp = container_of(rhp, struct sighand_struct, rcu);
+       kmem_cache_free(sighand_cachep, sp);
+}
+
 static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
 {
        struct sighand_struct *sig;
@@ -752,7 +760,7 @@ static inline int copy_sighand(unsigned long clone_flags, struct task_struct * t
                return 0;
        }
        sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);
-       tsk->sighand = sig;
+       rcu_assign_pointer(tsk->sighand, sig);
        if (!sig)
                return -ENOMEM;
        spin_lock_init(&sig->siglock);
@@ -803,9 +811,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
        sig->it_prof_expires = cputime_zero;
        sig->it_prof_incr = cputime_zero;
 
-       sig->tty = current->signal->tty;
-       sig->pgrp = process_group(current);
-       sig->session = current->signal->session;
        sig->leader = 0;        /* session leadership doesn't inherit */
        sig->tty_old_pgrp = 0;
 
@@ -964,12 +969,13 @@ static task_t *copy_process(unsigned long clone_flags,
        p->io_context = NULL;
        p->io_wait = NULL;
        p->audit_context = NULL;
+       cpuset_fork(p);
 #ifdef CONFIG_NUMA
        p->mempolicy = mpol_copy(p->mempolicy);
        if (IS_ERR(p->mempolicy)) {
                retval = PTR_ERR(p->mempolicy);
                p->mempolicy = NULL;
-               goto bad_fork_cleanup;
+               goto bad_fork_cleanup_cpuset;
        }
 #endif
 
@@ -1127,25 +1133,19 @@ static task_t *copy_process(unsigned long clone_flags,
        attach_pid(p, PIDTYPE_PID, p->pid);
        attach_pid(p, PIDTYPE_TGID, p->tgid);
        if (thread_group_leader(p)) {
+               p->signal->tty = current->signal->tty;
+               p->signal->pgrp = process_group(current);
+               p->signal->session = current->signal->session;
                attach_pid(p, PIDTYPE_PGID, process_group(p));
                attach_pid(p, PIDTYPE_SID, p->signal->session);
                if (p->pid)
                        __get_cpu_var(process_counts)++;
        }
 
-       if (!current->signal->tty && p->signal->tty)
-               p->signal->tty = NULL;
-
        nr_threads++;
        total_forks++;
        write_unlock_irq(&tasklist_lock);
        proc_fork_connector(p);
-       cpuset_fork(p);
-       retval = 0;
-
-fork_out:
-       if (retval)
-               return ERR_PTR(retval);
        return p;
 
 bad_fork_cleanup_namespace:
@@ -1172,7 +1172,9 @@ bad_fork_cleanup_security:
 bad_fork_cleanup_policy:
 #ifdef CONFIG_NUMA
        mpol_free(p->mempolicy);
+bad_fork_cleanup_cpuset:
 #endif
+       cpuset_exit(p);
 bad_fork_cleanup:
        if (p->binfmt)
                module_put(p->binfmt->module);
@@ -1184,7 +1186,8 @@ bad_fork_cleanup_count:
        free_uid(p->user);
 bad_fork_free:
        free_task(p);
-       goto fork_out;
+fork_out:
+       return ERR_PTR(retval);
 }
 
 struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs)
index 8a64a4844cdeeda11fd2286e17b9d9f977a7fa76..d03b5eef8ce07bee171424abcfec206c6faadcef 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
 
+#include "internals.h"
+
 static struct proc_dir_entry *root_irq_dir, *irq_dir[NR_IRQS];
 
 #ifdef CONFIG_SMP
index 4b06bbad49c2185015af02f49bf581b847c419be..e4276046a1b62489b9b4e60362119ad95656e438 100644 (file)
@@ -496,15 +496,15 @@ static void module_unload_free(struct module *mod)
 }
 
 #ifdef CONFIG_MODULE_FORCE_UNLOAD
-static inline int try_force(unsigned int flags)
+static inline int try_force_unload(unsigned int flags)
 {
        int ret = (flags & O_TRUNC);
        if (ret)
-               add_taint(TAINT_FORCED_MODULE);
+               add_taint(TAINT_FORCED_RMMOD);
        return ret;
 }
 #else
-static inline int try_force(unsigned int flags)
+static inline int try_force_unload(unsigned int flags)
 {
        return 0;
 }
@@ -524,7 +524,7 @@ static int __try_stop_module(void *_sref)
 
        /* If it's not unused, quit unless we are told to block. */
        if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) {
-               if (!(*sref->forced = try_force(sref->flags)))
+               if (!(*sref->forced = try_force_unload(sref->flags)))
                        return -EWOULDBLOCK;
        }
 
@@ -609,7 +609,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
        /* If it has an init func, it must have an exit func to unload */
        if ((mod->init != NULL && mod->exit == NULL)
            || mod->unsafe) {
-               forced = try_force(flags);
+               forced = try_force_unload(flags);
                if (!forced) {
                        /* This module can't be removed */
                        ret = -EBUSY;
@@ -958,7 +958,6 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
        unsigned long ret;
        const unsigned long *crc;
 
-       spin_lock_irq(&modlist_lock);
        ret = __find_symbol(name, &owner, &crc, mod->license_gplok);
        if (ret) {
                /* use_module can fail due to OOM, or module unloading */
@@ -966,7 +965,6 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
                    !use_module(mod, owner))
                        ret = 0;
        }
-       spin_unlock_irq(&modlist_lock);
        return ret;
 }
 
@@ -1204,6 +1202,39 @@ void *__symbol_get(const char *symbol)
 }
 EXPORT_SYMBOL_GPL(__symbol_get);
 
+/*
+ * Ensure that an exported symbol [global namespace] does not already exist
+ * in the Kernel or in some other modules exported symbol table.
+ */
+static int verify_export_symbols(struct module *mod)
+{
+       const char *name = NULL;
+       unsigned long i, ret = 0;
+       struct module *owner;
+       const unsigned long *crc;
+
+       for (i = 0; i < mod->num_syms; i++)
+               if (__find_symbol(mod->syms[i].name, &owner, &crc, 1)) {
+                       name = mod->syms[i].name;
+                       ret = -ENOEXEC;
+                       goto dup;
+               }
+
+       for (i = 0; i < mod->num_gpl_syms; i++)
+               if (__find_symbol(mod->gpl_syms[i].name, &owner, &crc, 1)) {
+                       name = mod->gpl_syms[i].name;
+                       ret = -ENOEXEC;
+                       goto dup;
+               }
+
+dup:
+       if (ret)
+               printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n",
+                       mod->name, name, module_name(owner));
+
+       return ret;
+}
+
 /* Change all symbols so that sh_value encodes the pointer directly. */
 static int simplify_symbols(Elf_Shdr *sechdrs,
                            unsigned int symindex,
@@ -1715,6 +1746,11 @@ static struct module *load_module(void __user *umod,
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 
+       if (strcmp(mod->name, "ndiswrapper") == 0)
+               add_taint(TAINT_PROPRIETARY_MODULE);
+       if (strcmp(mod->name, "driverloader") == 0)
+               add_taint(TAINT_PROPRIETARY_MODULE);
+
 #ifdef CONFIG_MODULE_UNLOAD
        /* Set up MODINFO_ATTR fields */
        setup_modinfo(mod, sechdrs, infoindex);
@@ -1767,6 +1803,12 @@ static struct module *load_module(void __user *umod,
                        goto cleanup;
        }
 
+        /* Find duplicate symbols */
+       err = verify_export_symbols(mod);
+
+       if (err < 0)
+               goto cleanup;
+
        /* Set up and sort exception table */
        mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);
        mod->extable = extable = (void *)sechdrs[exindex].sh_addr;
index edba31c681ace9dcca4ffa00e080d0a535591ffd..1acc07246991972a1eb012f5db0dadd4aeb1a188 100644 (file)
@@ -136,7 +136,7 @@ struct pid * fastcall find_pid(enum pid_type type, int nr)
        struct hlist_node *elem;
        struct pid *pid;
 
-       hlist_for_each_entry(pid, elem,
+       hlist_for_each_entry_rcu(pid, elem,
                        &pid_hash[type][pid_hashfn(nr)], pid_chain) {
                if (pid->nr == nr)
                        return pid;
@@ -150,15 +150,15 @@ int fastcall attach_pid(task_t *task, enum pid_type type, int nr)
 
        task_pid = &task->pids[type];
        pid = find_pid(type, nr);
+       task_pid->nr = nr;
        if (pid == NULL) {
-               hlist_add_head(&task_pid->pid_chain,
-                               &pid_hash[type][pid_hashfn(nr)]);
                INIT_LIST_HEAD(&task_pid->pid_list);
+               hlist_add_head_rcu(&task_pid->pid_chain,
+                                  &pid_hash[type][pid_hashfn(nr)]);
        } else {
                INIT_HLIST_NODE(&task_pid->pid_chain);
-               list_add_tail(&task_pid->pid_list, &pid->pid_list);
+               list_add_tail_rcu(&task_pid->pid_list, &pid->pid_list);
        }
-       task_pid->nr = nr;
 
        return 0;
 }
@@ -170,20 +170,20 @@ static fastcall int __detach_pid(task_t *task, enum pid_type type)
 
        pid = &task->pids[type];
        if (!hlist_unhashed(&pid->pid_chain)) {
-               hlist_del(&pid->pid_chain);
 
-               if (list_empty(&pid->pid_list))
+               if (list_empty(&pid->pid_list)) {
                        nr = pid->nr;
-               else {
+                       hlist_del_rcu(&pid->pid_chain);
+               } else {
                        pid_next = list_entry(pid->pid_list.next,
                                                struct pid, pid_list);
                        /* insert next pid from pid_list to hash */
-                       hlist_add_head(&pid_next->pid_chain,
-                               &pid_hash[type][pid_hashfn(pid_next->nr)]);
+                       hlist_replace_rcu(&pid->pid_chain,
+                                         &pid_next->pid_chain);
                }
        }
 
-       list_del(&pid->pid_list);
+       list_del_rcu(&pid->pid_list);
        pid->nr = 0;
 
        return nr;
index 5287be83e3e7951740bfe4350dbc763f8d663981..2251be80cd22644bc82773ffb1cd59c6661dbc7e 100644 (file)
@@ -569,7 +569,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                                   p[1] <= '7' && p[2] == '>') {
                                        loglev_char = p[1];
                                        p += 3;
-                                       printed_len += 3;
+                                       printed_len -= 3;
                                } else {
                                        loglev_char = default_message_loglevel
                                                + '0';
@@ -584,7 +584,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
 
                                for (tp = tbuf; tp < tbuf + tlen; tp++)
                                        emit_log_char(*tp);
-                               printed_len += tlen - 3;
+                               printed_len += tlen;
                        } else {
                                if (p[0] != '<' || p[1] < '0' ||
                                   p[1] > '7' || p[2] != '>') {
@@ -592,8 +592,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                                        emit_log_char(default_message_loglevel
                                                + '0');
                                        emit_log_char('>');
+                                       printed_len += 3;
                                }
-                               printed_len += 3;
                        }
                        log_level_unknown = 0;
                        if (!*p)
index 656476eedb1bfe9a4de0286d7dd35aad8023c8d1..cceaf09ac413a4da1b9ea3d27d7655cb405e785c 100644 (file)
@@ -408,54 +408,62 @@ int ptrace_request(struct task_struct *child, long request,
        return ret;
 }
 
-#ifndef __ARCH_SYS_PTRACE
-static int ptrace_get_task_struct(long request, long pid,
-               struct task_struct **childp)
+/**
+ * ptrace_traceme  --  helper for PTRACE_TRACEME
+ *
+ * Performs checks and sets PT_PTRACED.
+ * Should be used by all ptrace implementations for PTRACE_TRACEME.
+ */
+int ptrace_traceme(void)
 {
-       struct task_struct *child;
        int ret;
 
        /*
-        * Callers use child == NULL as an indication to exit early even
-        * when the return value is 0, so make sure it is non-NULL here.
+        * Are we already being traced?
+        */
+       if (current->ptrace & PT_PTRACED)
+               return -EPERM;
+       ret = security_ptrace(current->parent, current);
+       if (ret)
+               return -EPERM;
+       /*
+        * Set the ptrace bit in the process ptrace flags.
         */
-       *childp = NULL;
+       current->ptrace |= PT_PTRACED;
+       return 0;
+}
 
-       if (request == PTRACE_TRACEME) {
-               /*
-                * Are we already being traced?
-                */
-               if (current->ptrace & PT_PTRACED)
-                       return -EPERM;
-               ret = security_ptrace(current->parent, current);
-               if (ret)
-                       return -EPERM;
-               /*
-                * Set the ptrace bit in the process ptrace flags.
-                */
-               current->ptrace |= PT_PTRACED;
-               return 0;
-       }
+/**
+ * ptrace_get_task_struct  --  grab a task struct reference for ptrace
+ * @pid:       process id to grab a task_struct reference of
+ *
+ * This function is a helper for ptrace implementations.  It checks
+ * permissions and then grabs a task struct for use of the actual
+ * ptrace implementation.
+ *
+ * Returns the task_struct for @pid or an ERR_PTR() on failure.
+ */
+struct task_struct *ptrace_get_task_struct(pid_t pid)
+{
+       struct task_struct *child;
 
        /*
-        * You may not mess with init
+        * Tracing init is not allowed.
         */
        if (pid == 1)
-               return -EPERM;
+               return ERR_PTR(-EPERM);
 
-       ret = -ESRCH;
        read_lock(&tasklist_lock);
        child = find_task_by_pid(pid);
        if (child)
                get_task_struct(child);
        read_unlock(&tasklist_lock);
        if (!child)
-               return -ESRCH;
-
-       *childp = child;
-       return 0;
+               return ERR_PTR(-ESRCH);
+       return child;
 }
 
+#ifndef __ARCH_SYS_PTRACE
 asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -465,9 +473,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
         * This lock_kernel fixes a subtle race with suid exec
         */
        lock_kernel();
-       ret = ptrace_get_task_struct(request, pid, &child);
-       if (!child)
+       if (request == PTRACE_TRACEME) {
+               ret = ptrace_traceme();
                goto out;
+       }
+
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child)) {
+               ret = PTR_ERR(child);
+               goto out;
+       }
 
        if (request == PTRACE_ATTACH) {
                ret = ptrace_attach(child);
index 48d3bce465b88e38b0715a46a5b7fe8c95820c2d..ccc45d49ce71c6180d91418584be5fc948c6b862 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/smp.h>
+#include <linux/rcupdate.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <asm/atomic.h>
@@ -45,7 +46,6 @@
 #include <linux/percpu.h>
 #include <linux/notifier.h>
 #include <linux/rcupdate.h>
-#include <linux/rcuref.h>
 #include <linux/cpu.h>
 
 /* Definition for rcupdate control block. */
@@ -61,9 +61,9 @@ struct rcu_state {
                                      /* for current batch to proceed.        */
 };
 
-static struct rcu_state rcu_state ____cacheline_maxaligned_in_smp =
+static struct rcu_state rcu_state ____cacheline_internodealigned_in_smp =
          {.lock = SPIN_LOCK_UNLOCKED, .cpumask = CPU_MASK_NONE };
-static struct rcu_state rcu_bh_state ____cacheline_maxaligned_in_smp =
+static struct rcu_state rcu_bh_state ____cacheline_internodealigned_in_smp =
          {.lock = SPIN_LOCK_UNLOCKED, .cpumask = CPU_MASK_NONE };
 
 DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L };
@@ -73,19 +73,6 @@ DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L };
 static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL};
 static int maxbatch = 10000;
 
-#ifndef __HAVE_ARCH_CMPXCHG
-/*
- * We use an array of spinlocks for the rcurefs -- similar to ones in sparc
- * 32 bit atomic_t implementations, and a hash function similar to that
- * for our refcounting needs.
- * Can't help multiprocessors which donot have cmpxchg :(
- */
-
-spinlock_t __rcuref_hash[RCUREF_HASH_SIZE] = {
-       [0 ... (RCUREF_HASH_SIZE-1)] = SPIN_LOCK_UNLOCKED
-};
-#endif
-
 /**
  * call_rcu - Queue an RCU callback for invocation after a grace period.
  * @head: structure to be used for queueing the RCU updates.
@@ -442,6 +429,36 @@ static void rcu_process_callbacks(unsigned long unused)
                                &__get_cpu_var(rcu_bh_data));
 }
 
+static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
+{
+       /* This cpu has pending rcu entries and the grace period
+        * for them has completed.
+        */
+       if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
+               return 1;
+
+       /* This cpu has no pending entries, but there are new entries */
+       if (!rdp->curlist && rdp->nxtlist)
+               return 1;
+
+       /* This cpu has finished callbacks to invoke */
+       if (rdp->donelist)
+               return 1;
+
+       /* The rcu core waits for a quiescent state from the cpu */
+       if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
+               return 1;
+
+       /* nothing to do */
+       return 0;
+}
+
+int rcu_pending(int cpu)
+{
+       return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
+               __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
+}
+
 void rcu_check_callbacks(int cpu, int user)
 {
        if (user || 
index 49fbbeff201ce7c27c72e7077b2555c31f478040..773219907dd8a96698f6c0390778538071e2e890 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/moduleparam.h>
 #include <linux/percpu.h>
 #include <linux/notifier.h>
-#include <linux/rcuref.h>
 #include <linux/cpu.h>
 #include <linux/random.h>
 #include <linux/delay.h>
 MODULE_LICENSE("GPL");
 
 static int nreaders = -1;      /* # reader threads, defaults to 4*ncpus */
-static int stat_interval = 0;  /* Interval between stats, in seconds. */
+static int stat_interval;      /* Interval between stats, in seconds. */
                                /*  Defaults to "only at end of test". */
-static int verbose = 0;                /* Print more debug info. */
+static int verbose;            /* Print more debug info. */
+static int test_no_idle_hz;    /* Test RCU's support for tickless idle CPUs. */
+static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
 
 MODULE_PARM(nreaders, "i");
 MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
@@ -59,6 +60,10 @@ MODULE_PARM(stat_interval, "i");
 MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
 MODULE_PARM(verbose, "i");
 MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
+MODULE_PARM(test_no_idle_hz, "i");
+MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
+MODULE_PARM(shuffle_interval, "i");
+MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
 #define TORTURE_FLAG "rcutorture: "
 #define PRINTK_STRING(s) \
        do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
@@ -73,6 +78,7 @@ static int nrealreaders;
 static struct task_struct *writer_task;
 static struct task_struct **reader_tasks;
 static struct task_struct *stats_task;
+static struct task_struct *shuffler_task;
 
 #define RCU_TORTURE_PIPE_LEN 10
 
@@ -103,7 +109,7 @@ atomic_t n_rcu_torture_error;
 /*
  * Allocate an element from the rcu_tortures pool.
  */
-struct rcu_torture *
+static struct rcu_torture *
 rcu_torture_alloc(void)
 {
        struct list_head *p;
@@ -376,12 +382,77 @@ rcu_torture_stats(void *arg)
        return 0;
 }
 
+static int rcu_idle_cpu;       /* Force all torture tasks off this CPU */
+
+/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
+ * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
+ */
+void rcu_torture_shuffle_tasks(void)
+{
+       cpumask_t tmp_mask = CPU_MASK_ALL;
+       int i;
+
+       lock_cpu_hotplug();
+
+       /* No point in shuffling if there is only one online CPU (ex: UP) */
+       if (num_online_cpus() == 1) {
+               unlock_cpu_hotplug();
+               return;
+       }
+
+       if (rcu_idle_cpu != -1)
+               cpu_clear(rcu_idle_cpu, tmp_mask);
+
+       set_cpus_allowed(current, tmp_mask);
+
+       if (reader_tasks != NULL) {
+               for (i = 0; i < nrealreaders; i++)
+                       if (reader_tasks[i])
+                               set_cpus_allowed(reader_tasks[i], tmp_mask);
+       }
+
+       if (writer_task)
+               set_cpus_allowed(writer_task, tmp_mask);
+
+       if (stats_task)
+               set_cpus_allowed(stats_task, tmp_mask);
+
+       if (rcu_idle_cpu == -1)
+               rcu_idle_cpu = num_online_cpus() - 1;
+       else
+               rcu_idle_cpu--;
+
+       unlock_cpu_hotplug();
+}
+
+/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
+ * system to become idle at a time and cut off its timer ticks. This is meant
+ * to test the support for such tickless idle CPU in RCU.
+ */
+static int
+rcu_torture_shuffle(void *arg)
+{
+       VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started");
+       do {
+               schedule_timeout_interruptible(shuffle_interval * HZ);
+               rcu_torture_shuffle_tasks();
+       } while (!kthread_should_stop());
+       VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
+       return 0;
+}
+
 static void
 rcu_torture_cleanup(void)
 {
        int i;
 
        fullstop = 1;
+       if (shuffler_task != NULL) {
+               VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
+               kthread_stop(shuffler_task);
+       }
+       shuffler_task = NULL;
+
        if (writer_task != NULL) {
                VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
                kthread_stop(writer_task);
@@ -430,9 +501,11 @@ rcu_torture_init(void)
                nrealreaders = nreaders;
        else
                nrealreaders = 2 * num_online_cpus();
-       printk(KERN_ALERT TORTURE_FLAG
-              "--- Start of test: nreaders=%d stat_interval=%d verbose=%d\n",
-              nrealreaders, stat_interval, verbose);
+       printk(KERN_ALERT TORTURE_FLAG "--- Start of test: nreaders=%d "
+               "stat_interval=%d verbose=%d test_no_idle_hz=%d "
+               "shuffle_interval = %d\n",
+               nrealreaders, stat_interval, verbose, test_no_idle_hz,
+               shuffle_interval);
        fullstop = 0;
 
        /* Set up the freelist. */
@@ -502,6 +575,18 @@ rcu_torture_init(void)
                        goto unwind;
                }
        }
+       if (test_no_idle_hz) {
+               rcu_idle_cpu = num_online_cpus() - 1;
+               /* Create the shuffler thread */
+               shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
+                                         "rcu_torture_shuffle");
+               if (IS_ERR(shuffler_task)) {
+                       firsterr = PTR_ERR(shuffler_task);
+                       VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
+                       shuffler_task = NULL;
+                       goto unwind;
+               }
+       }
        return 0;
 
 unwind:
index 6f46c94cc29ea4f46d79eb50b36da77208024df3..92733091154c48e0502732deac9fa2905b3b3a31 100644 (file)
@@ -176,6 +176,13 @@ static unsigned int task_timeslice(task_t *p)
 #define task_hot(p, now, sd) ((long long) ((now) - (p)->last_ran)      \
                                < (long long) (sd)->cache_hot_time)
 
+void __put_task_struct_cb(struct rcu_head *rhp)
+{
+       __put_task_struct(container_of(rhp, struct task_struct, rcu));
+}
+
+EXPORT_SYMBOL_GPL(__put_task_struct_cb);
+
 /*
  * These are the runqueue data structures:
  */
index d7611f189ef7ac33ef7610e7a92a3584f5c7028b..08aa5b263f36b01c0308c11f94428b404f5c7582 100644 (file)
@@ -329,13 +329,20 @@ void __exit_sighand(struct task_struct *tsk)
        /* Ok, we're done with the signal handlers */
        tsk->sighand = NULL;
        if (atomic_dec_and_test(&sighand->count))
-               kmem_cache_free(sighand_cachep, sighand);
+               sighand_free(sighand);
 }
 
 void exit_sighand(struct task_struct *tsk)
 {
        write_lock_irq(&tasklist_lock);
-       __exit_sighand(tsk);
+       rcu_read_lock();
+       if (tsk->sighand != NULL) {
+               struct sighand_struct *sighand = rcu_dereference(tsk->sighand);
+               spin_lock(&sighand->siglock);
+               __exit_sighand(tsk);
+               spin_unlock(&sighand->siglock);
+       }
+       rcu_read_unlock();
        write_unlock_irq(&tasklist_lock);
 }
 
@@ -345,19 +352,20 @@ void exit_sighand(struct task_struct *tsk)
 void __exit_signal(struct task_struct *tsk)
 {
        struct signal_struct * sig = tsk->signal;
-       struct sighand_struct * sighand = tsk->sighand;
+       struct sighand_struct * sighand;
 
        if (!sig)
                BUG();
        if (!atomic_read(&sig->count))
                BUG();
+       rcu_read_lock();
+       sighand = rcu_dereference(tsk->sighand);
        spin_lock(&sighand->siglock);
        posix_cpu_timers_exit(tsk);
        if (atomic_dec_and_test(&sig->count)) {
                posix_cpu_timers_exit_group(tsk);
-               if (tsk == sig->curr_target)
-                       sig->curr_target = next_thread(tsk);
                tsk->signal = NULL;
+               __exit_sighand(tsk);
                spin_unlock(&sighand->siglock);
                flush_sigqueue(&sig->shared_pending);
        } else {
@@ -389,9 +397,11 @@ void __exit_signal(struct task_struct *tsk)
                sig->nvcsw += tsk->nvcsw;
                sig->nivcsw += tsk->nivcsw;
                sig->sched_time += tsk->sched_time;
+               __exit_sighand(tsk);
                spin_unlock(&sighand->siglock);
                sig = NULL;     /* Marker for below.  */
        }
+       rcu_read_unlock();
        clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
        flush_sigqueue(&tsk->pending);
        if (sig) {
@@ -608,6 +618,33 @@ void signal_wake_up(struct task_struct *t, int resume)
                kick_process(t);
 }
 
+/*
+ * Remove signals in mask from the pending set and queue.
+ * Returns 1 if any signals were found.
+ *
+ * All callers must be holding the siglock.
+ *
+ * This version takes a sigset mask and looks at all signals,
+ * not just those in the first mask word.
+ */
+static int rm_from_queue_full(sigset_t *mask, struct sigpending *s)
+{
+       struct sigqueue *q, *n;
+       sigset_t m;
+
+       sigandsets(&m, mask, &s->signal);
+       if (sigisemptyset(&m))
+               return 0;
+
+       signandsets(&s->signal, &s->signal, mask);
+       list_for_each_entry_safe(q, n, &s->list, list) {
+               if (sigismember(mask, q->info.si_signo)) {
+                       list_del_init(&q->list);
+                       __sigqueue_free(q);
+               }
+       }
+       return 1;
+}
 /*
  * Remove signals in mask from the pending set and queue.
  * Returns 1 if any signals were found.
@@ -1080,18 +1117,29 @@ void zap_other_threads(struct task_struct *p)
 }
 
 /*
- * Must be called with the tasklist_lock held for reading!
+ * Must be called under rcu_read_lock() or with tasklist_lock read-held.
  */
 int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
        unsigned long flags;
+       struct sighand_struct *sp;
        int ret;
 
+retry:
        ret = check_kill_permission(sig, info, p);
-       if (!ret && sig && p->sighand) {
-               spin_lock_irqsave(&p->sighand->siglock, flags);
+       if (!ret && sig && (sp = rcu_dereference(p->sighand))) {
+               spin_lock_irqsave(&sp->siglock, flags);
+               if (p->sighand != sp) {
+                       spin_unlock_irqrestore(&sp->siglock, flags);
+                       goto retry;
+               }
+               if ((atomic_read(&sp->count) == 0) ||
+                               (atomic_read(&p->usage) == 0)) {
+                       spin_unlock_irqrestore(&sp->siglock, flags);
+                       return -ESRCH;
+               }
                ret = __group_send_sig_info(sig, info, p);
-               spin_unlock_irqrestore(&p->sighand->siglock, flags);
+               spin_unlock_irqrestore(&sp->siglock, flags);
        }
 
        return ret;
@@ -1136,14 +1184,21 @@ int
 kill_proc_info(int sig, struct siginfo *info, pid_t pid)
 {
        int error;
+       int acquired_tasklist_lock = 0;
        struct task_struct *p;
 
-       read_lock(&tasklist_lock);
+       rcu_read_lock();
+       if (unlikely(sig_kernel_stop(sig) || sig == SIGCONT)) {
+               read_lock(&tasklist_lock);
+               acquired_tasklist_lock = 1;
+       }
        p = find_task_by_pid(pid);
        error = -ESRCH;
        if (p)
                error = group_send_sig_info(sig, info, p);
-       read_unlock(&tasklist_lock);
+       if (unlikely(acquired_tasklist_lock))
+               read_unlock(&tasklist_lock);
+       rcu_read_unlock();
        return error;
 }
 
@@ -1163,8 +1218,7 @@ int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid,
                ret = -ESRCH;
                goto out_unlock;
        }
-       if ((!info || ((unsigned long)info != 1 &&
-                       (unsigned long)info != 2 && SI_FROMUSER(info)))
+       if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
            && (euid != p->suid) && (euid != p->uid)
            && (uid != p->suid) && (uid != p->uid)) {
                ret = -EPERM;
@@ -1355,16 +1409,54 @@ send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
 {
        unsigned long flags;
        int ret = 0;
+       struct sighand_struct *sh;
 
        BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
-       read_lock(&tasklist_lock);
+
+       /*
+        * The rcu based delayed sighand destroy makes it possible to
+        * run this without tasklist lock held. The task struct itself
+        * cannot go away as create_timer did get_task_struct().
+        *
+        * We return -1, when the task is marked exiting, so
+        * posix_timer_event can redirect it to the group leader
+        */
+       rcu_read_lock();
 
        if (unlikely(p->flags & PF_EXITING)) {
                ret = -1;
                goto out_err;
        }
 
-       spin_lock_irqsave(&p->sighand->siglock, flags);
+retry:
+       sh = rcu_dereference(p->sighand);
+
+       spin_lock_irqsave(&sh->siglock, flags);
+       if (p->sighand != sh) {
+               /* We raced with exec() in a multithreaded process... */
+               spin_unlock_irqrestore(&sh->siglock, flags);
+               goto retry;
+       }
+
+       /*
+        * We do the check here again to handle the following scenario:
+        *
+        * CPU 0                CPU 1
+        * send_sigqueue
+        * check PF_EXITING
+        * interrupt            exit code running
+        *                      __exit_signal
+        *                      lock sighand->siglock
+        *                      unlock sighand->siglock
+        * lock sh->siglock
+        * add(tsk->pending)    flush_sigqueue(tsk->pending)
+        *
+        */
+
+       if (unlikely(p->flags & PF_EXITING)) {
+               ret = -1;
+               goto out;
+       }
 
        if (unlikely(!list_empty(&q->list))) {
                /*
@@ -1388,9 +1480,9 @@ send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
                signal_wake_up(p, sig == SIGKILL);
 
 out:
-       spin_unlock_irqrestore(&p->sighand->siglock, flags);
+       spin_unlock_irqrestore(&sh->siglock, flags);
 out_err:
-       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 
        return ret;
 }
@@ -1402,7 +1494,9 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
        int ret = 0;
 
        BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
+
        read_lock(&tasklist_lock);
+       /* Since it_lock is held, p->sighand cannot be NULL. */
        spin_lock_irqsave(&p->sighand->siglock, flags);
        handle_stop_signal(sig, p);
 
@@ -1436,7 +1530,7 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
 out:
        spin_unlock_irqrestore(&p->sighand->siglock, flags);
        read_unlock(&tasklist_lock);
-       return(ret);
+       return ret;
 }
 
 /*
@@ -2338,6 +2432,7 @@ int
 do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact)
 {
        struct k_sigaction *k;
+       sigset_t mask;
 
        if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig)))
                return -EINVAL;
@@ -2385,9 +2480,11 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact)
                        *k = *act;
                        sigdelsetmask(&k->sa.sa_mask,
                                      sigmask(SIGKILL) | sigmask(SIGSTOP));
-                       rm_from_queue(sigmask(sig), &t->signal->shared_pending);
+                       sigemptyset(&mask);
+                       sigaddset(&mask, sig);
+                       rm_from_queue_full(&mask, &t->signal->shared_pending);
                        do {
-                               rm_from_queue(sigmask(sig), &t->pending);
+                               rm_from_queue_full(&mask, &t->pending);
                                recalc_sigpending_tsk(t);
                                t = next_thread(t);
                        } while (t != current);
index eecf84526afeca15c7e82894c5c3e898239fa062..b6941e06d5d507a141a135294c8d29e62ddd59d3 100644 (file)
@@ -489,6 +489,12 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
                        magic2 != LINUX_REBOOT_MAGIC2C))
                return -EINVAL;
 
+       /* Instead of trying to make the power_off code look like
+        * halt when pm_power_off is not set do it the easy way.
+        */
+       if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
+               cmd = LINUX_REBOOT_CMD_HALT;
+
        lock_kernel();
        switch (cmd) {
        case LINUX_REBOOT_CMD_RESTART:
@@ -1084,10 +1090,11 @@ asmlinkage long sys_times(struct tms __user * tbuf)
 asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
 {
        struct task_struct *p;
+       struct task_struct *group_leader = current->group_leader;
        int err = -EINVAL;
 
        if (!pid)
-               pid = current->pid;
+               pid = group_leader->pid;
        if (!pgid)
                pgid = pid;
        if (pgid < 0)
@@ -1107,16 +1114,16 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
        if (!thread_group_leader(p))
                goto out;
 
-       if (p->parent == current || p->real_parent == current) {
+       if (p->real_parent == group_leader) {
                err = -EPERM;
-               if (p->signal->session != current->signal->session)
+               if (p->signal->session != group_leader->signal->session)
                        goto out;
                err = -EACCES;
                if (p->did_exec)
                        goto out;
        } else {
                err = -ESRCH;
-               if (p != current)
+               if (p != group_leader)
                        goto out;
        }
 
@@ -1128,7 +1135,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
                struct task_struct *p;
 
                do_each_task_pid(pgid, PIDTYPE_PGID, p) {
-                       if (p->signal->session == current->signal->session)
+                       if (p->signal->session == group_leader->signal->session)
                                goto ok_pgid;
                } while_each_task_pid(pgid, PIDTYPE_PGID, p);
                goto out;
@@ -1208,24 +1215,22 @@ asmlinkage long sys_getsid(pid_t pid)
 
 asmlinkage long sys_setsid(void)
 {
+       struct task_struct *group_leader = current->group_leader;
        struct pid *pid;
        int err = -EPERM;
 
-       if (!thread_group_leader(current))
-               return -EINVAL;
-
        down(&tty_sem);
        write_lock_irq(&tasklist_lock);
 
-       pid = find_pid(PIDTYPE_PGID, current->pid);
+       pid = find_pid(PIDTYPE_PGID, group_leader->pid);
        if (pid)
                goto out;
 
-       current->signal->leader = 1;
-       __set_special_pids(current->pid, current->pid);
-       current->signal->tty = NULL;
-       current->signal->tty_old_pgrp = 0;
-       err = process_group(current);
+       group_leader->signal->leader = 1;
+       __set_special_pids(group_leader->pid, group_leader->pid);
+       group_leader->signal->tty = NULL;
+       group_leader->signal->tty_old_pgrp = 0;
+       err = process_group(group_leader);
 out:
        write_unlock_irq(&tasklist_lock);
        up(&tty_sem);
@@ -1687,7 +1692,10 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
        if (unlikely(!p->signal))
                return;
 
+       utime = stime = cputime_zero;
+
        switch (who) {
+               case RUSAGE_BOTH:
                case RUSAGE_CHILDREN:
                        spin_lock_irqsave(&p->sighand->siglock, flags);
                        utime = p->signal->cutime;
@@ -1697,22 +1705,11 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                        r->ru_minflt = p->signal->cmin_flt;
                        r->ru_majflt = p->signal->cmaj_flt;
                        spin_unlock_irqrestore(&p->sighand->siglock, flags);
-                       cputime_to_timeval(utime, &r->ru_utime);
-                       cputime_to_timeval(stime, &r->ru_stime);
-                       break;
+
+                       if (who == RUSAGE_CHILDREN)
+                               break;
+
                case RUSAGE_SELF:
-                       spin_lock_irqsave(&p->sighand->siglock, flags);
-                       utime = stime = cputime_zero;
-                       goto sum_group;
-               case RUSAGE_BOTH:
-                       spin_lock_irqsave(&p->sighand->siglock, flags);
-                       utime = p->signal->cutime;
-                       stime = p->signal->cstime;
-                       r->ru_nvcsw = p->signal->cnvcsw;
-                       r->ru_nivcsw = p->signal->cnivcsw;
-                       r->ru_minflt = p->signal->cmin_flt;
-                       r->ru_majflt = p->signal->cmaj_flt;
-               sum_group:
                        utime = cputime_add(utime, p->signal->utime);
                        stime = cputime_add(stime, p->signal->stime);
                        r->ru_nvcsw += p->signal->nvcsw;
@@ -1729,13 +1726,14 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                                r->ru_majflt += t->maj_flt;
                                t = next_thread(t);
                        } while (t != p);
-                       spin_unlock_irqrestore(&p->sighand->siglock, flags);
-                       cputime_to_timeval(utime, &r->ru_utime);
-                       cputime_to_timeval(stime, &r->ru_stime);
                        break;
+
                default:
                        BUG();
        }
+
+       cputime_to_timeval(utime, &r->ru_utime);
+       cputime_to_timeval(stime, &r->ru_stime);
 }
 
 int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
index 1ab2370e2efaee04f62334ae98a778ed3bbf9398..17313b99e53d2539789ddcf2dae5e30c45be0780 100644 (file)
@@ -82,6 +82,28 @@ cond_syscall(compat_sys_socketcall);
 cond_syscall(sys_inotify_init);
 cond_syscall(sys_inotify_add_watch);
 cond_syscall(sys_inotify_rm_watch);
+cond_syscall(sys_migrate_pages);
+cond_syscall(sys_chown16);
+cond_syscall(sys_fchown16);
+cond_syscall(sys_getegid16);
+cond_syscall(sys_geteuid16);
+cond_syscall(sys_getgid16);
+cond_syscall(sys_getgroups16);
+cond_syscall(sys_getresgid16);
+cond_syscall(sys_getresuid16);
+cond_syscall(sys_getuid16);
+cond_syscall(sys_lchown16);
+cond_syscall(sys_setfsgid16);
+cond_syscall(sys_setfsuid16);
+cond_syscall(sys_setgid16);
+cond_syscall(sys_setgroups16);
+cond_syscall(sys_setregid16);
+cond_syscall(sys_setresgid16);
+cond_syscall(sys_setresuid16);
+cond_syscall(sys_setreuid16);
+cond_syscall(sys_setuid16);
+cond_syscall(sys_vm86old);
+cond_syscall(sys_vm86);
 
 /* arch-specific weak syscall entries */
 cond_syscall(sys_pciconfig_read);
@@ -90,3 +112,5 @@ cond_syscall(sys_pciconfig_iobase);
 cond_syscall(sys32_ipc);
 cond_syscall(sys32_sysctl);
 cond_syscall(ppc_rtas);
+cond_syscall(sys_spu_run);
+cond_syscall(sys_spu_create);
index a85047bb5739f97763345bc9ef047e0fe043f33c..03b0598f2369d2e6cd0d67493f161c675b87b954 100644 (file)
@@ -68,6 +68,8 @@ extern int min_free_kbytes;
 extern int printk_ratelimit_jiffies;
 extern int printk_ratelimit_burst;
 extern int pid_max_min, pid_max_max;
+extern int sysctl_drop_caches;
+extern int percpu_pagelist_fraction;
 
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
 int unknown_nmi_panic;
@@ -78,6 +80,7 @@ extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *,
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
 static int minolduid;
+static int min_percpu_pagelist_fract = 8;
 
 static int ngroups_max = NGROUPS_MAX;
 
@@ -774,6 +777,15 @@ static ctl_table vm_table[] = {
                .proc_handler   = &lowmem_reserve_ratio_sysctl_handler,
                .strategy       = &sysctl_intvec,
        },
+       {
+               .ctl_name       = VM_DROP_PAGECACHE,
+               .procname       = "drop_caches",
+               .data           = &sysctl_drop_caches,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = drop_caches_sysctl_handler,
+               .strategy       = &sysctl_intvec,
+       },
        {
                .ctl_name       = VM_MIN_FREE_KBYTES,
                .procname       = "min_free_kbytes",
@@ -784,6 +796,16 @@ static ctl_table vm_table[] = {
                .strategy       = &sysctl_intvec,
                .extra1         = &zero,
        },
+       {
+               .ctl_name       = VM_PERCPU_PAGELIST_FRACTION,
+               .procname       = "percpu_pagelist_fraction",
+               .data           = &percpu_pagelist_fraction,
+               .maxlen         = sizeof(percpu_pagelist_fraction),
+               .mode           = 0644,
+               .proc_handler   = &percpu_pagelist_fraction_sysctl_handler,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_percpu_pagelist_fract,
+       },
 #ifdef CONFIG_MMU
        {
                .ctl_name       = VM_MAX_MAP_COUNT,
index fd74268d8663ca8734814f175c1f0735d020d7a0..074b4bd5cfd8b62a9b92555514455a4a06f0416e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/posix-timers.h>
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
+#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
index 2bd5aee1c7369af14c8f8ba71a9715ad6f03346b..82c4fa70595cce5c929b8e431047d882749d0227 100644 (file)
@@ -29,7 +29,8 @@
 #include <linux/kthread.h>
 
 /*
- * The per-CPU workqueue (if single thread, we always use cpu 0's).
+ * The per-CPU workqueue (if single thread, we always use the first
+ * possible cpu).
  *
  * The sequence counters are for flush_scheduled_work().  It wants to wait
  * until until all currently-scheduled works are completed, but it doesn't
@@ -69,6 +70,8 @@ struct workqueue_struct {
 static DEFINE_SPINLOCK(workqueue_lock);
 static LIST_HEAD(workqueues);
 
+static int singlethread_cpu;
+
 /* If it's single threaded, it isn't in the list of workqueues. */
 static inline int is_single_threaded(struct workqueue_struct *wq)
 {
@@ -102,7 +105,7 @@ int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
 
        if (!test_and_set_bit(0, &work->pending)) {
                if (unlikely(is_single_threaded(wq)))
-                       cpu = any_online_cpu(cpu_online_map);
+                       cpu = singlethread_cpu;
                BUG_ON(!list_empty(&work->entry));
                __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
                ret = 1;
@@ -118,7 +121,7 @@ static void delayed_work_timer_fn(unsigned long __data)
        int cpu = smp_processor_id();
 
        if (unlikely(is_single_threaded(wq)))
-               cpu = any_online_cpu(cpu_online_map);
+               cpu = singlethread_cpu;
 
        __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
 }
@@ -267,7 +270,7 @@ void fastcall flush_workqueue(struct workqueue_struct *wq)
 
        if (is_single_threaded(wq)) {
                /* Always use first cpu's area. */
-               flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, any_online_cpu(cpu_online_map)));
+               flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, singlethread_cpu));
        } else {
                int cpu;
 
@@ -315,12 +318,17 @@ struct workqueue_struct *__create_workqueue(const char *name,
                return NULL;
 
        wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
+       if (!wq->cpu_wq) {
+               kfree(wq);
+               return NULL;
+       }
+
        wq->name = name;
        /* We don't need the distraction of CPUs appearing and vanishing. */
        lock_cpu_hotplug();
        if (singlethread) {
                INIT_LIST_HEAD(&wq->list);
-               p = create_workqueue_thread(wq, any_online_cpu(cpu_online_map));
+               p = create_workqueue_thread(wq, singlethread_cpu);
                if (!p)
                        destroy = 1;
                else
@@ -374,7 +382,7 @@ void destroy_workqueue(struct workqueue_struct *wq)
        /* We don't need the distraction of CPUs appearing and vanishing. */
        lock_cpu_hotplug();
        if (is_single_threaded(wq))
-               cleanup_workqueue_thread(wq, any_online_cpu(cpu_online_map));
+               cleanup_workqueue_thread(wq, singlethread_cpu);
        else {
                for_each_online_cpu(cpu)
                        cleanup_workqueue_thread(wq, cpu);
@@ -419,6 +427,25 @@ int schedule_delayed_work_on(int cpu,
        return ret;
 }
 
+int schedule_on_each_cpu(void (*func) (void *info), void *info)
+{
+       int cpu;
+       struct work_struct *work;
+
+       work = kmalloc(NR_CPUS * sizeof(struct work_struct), GFP_KERNEL);
+
+       if (!work)
+               return -ENOMEM;
+       for_each_online_cpu(cpu) {
+               INIT_WORK(work + cpu, func, info);
+               __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu),
+                               work + cpu);
+       }
+       flush_workqueue(keventd_wq);
+       kfree(work);
+       return 0;
+}
+
 void flush_scheduled_work(void)
 {
        flush_workqueue(keventd_wq);
@@ -543,6 +570,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
 
 void init_workqueues(void)
 {
+       singlethread_cpu = first_cpu(cpu_possible_map);
        hotcpu_notifier(workqueue_cpu_callback, 0);
        keventd_wq = create_workqueue("events");
        BUG_ON(!keventd_wq);
index 80598cfd728c39744c5841e0e5d0bbd078833dba..c48260fb8fd910add057a6d94f5ecc7b14d4fa2f 100644 (file)
@@ -79,7 +79,7 @@ config SCHEDSTATS
 
 config DEBUG_SLAB
        bool "Debug memory allocations"
-       depends on DEBUG_KERNEL
+       depends on DEBUG_KERNEL && SLAB
        help
          Say Y here to have the kernel do limited verification on memory
          allocation as well as poisoning memory on free to catch use of freed
index 23d3b1147fe93aa282a2d772493c64dde9d4dd50..48e708381d44d0fb4ce1810aa24fc819ceaf7e2d 100644 (file)
@@ -519,7 +519,7 @@ EXPORT_SYMBOL(bitmap_parselist);
  *
  * Map the bit at position @pos in @buf (of length @bits) to the
  * ordinal of which set bit it is.  If it is not set or if @pos
- * is not a valid bit position, map to zero (0).
+ * is not a valid bit position, map to -1.
  *
  * If for example, just bits 4 through 7 are set in @buf, then @pos
  * values 4 through 7 will get mapped to 0 through 3, respectively,
@@ -531,18 +531,19 @@ EXPORT_SYMBOL(bitmap_parselist);
  */
 static int bitmap_pos_to_ord(const unsigned long *buf, int pos, int bits)
 {
-       int ord = 0;
+       int i, ord;
 
-       if (pos >= 0 && pos < bits) {
-               int i;
+       if (pos < 0 || pos >= bits || !test_bit(pos, buf))
+               return -1;
 
-               for (i = find_first_bit(buf, bits);
-                    i < pos;
-                    i = find_next_bit(buf, bits, i + 1))
-                       ord++;
-               if (i > pos)
-                       ord = 0;
+       i = find_first_bit(buf, bits);
+       ord = 0;
+       while (i < pos) {
+               i = find_next_bit(buf, bits, i + 1);
+               ord++;
        }
+       BUG_ON(i != pos);
+
        return ord;
 }
 
@@ -553,11 +554,12 @@ static int bitmap_pos_to_ord(const unsigned long *buf, int pos, int bits)
  *     @bits: number of valid bit positions in @buf
  *
  * Map the ordinal offset of bit @ord in @buf to its position in @buf.
- * If @ord is not the ordinal offset of a set bit in @buf, map to zero (0).
+ * Value of @ord should be in range 0 <= @ord < weight(buf), else
+ * results are undefined.
  *
  * If for example, just bits 4 through 7 are set in @buf, then @ord
  * values 0 through 3 will get mapped to 4 through 7, respectively,
- * and all other @ord valuds will get mapped to 0.  When @ord value 3
+ * and all other @ord values return undefined values.  When @ord value 3
  * gets mapped to (returns) @pos value 7 in this example, that means
  * that the 3rd set bit (starting with 0th) is at position 7 in @buf.
  *
@@ -583,8 +585,8 @@ static int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits)
 
 /**
  * bitmap_remap - Apply map defined by a pair of bitmaps to another bitmap
- *     @src: subset to be remapped
  *     @dst: remapped result
+ *     @src: subset to be remapped
  *     @old: defines domain of map
  *     @new: defines range of map
  *     @bits: number of bits in each of these bitmaps
@@ -596,49 +598,42 @@ static int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits)
  * weight of @old, map the position of the n-th set bit in @old to
  * the position of the m-th set bit in @new, where m == n % w.
  *
- * If either of the @old and @new bitmaps are empty, or if@src and @dst
- * point to the same location, then this routine does nothing.
+ * If either of the @old and @new bitmaps are empty, or if @src and
+ * @dst point to the same location, then this routine copies @src
+ * to @dst.
  *
- * The positions of unset bits in @old are mapped to the position of
- * the first set bit in @new.
+ * The positions of unset bits in @old are mapped to themselves
+ * (the identify map).
  *
  * Apply the above specified mapping to @src, placing the result in
  * @dst, clearing any bits previously set in @dst.
  *
- * The resulting value of @dst will have either the same weight as
- * @src, or less weight in the general case that the mapping wasn't
- * injective due to the weight of @new being less than that of @old.
- * The resulting value of @dst will never have greater weight than
- * that of @src, except perhaps in the case that one of the above
- * conditions was not met and this routine just returned.
- *
  * For example, lets say that @old has bits 4 through 7 set, and
  * @new has bits 12 through 15 set.  This defines the mapping of bit
  * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other
- * bit positions to 12 (the first set bit in @new.  So if say @src
- * comes into this routine with bits 1, 5 and 7 set, then @dst should
- * leave with bits 12, 13 and 15 set.
+ * bit positions unchanged.  So if say @src comes into this routine
+ * with bits 1, 5 and 7 set, then @dst should leave with bits 1,
+ * 13 and 15 set.
  */
 void bitmap_remap(unsigned long *dst, const unsigned long *src,
                const unsigned long *old, const unsigned long *new,
                int bits)
 {
-       int s;
+       int oldbit, w;
 
-       if (bitmap_weight(old, bits) == 0)
-               return;
-       if (bitmap_weight(new, bits) == 0)
-               return;
        if (dst == src)         /* following doesn't handle inplace remaps */
                return;
-
        bitmap_zero(dst, bits);
-       for (s = find_first_bit(src, bits);
-            s < bits;
-            s = find_next_bit(src, bits, s + 1)) {
-               int x = bitmap_pos_to_ord(old, s, bits);
-               int y = bitmap_ord_to_pos(new, x, bits);
-               set_bit(y, dst);
+
+       w = bitmap_weight(new, bits);
+       for (oldbit = find_first_bit(src, bits);
+            oldbit < bits;
+            oldbit = find_next_bit(src, bits, oldbit + 1)) {
+               int n = bitmap_pos_to_ord(old, oldbit, bits);
+               if (n < 0 || w == 0)
+                       set_bit(oldbit, dst);   /* identity map */
+               else
+                       set_bit(bitmap_ord_to_pos(new, n % w, bits), dst);
        }
 }
 EXPORT_SYMBOL(bitmap_remap);
@@ -657,8 +652,8 @@ EXPORT_SYMBOL(bitmap_remap);
  * weight of @old, map the position of the n-th set bit in @old to
  * the position of the m-th set bit in @new, where m == n % w.
  *
- * The positions of unset bits in @old are mapped to the position of
- * the first set bit in @new.
+ * The positions of unset bits in @old are mapped to themselves
+ * (the identify map).
  *
  * Apply the above specified mapping to bit position @oldbit, returning
  * the new bit position.
@@ -666,14 +661,18 @@ EXPORT_SYMBOL(bitmap_remap);
  * For example, lets say that @old has bits 4 through 7 set, and
  * @new has bits 12 through 15 set.  This defines the mapping of bit
  * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other
- * bit positions to 12 (the first set bit in @new.  So if say @oldbit
- * is 5, then this routine returns 13.
+ * bit positions unchanged.  So if say @oldbit is 5, then this routine
+ * returns 13.
  */
 int bitmap_bitremap(int oldbit, const unsigned long *old,
                                const unsigned long *new, int bits)
 {
-       int x = bitmap_pos_to_ord(old, oldbit, bits);
-       return bitmap_ord_to_pos(new, x, bits);
+       int w = bitmap_weight(new, bits);
+       int n = bitmap_pos_to_ord(old, oldbit, bits);
+       if (n < 0 || w == 0)
+               return oldbit;
+       else
+               return bitmap_ord_to_pos(new, n % w, bits);
 }
 EXPORT_SYMBOL(bitmap_bitremap);
 
index 305a9663aee39aba26532082319433e0a4e9ae33..a65c314555416d9f1ea262455d1da313e1959902 100644 (file)
@@ -1,47 +1,11 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
-#include <asm/system.h>
 
-#ifdef __HAVE_ARCH_CMPXCHG
 /*
  * This is an implementation of the notion of "decrement a
  * reference count, and return locked if it decremented to zero".
  *
- * This implementation can be used on any architecture that
- * has a cmpxchg, and where atomic->value is an int holding
- * the value of the atomic (i.e. the high bits aren't used
- * for a lock or anything like that).
- */
-int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
-{
-       int counter;
-       int newcount;
-
-       for (;;) {
-               counter = atomic_read(atomic);
-               newcount = counter - 1;
-               if (!newcount)
-                       break;          /* do it the slow way */
-
-               newcount = cmpxchg(&atomic->counter, counter, newcount);
-               if (newcount == counter)
-                       return 0;
-       }
-
-       spin_lock(lock);
-       if (atomic_dec_and_test(atomic))
-               return 1;
-       spin_unlock(lock);
-       return 0;
-}
-#else
-/*
- * This is an architecture-neutral, but slow,
- * implementation of the notion of "decrement
- * a reference count, and return locked if it
- * decremented to zero".
- *
  * NOTE NOTE NOTE! This is _not_ equivalent to
  *
  *     if (atomic_dec_and_test(&atomic)) {
@@ -52,21 +16,20 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
  *
  * because the spin-lock and the decrement must be
  * "atomic".
- *
- * This slow version gets the spinlock unconditionally,
- * and releases it if it isn't needed. Architectures
- * are encouraged to come up with better approaches,
- * this is trivially done efficiently using a load-locked
- * store-conditional approach, for example.
  */
 int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
+#ifdef CONFIG_SMP
+       /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
+       if (atomic_add_unless(atomic, -1, 1))
+               return 0;
+#endif
+       /* Otherwise do it the slow way */
        spin_lock(lock);
        if (atomic_dec_and_test(atomic))
                return 1;
        spin_unlock(lock);
        return 0;
 }
-#endif
 
 EXPORT_SYMBOL(_atomic_dec_and_lock);
index d08302d2a42cbe5973b55a6370e86f272f32ef34..c05b4b19cf6cac90e407eac98e870130bbb3e66a 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/module.h>
 
 int find_next_bit(const unsigned long *addr, int size, int offset)
 {
@@ -53,3 +54,5 @@ int find_next_bit(const unsigned long *addr, int size, int offset)
 
        return offset;
 }
+
+EXPORT_SYMBOL(find_next_bit);
index 88511c3805ad77fc9515b7a75bdc52e09a6393df..c0bd4a91480387e0c22d43b65d7f75fc2a522188 100644 (file)
@@ -137,18 +137,31 @@ out:
 
 static inline void tag_set(struct radix_tree_node *node, int tag, int offset)
 {
-       if (!test_bit(offset, &node->tags[tag][0]))
-               __set_bit(offset, &node->tags[tag][0]);
+       __set_bit(offset, node->tags[tag]);
 }
 
 static inline void tag_clear(struct radix_tree_node *node, int tag, int offset)
 {
-       __clear_bit(offset, &node->tags[tag][0]);
+       __clear_bit(offset, node->tags[tag]);
 }
 
 static inline int tag_get(struct radix_tree_node *node, int tag, int offset)
 {
-       return test_bit(offset, &node->tags[tag][0]);
+       return test_bit(offset, node->tags[tag]);
+}
+
+/*
+ * Returns 1 if any slot in the node has this tag set.
+ * Otherwise returns 0.
+ */
+static inline int any_tag_set(struct radix_tree_node *node, int tag)
+{
+       int idx;
+       for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
+               if (node->tags[tag][idx])
+                       return 1;
+       }
+       return 0;
 }
 
 /*
@@ -185,15 +198,9 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
         * into the newly-pushed top-level node(s)
         */
        for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
-               int idx;
-
                tags[tag] = 0;
-               for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
-                       if (root->rnode->tags[tag][idx]) {
-                               tags[tag] = 1;
-                               break;
-                       }
-               }
+               if (any_tag_set(root->rnode, tag))
+                       tags[tag] = 1;
        }
 
        do {
@@ -246,7 +253,7 @@ int radix_tree_insert(struct radix_tree_root *root,
        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 
        offset = 0;                     /* uninitialised var warning */
-       while (height > 0) {
+       do {
                if (slot == NULL) {
                        /* Have to add a child node.  */
                        if (!(slot = radix_tree_node_alloc(root)))
@@ -264,18 +271,16 @@ int radix_tree_insert(struct radix_tree_root *root,
                slot = node->slots[offset];
                shift -= RADIX_TREE_MAP_SHIFT;
                height--;
-       }
+       } while (height > 0);
 
        if (slot != NULL)
                return -EEXIST;
 
-       if (node) {
-               node->count++;
-               node->slots[offset] = item;
-               BUG_ON(tag_get(node, 0, offset));
-               BUG_ON(tag_get(node, 1, offset));
-       } else
-               root->rnode = item;
+       BUG_ON(!node);
+       node->count++;
+       node->slots[offset] = item;
+       BUG_ON(tag_get(node, 0, offset));
+       BUG_ON(tag_get(node, 1, offset));
 
        return 0;
 }
@@ -367,7 +372,8 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
                int offset;
 
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               tag_set(slot, tag, offset);
+               if (!tag_get(slot, tag, offset))
+                       tag_set(slot, tag, offset);
                slot = slot->slots[offset];
                BUG_ON(slot == NULL);
                shift -= RADIX_TREE_MAP_SHIFT;
@@ -427,13 +433,11 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
                goto out;
 
        do {
-               int idx;
-
+               if (!tag_get(pathp->node, tag, pathp->offset))
+                       goto out;
                tag_clear(pathp->node, tag, pathp->offset);
-               for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
-                       if (pathp->node->tags[tag][idx])
-                               goto out;
-               }
+               if (any_tag_set(pathp->node, tag))
+                       goto out;
                pathp--;
        } while (pathp->node);
 out:
@@ -673,6 +677,29 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
 }
 EXPORT_SYMBOL(radix_tree_gang_lookup_tag);
 
+/**
+ *     radix_tree_shrink    -    shrink height of a radix tree to minimal
+ *     @root           radix tree root
+ */
+static inline void radix_tree_shrink(struct radix_tree_root *root)
+{
+       /* try to shrink tree height */
+       while (root->height > 1 &&
+                       root->rnode->count == 1 &&
+                       root->rnode->slots[0]) {
+               struct radix_tree_node *to_free = root->rnode;
+
+               root->rnode = to_free->slots[0];
+               root->height--;
+               /* must only free zeroed nodes into the slab */
+               tag_clear(to_free, 0, 0);
+               tag_clear(to_free, 1, 0);
+               to_free->slots[0] = NULL;
+               to_free->count = 0;
+               radix_tree_node_free(to_free);
+       }
+}
+
 /**
  *     radix_tree_delete    -    delete an item from a radix tree
  *     @root:          radix tree root
@@ -691,6 +718,8 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
        void *ret = NULL;
        char tags[RADIX_TREE_TAGS];
        int nr_cleared_tags;
+       int tag;
+       int offset;
 
        height = root->height;
        if (index > radix_tree_maxindex(height))
@@ -701,16 +730,14 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
        slot = root->rnode;
 
        for ( ; height > 0; height--) {
-               int offset;
-
                if (slot == NULL)
                        goto out;
 
+               pathp++;
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               pathp[1].offset = offset;
-               pathp[1].node = slot;
+               pathp->offset = offset;
+               pathp->node = slot;
                slot = slot->slots[offset];
-               pathp++;
                shift -= RADIX_TREE_MAP_SHIFT;
        }
 
@@ -723,35 +750,39 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
        /*
         * Clear all tags associated with the just-deleted item
         */
-       memset(tags, 0, sizeof(tags));
-       do {
-               int tag;
+       nr_cleared_tags = 0;
+       for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
+               if (tag_get(pathp->node, tag, pathp->offset)) {
+                       tag_clear(pathp->node, tag, pathp->offset);
+                       tags[tag] = 0;
+                       nr_cleared_tags++;
+               } else
+                       tags[tag] = 1;
+       }
 
-               nr_cleared_tags = RADIX_TREE_TAGS;
+       for (pathp--; nr_cleared_tags && pathp->node; pathp--) {
                for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
-                       int idx;
-
                        if (tags[tag])
                                continue;
 
                        tag_clear(pathp->node, tag, pathp->offset);
-
-                       for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
-                               if (pathp->node->tags[tag][idx]) {
-                                       tags[tag] = 1;
-                                       nr_cleared_tags--;
-                                       break;
-                               }
+                       if (any_tag_set(pathp->node, tag)) {
+                               tags[tag] = 1;
+                               nr_cleared_tags--;
                        }
                }
-               pathp--;
-       } while (pathp->node && nr_cleared_tags);
+       }
 
        /* Now free the nodes we do not need anymore */
        for (pathp = orig_pathp; pathp->node; pathp--) {
                pathp->node->slots[pathp->offset] = NULL;
-               if (--pathp->node->count)
+               pathp->node->count--;
+
+               if (pathp->node->count) {
+                       if (pathp->node == root->rnode)
+                               radix_tree_shrink(root);
                        goto out;
+               }
 
                /* Node with zero slots in use so free it */
                radix_tree_node_free(pathp->node);
@@ -770,15 +801,11 @@ EXPORT_SYMBOL(radix_tree_delete);
  */
 int radix_tree_tagged(struct radix_tree_root *root, int tag)
 {
-       int idx;
-
-       if (!root->rnode)
-               return 0;
-       for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
-               if (root->rnode->tags[tag][idx])
-                       return 1;
-       }
-       return 0;
+       struct radix_tree_node *rnode;
+       rnode = root->rnode;
+       if (!rnode)
+               return 0;
+       return any_tag_set(rnode, tag);
 }
 EXPORT_SYMBOL(radix_tree_tagged);
 
index b3db11f137e006d937e5d16199ae4506a0771095..a9cb80ae6409df599cc3823a7a072a158c41112c 100644 (file)
@@ -132,3 +132,10 @@ config SPLIT_PTLOCK_CPUS
        default "4096" if ARM && !CPU_CACHE_VIPT
        default "4096" if PARISC && !PA20
        default "4"
+
+#
+# support for page migration
+#
+config MIGRATION
+       def_bool y if NUMA || SPARSEMEM || DISCONTIGMEM
+       depends on SWAP
index 2fa6d2ca9f28ec0572eded8cf025e727a622440d..9aa03fa1dcc319b51123f89fc7c282d5de068ace 100644 (file)
@@ -9,8 +9,8 @@ mmu-$(CONFIG_MMU)       := fremap.o highmem.o madvise.o memory.o mincore.o \
 
 obj-y                  := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
                           page_alloc.o page-writeback.o pdflush.o \
-                          readahead.o slab.o swap.o truncate.o vmscan.o \
-                          prio_tree.o $(mmu-y)
+                          readahead.o swap.o truncate.o vmscan.o \
+                          prio_tree.o util.o $(mmu-y)
 
 obj-$(CONFIG_SWAP)     += page_io.o swap_state.o swapfile.o thrash.o
 obj-$(CONFIG_HUGETLBFS)        += hugetlb.o
@@ -18,5 +18,7 @@ obj-$(CONFIG_NUMA)    += mempolicy.o
 obj-$(CONFIG_SPARSEMEM)        += sparse.o
 obj-$(CONFIG_SHMEM) += shmem.o
 obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+obj-$(CONFIG_SLOB) += slob.o
+obj-$(CONFIG_SLAB) += slab.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
 obj-$(CONFIG_FS_XIP) += filemap_xip.o
index 5f19e87bc5af1c86dd121d7e50dcd3e5cc1c7e94..d257c89e7704c60d8decf405c89c46f8de262153 100644 (file)
@@ -37,6 +37,11 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
        if (!file)
                return -EBADF;
 
+       if (S_ISFIFO(file->f_dentry->d_inode->i_mode)) {
+               ret = -ESPIPE;
+               goto out;
+       }
+
        mapping = file->f_mapping;
        if (!mapping || len < 0) {
                ret = -EINVAL;
index 4ef24a397684f7b9a51c70e94843f4cff35ed281..478f4c74cc31e31b01855e0d5ac20ec6e088e5ce 100644 (file)
@@ -280,7 +280,7 @@ static int wait_on_page_writeback_range(struct address_space *mapping,
  * it is otherwise livelockable.
  */
 int sync_page_range(struct inode *inode, struct address_space *mapping,
-                       loff_t pos, size_t count)
+                       loff_t pos, loff_t count)
 {
        pgoff_t start = pos >> PAGE_CACHE_SHIFT;
        pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT;
@@ -305,9 +305,8 @@ EXPORT_SYMBOL(sync_page_range);
  * as it forces O_SYNC writers to different parts of the same file
  * to be serialised right until io completion.
  */
-static int sync_page_range_nolock(struct inode *inode,
-                                 struct address_space *mapping,
-                                 loff_t pos, size_t count)
+int sync_page_range_nolock(struct inode *inode, struct address_space *mapping,
+                          loff_t pos, loff_t count)
 {
        pgoff_t start = pos >> PAGE_CACHE_SHIFT;
        pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT;
@@ -322,6 +321,7 @@ static int sync_page_range_nolock(struct inode *inode,
                ret = wait_on_page_writeback_range(mapping, start, end);
        return ret;
 }
+EXPORT_SYMBOL(sync_page_range_nolock);
 
 /**
  * filemap_fdatawait - walk the list of under-writeback pages of the given
@@ -343,30 +343,44 @@ EXPORT_SYMBOL(filemap_fdatawait);
 
 int filemap_write_and_wait(struct address_space *mapping)
 {
-       int retval = 0;
+       int err = 0;
 
        if (mapping->nrpages) {
-               retval = filemap_fdatawrite(mapping);
-               if (retval == 0)
-                       retval = filemap_fdatawait(mapping);
+               err = filemap_fdatawrite(mapping);
+               /*
+                * Even if the above returned error, the pages may be
+                * written partially (e.g. -ENOSPC), so we wait for it.
+                * But the -EIO is special case, it may indicate the worst
+                * thing (e.g. bug) happened, so we avoid waiting for it.
+                */
+               if (err != -EIO) {
+                       int err2 = filemap_fdatawait(mapping);
+                       if (!err)
+                               err = err2;
+               }
        }
-       return retval;
+       return err;
 }
+EXPORT_SYMBOL(filemap_write_and_wait);
 
 int filemap_write_and_wait_range(struct address_space *mapping,
                                 loff_t lstart, loff_t lend)
 {
-       int retval = 0;
+       int err = 0;
 
        if (mapping->nrpages) {
-               retval = __filemap_fdatawrite_range(mapping, lstart, lend,
-                                                   WB_SYNC_ALL);
-               if (retval == 0)
-                       retval = wait_on_page_writeback_range(mapping,
-                                                   lstart >> PAGE_CACHE_SHIFT,
-                                                   lend >> PAGE_CACHE_SHIFT);
+               err = __filemap_fdatawrite_range(mapping, lstart, lend,
+                                                WB_SYNC_ALL);
+               /* See comment of filemap_write_and_wait() */
+               if (err != -EIO) {
+                       int err2 = wait_on_page_writeback_range(mapping,
+                                               lstart >> PAGE_CACHE_SHIFT,
+                                               lend >> PAGE_CACHE_SHIFT);
+                       if (!err)
+                               err = err2;
+               }
        }
-       return retval;
+       return err;
 }
 
 /*
index f4c43d7980ba2d83ff3d038995792aa93d991d18..b21d78c941b527b9c8021d23a6d63bf3dd892523 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/nodemask.h>
 #include <linux/pagemap.h>
 #include <linux/mempolicy.h>
+#include <linux/cpuset.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -48,7 +49,8 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,
 
        for (z = zonelist->zones; *z; z++) {
                nid = (*z)->zone_pgdat->node_id;
-               if (!list_empty(&hugepage_freelists[nid]))
+               if (cpuset_zone_allowed(*z, GFP_HIGHUSER) &&
+                   !list_empty(&hugepage_freelists[nid]))
                        break;
        }
 
index 7197f9bcd384d99bdd51d858cb8438a67a4198a0..3944fec380125b8698e47468e5b0ea4d7407060a 100644 (file)
@@ -2267,6 +2267,8 @@ 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.
index 0f1d2b8a952b900f899ea19233c84b862909323d..1850d0aef4ac3aba3abc99caf9b479c75319e368 100644 (file)
 #include <linux/init.h>
 #include <linux/compat.h>
 #include <linux/mempolicy.h>
+#include <linux/swap.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+
 #include <asm/tlbflush.h>
 #include <asm/uaccess.h>
 
+/* Internal flags */
+#define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0)   /* Skip checks for continuous vmas */
+#define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1)         /* Invert check for nodemask */
+#define MPOL_MF_STATS (MPOL_MF_INTERNAL << 2)          /* Gather statistics */
+
 static kmem_cache_t *policy_cache;
 static kmem_cache_t *sn_cache;
 
@@ -171,12 +180,19 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)
                break;
        }
        policy->policy = mode;
+       policy->cpuset_mems_allowed = cpuset_mems_allowed(current);
        return policy;
 }
 
-/* Ensure all existing pages follow the policy. */
+static void gather_stats(struct page *, void *);
+static void migrate_page_add(struct vm_area_struct *vma,
+       struct page *page, struct list_head *pagelist, unsigned long flags);
+
+/* Scan through pages checking if pages follow certain conditions. */
 static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
-               unsigned long addr, unsigned long end, nodemask_t *nodes)
+               unsigned long addr, unsigned long end,
+               const nodemask_t *nodes, unsigned long flags,
+               void *private)
 {
        pte_t *orig_pte;
        pte_t *pte;
@@ -193,7 +209,17 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                if (!page)
                        continue;
                nid = page_to_nid(page);
-               if (!node_isset(nid, *nodes))
+               if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT))
+                       continue;
+
+               if (flags & MPOL_MF_STATS)
+                       gather_stats(page, private);
+               else if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
+                       spin_unlock(ptl);
+                       migrate_page_add(vma, page, private, flags);
+                       spin_lock(ptl);
+               }
+               else
                        break;
        } while (pte++, addr += PAGE_SIZE, addr != end);
        pte_unmap_unlock(orig_pte, ptl);
@@ -201,7 +227,9 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 }
 
 static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud,
-               unsigned long addr, unsigned long end, nodemask_t *nodes)
+               unsigned long addr, unsigned long end,
+               const nodemask_t *nodes, unsigned long flags,
+               void *private)
 {
        pmd_t *pmd;
        unsigned long next;
@@ -211,14 +239,17 @@ static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud,
                next = pmd_addr_end(addr, end);
                if (pmd_none_or_clear_bad(pmd))
                        continue;
-               if (check_pte_range(vma, pmd, addr, next, nodes))
+               if (check_pte_range(vma, pmd, addr, next, nodes,
+                                   flags, private))
                        return -EIO;
        } while (pmd++, addr = next, addr != end);
        return 0;
 }
 
 static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
-               unsigned long addr, unsigned long end, nodemask_t *nodes)
+               unsigned long addr, unsigned long end,
+               const nodemask_t *nodes, unsigned long flags,
+               void *private)
 {
        pud_t *pud;
        unsigned long next;
@@ -228,14 +259,17 @@ static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
                next = pud_addr_end(addr, end);
                if (pud_none_or_clear_bad(pud))
                        continue;
-               if (check_pmd_range(vma, pud, addr, next, nodes))
+               if (check_pmd_range(vma, pud, addr, next, nodes,
+                                   flags, private))
                        return -EIO;
        } while (pud++, addr = next, addr != end);
        return 0;
 }
 
 static inline int check_pgd_range(struct vm_area_struct *vma,
-               unsigned long addr, unsigned long end, nodemask_t *nodes)
+               unsigned long addr, unsigned long end,
+               const nodemask_t *nodes, unsigned long flags,
+               void *private)
 {
        pgd_t *pgd;
        unsigned long next;
@@ -245,16 +279,30 @@ static inline int check_pgd_range(struct vm_area_struct *vma,
                next = pgd_addr_end(addr, end);
                if (pgd_none_or_clear_bad(pgd))
                        continue;
-               if (check_pud_range(vma, pgd, addr, next, nodes))
+               if (check_pud_range(vma, pgd, addr, next, nodes,
+                                   flags, private))
                        return -EIO;
        } while (pgd++, addr = next, addr != end);
        return 0;
 }
 
-/* Step 1: check the range */
+/* Check if a vma is migratable */
+static inline int vma_migratable(struct vm_area_struct *vma)
+{
+       if (vma->vm_flags & (
+               VM_LOCKED|VM_IO|VM_HUGETLB|VM_PFNMAP))
+               return 0;
+       return 1;
+}
+
+/*
+ * Check if all pages in a range are on a set of nodes.
+ * If pagelist != NULL then isolate pages from the LRU and
+ * put them on the pagelist.
+ */
 static struct vm_area_struct *
 check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
-           nodemask_t *nodes, unsigned long flags)
+               const nodemask_t *nodes, unsigned long flags, void *private)
 {
        int err;
        struct vm_area_struct *first, *vma, *prev;
@@ -264,17 +312,24 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
                return ERR_PTR(-EFAULT);
        prev = NULL;
        for (vma = first; vma && vma->vm_start < end; vma = vma->vm_next) {
-               if (!vma->vm_next && vma->vm_end < end)
-                       return ERR_PTR(-EFAULT);
-               if (prev && prev->vm_end < vma->vm_start)
-                       return ERR_PTR(-EFAULT);
-               if ((flags & MPOL_MF_STRICT) && !is_vm_hugetlb_page(vma)) {
+               if (!(flags & MPOL_MF_DISCONTIG_OK)) {
+                       if (!vma->vm_next && vma->vm_end < end)
+                               return ERR_PTR(-EFAULT);
+                       if (prev && prev->vm_end < vma->vm_start)
+                               return ERR_PTR(-EFAULT);
+               }
+               if (!is_vm_hugetlb_page(vma) &&
+                   ((flags & MPOL_MF_STRICT) ||
+                    ((flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) &&
+                               vma_migratable(vma)))) {
                        unsigned long endvma = vma->vm_end;
+
                        if (endvma > end)
                                endvma = end;
                        if (vma->vm_start > start)
                                start = vma->vm_start;
-                       err = check_pgd_range(vma, start, endvma, nodes);
+                       err = check_pgd_range(vma, start, endvma, nodes,
+                                               flags, private);
                        if (err) {
                                first = ERR_PTR(err);
                                break;
@@ -333,51 +388,10 @@ static int contextualize_policy(int mode, nodemask_t *nodes)
        if (!nodes)
                return 0;
 
-       /* Update current mems_allowed */
-       cpuset_update_current_mems_allowed();
-       /* Ignore nodes not set in current->mems_allowed */
-       cpuset_restrict_to_mems_allowed(nodes->bits);
-       return mpol_check_policy(mode, nodes);
-}
-
-long do_mbind(unsigned long start, unsigned long len,
-               unsigned long mode, nodemask_t *nmask, unsigned long flags)
-{
-       struct vm_area_struct *vma;
-       struct mm_struct *mm = current->mm;
-       struct mempolicy *new;
-       unsigned long end;
-       int err;
-
-       if ((flags & ~(unsigned long)(MPOL_MF_STRICT)) || mode > MPOL_MAX)
-               return -EINVAL;
-       if (start & ~PAGE_MASK)
-               return -EINVAL;
-       if (mode == MPOL_DEFAULT)
-               flags &= ~MPOL_MF_STRICT;
-       len = (len + PAGE_SIZE - 1) & PAGE_MASK;
-       end = start + len;
-       if (end < start)
+       cpuset_update_task_memory_state();
+       if (!cpuset_nodes_subset_current_mems_allowed(*nodes))
                return -EINVAL;
-       if (end == start)
-               return 0;
-       if (mpol_check_policy(mode, nmask))
-               return -EINVAL;
-       new = mpol_new(mode, nmask);
-       if (IS_ERR(new))
-               return PTR_ERR(new);
-
-       PDprintk("mbind %lx-%lx mode:%ld nodes:%lx\n",start,start+len,
-                       mode,nodes_addr(nodes)[0]);
-
-       down_write(&mm->mmap_sem);
-       vma = check_range(mm, start, end, nmask, flags);
-       err = PTR_ERR(vma);
-       if (!IS_ERR(vma))
-               err = mbind_range(vma, start, end, new);
-       up_write(&mm->mmap_sem);
-       mpol_free(new);
-       return err;
+       return mpol_check_policy(mode, nodes);
 }
 
 /* Set the process memory policy */
@@ -448,7 +462,7 @@ long do_get_mempolicy(int *policy, nodemask_t *nmask,
        struct vm_area_struct *vma = NULL;
        struct mempolicy *pol = current->mempolicy;
 
-       cpuset_update_current_mems_allowed();
+       cpuset_update_task_memory_state();
        if (flags & ~(unsigned long)(MPOL_F_NODE|MPOL_F_ADDR))
                return -EINVAL;
        if (flags & MPOL_F_ADDR) {
@@ -499,12 +513,178 @@ long do_get_mempolicy(int *policy, nodemask_t *nmask,
        return err;
 }
 
+/*
+ * page migration
+ */
+
+/* Check if we are the only process mapping the page in question */
+static inline int single_mm_mapping(struct mm_struct *mm,
+                       struct address_space *mapping)
+{
+       struct vm_area_struct *vma;
+       struct prio_tree_iter iter;
+       int rc = 1;
+
+       spin_lock(&mapping->i_mmap_lock);
+       vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX)
+               if (mm != vma->vm_mm) {
+                       rc = 0;
+                       goto out;
+               }
+       list_for_each_entry(vma, &mapping->i_mmap_nonlinear, shared.vm_set.list)
+               if (mm != vma->vm_mm) {
+                       rc = 0;
+                       goto out;
+               }
+out:
+       spin_unlock(&mapping->i_mmap_lock);
+       return rc;
+}
+
+/*
+ * Add a page to be migrated to the pagelist
+ */
+static void migrate_page_add(struct vm_area_struct *vma,
+       struct page *page, struct list_head *pagelist, unsigned long flags)
+{
+       /*
+        * Avoid migrating a page that is shared by others and not writable.
+        */
+       if ((flags & MPOL_MF_MOVE_ALL) || !page->mapping || PageAnon(page) ||
+           mapping_writably_mapped(page->mapping) ||
+           single_mm_mapping(vma->vm_mm, page->mapping)) {
+               int rc = isolate_lru_page(page);
+
+               if (rc == 1)
+                       list_add(&page->lru, pagelist);
+               /*
+                * If the isolate attempt was not successful then we just
+                * encountered an unswappable page. Something must be wrong.
+                */
+               WARN_ON(rc == 0);
+       }
+}
+
+static int swap_pages(struct list_head *pagelist)
+{
+       LIST_HEAD(moved);
+       LIST_HEAD(failed);
+       int n;
+
+       n = migrate_pages(pagelist, NULL, &moved, &failed);
+       putback_lru_pages(&failed);
+       putback_lru_pages(&moved);
+
+       return n;
+}
+
+/*
+ * For now migrate_pages simply swaps out the pages from nodes that are in
+ * the source set but not in the target set. In the future, we would
+ * want a function that moves pages between the two nodesets in such
+ * a way as to preserve the physical layout as much as possible.
+ *
+ * Returns the number of page that could not be moved.
+ */
+int do_migrate_pages(struct mm_struct *mm,
+       const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags)
+{
+       LIST_HEAD(pagelist);
+       int count = 0;
+       nodemask_t nodes;
+
+       nodes_andnot(nodes, *from_nodes, *to_nodes);
+
+       down_read(&mm->mmap_sem);
+       check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nodes,
+                       flags | MPOL_MF_DISCONTIG_OK, &pagelist);
+
+       if (!list_empty(&pagelist)) {
+               count = swap_pages(&pagelist);
+               putback_lru_pages(&pagelist);
+       }
+
+       up_read(&mm->mmap_sem);
+       return count;
+}
+
+long do_mbind(unsigned long start, unsigned long len,
+               unsigned long mode, nodemask_t *nmask, unsigned long flags)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = current->mm;
+       struct mempolicy *new;
+       unsigned long end;
+       int err;
+       LIST_HEAD(pagelist);
+
+       if ((flags & ~(unsigned long)(MPOL_MF_STRICT |
+                                     MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
+           || mode > MPOL_MAX)
+               return -EINVAL;
+       if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_RESOURCE))
+               return -EPERM;
+
+       if (start & ~PAGE_MASK)
+               return -EINVAL;
+
+       if (mode == MPOL_DEFAULT)
+               flags &= ~MPOL_MF_STRICT;
+
+       len = (len + PAGE_SIZE - 1) & PAGE_MASK;
+       end = start + len;
+
+       if (end < start)
+               return -EINVAL;
+       if (end == start)
+               return 0;
+
+       if (mpol_check_policy(mode, nmask))
+               return -EINVAL;
+
+       new = mpol_new(mode, nmask);
+       if (IS_ERR(new))
+               return PTR_ERR(new);
+
+       /*
+        * If we are using the default policy then operation
+        * on discontinuous address spaces is okay after all
+        */
+       if (!new)
+               flags |= MPOL_MF_DISCONTIG_OK;
+
+       PDprintk("mbind %lx-%lx mode:%ld nodes:%lx\n",start,start+len,
+                       mode,nodes_addr(nodes)[0]);
+
+       down_write(&mm->mmap_sem);
+       vma = check_range(mm, start, end, nmask,
+                         flags | MPOL_MF_INVERT, &pagelist);
+
+       err = PTR_ERR(vma);
+       if (!IS_ERR(vma)) {
+               int nr_failed = 0;
+
+               err = mbind_range(vma, start, end, new);
+               if (!list_empty(&pagelist))
+                       nr_failed = swap_pages(&pagelist);
+
+               if (!err && nr_failed && (flags & MPOL_MF_STRICT))
+                       err = -EIO;
+       }
+       if (!list_empty(&pagelist))
+               putback_lru_pages(&pagelist);
+
+       up_write(&mm->mmap_sem);
+       mpol_free(new);
+       return err;
+}
+
 /*
  * User space interface with variable sized bitmaps for nodelists.
  */
 
 /* Copy a node mask from user space. */
-static int get_nodes(nodemask_t *nodes, unsigned long __user *nmask,
+static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
                     unsigned long maxnode)
 {
        unsigned long k;
@@ -593,6 +773,65 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask,
        return do_set_mempolicy(mode, &nodes);
 }
 
+asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
+               const unsigned long __user *old_nodes,
+               const unsigned long __user *new_nodes)
+{
+       struct mm_struct *mm;
+       struct task_struct *task;
+       nodemask_t old;
+       nodemask_t new;
+       nodemask_t task_nodes;
+       int err;
+
+       err = get_nodes(&old, old_nodes, maxnode);
+       if (err)
+               return err;
+
+       err = get_nodes(&new, new_nodes, maxnode);
+       if (err)
+               return err;
+
+       /* Find the mm_struct */
+       read_lock(&tasklist_lock);
+       task = pid ? find_task_by_pid(pid) : current;
+       if (!task) {
+               read_unlock(&tasklist_lock);
+               return -ESRCH;
+       }
+       mm = get_task_mm(task);
+       read_unlock(&tasklist_lock);
+
+       if (!mm)
+               return -EINVAL;
+
+       /*
+        * Check if this process has the right to modify the specified
+        * process. The right exists if the process has administrative
+        * capabilities, superuser priviledges or the same
+        * userid as the target process.
+        */
+       if ((current->euid != task->suid) && (current->euid != task->uid) &&
+           (current->uid != task->suid) && (current->uid != task->uid) &&
+           !capable(CAP_SYS_ADMIN)) {
+               err = -EPERM;
+               goto out;
+       }
+
+       task_nodes = cpuset_mems_allowed(task);
+       /* Is the user allowed to access the target nodes? */
+       if (!nodes_subset(new, task_nodes) && !capable(CAP_SYS_ADMIN)) {
+               err = -EPERM;
+               goto out;
+       }
+
+       err = do_migrate_pages(mm, &old, &new, MPOL_MF_MOVE);
+out:
+       mmput(mm);
+       return err;
+}
+
+
 /* Retrieve NUMA policy */
 asmlinkage long sys_get_mempolicy(int __user *policy,
                                unsigned long __user *nmask,
@@ -699,8 +938,8 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
 #endif
 
 /* Return effective policy for a VMA */
-struct mempolicy *
-get_vma_policy(struct task_struct *task, struct vm_area_struct *vma, unsigned long addr)
+static struct mempolicy * get_vma_policy(struct task_struct *task,
+               struct vm_area_struct *vma, unsigned long addr)
 {
        struct mempolicy *pol = task->mempolicy;
 
@@ -848,7 +1087,7 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
 {
        struct mempolicy *pol = get_vma_policy(current, vma, addr);
 
-       cpuset_update_current_mems_allowed();
+       cpuset_update_task_memory_state();
 
        if (unlikely(pol->policy == MPOL_INTERLEAVE)) {
                unsigned nid;
@@ -874,7 +1113,7 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
  *     interrupt context and apply the current process NUMA policy.
  *     Returns NULL when no page can be allocated.
  *
- *     Don't call cpuset_update_current_mems_allowed() unless
+ *     Don't call cpuset_update_task_memory_state() unless
  *     1) it's ok to take cpuset_sem (can WAIT), and
  *     2) allocating for current task (not interrupt).
  */
@@ -883,7 +1122,7 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order)
        struct mempolicy *pol = current->mempolicy;
 
        if ((gfp & __GFP_WAIT) && !in_interrupt())
-               cpuset_update_current_mems_allowed();
+               cpuset_update_task_memory_state();
        if (!pol || in_interrupt())
                pol = &default_policy;
        if (pol->policy == MPOL_INTERLEAVE)
@@ -892,6 +1131,15 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order)
 }
 EXPORT_SYMBOL(alloc_pages_current);
 
+/*
+ * If mpol_copy() sees current->cpuset == cpuset_being_rebound, then it
+ * rebinds the mempolicy its copying by calling mpol_rebind_policy()
+ * with the mems_allowed returned by cpuset_mems_allowed().  This
+ * keeps mempolicies cpuset relative after its cpuset moves.  See
+ * further kernel/cpuset.c update_nodemask().
+ */
+void *cpuset_being_rebound;
+
 /* Slow path of a mempolicy copy */
 struct mempolicy *__mpol_copy(struct mempolicy *old)
 {
@@ -899,6 +1147,10 @@ struct mempolicy *__mpol_copy(struct mempolicy *old)
 
        if (!new)
                return ERR_PTR(-ENOMEM);
+       if (current_cpuset_is_being_rebound()) {
+               nodemask_t mems = cpuset_mems_allowed(current);
+               mpol_rebind_policy(old, &mems);
+       }
        *new = *old;
        atomic_set(&new->refcnt, 1);
        if (new->policy == MPOL_BIND) {
@@ -1173,25 +1425,31 @@ void numa_default_policy(void)
 }
 
 /* Migrate a policy to a different set of nodes */
-static void rebind_policy(struct mempolicy *pol, const nodemask_t *old,
-                                                       const nodemask_t *new)
+void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *newmask)
 {
+       nodemask_t *mpolmask;
        nodemask_t tmp;
 
        if (!pol)
                return;
+       mpolmask = &pol->cpuset_mems_allowed;
+       if (nodes_equal(*mpolmask, *newmask))
+               return;
 
        switch (pol->policy) {
        case MPOL_DEFAULT:
                break;
        case MPOL_INTERLEAVE:
-               nodes_remap(tmp, pol->v.nodes, *old, *new);
+               nodes_remap(tmp, pol->v.nodes, *mpolmask, *newmask);
                pol->v.nodes = tmp;
-               current->il_next = node_remap(current->il_next, *old, *new);
+               *mpolmask = *newmask;
+               current->il_next = node_remap(current->il_next,
+                                               *mpolmask, *newmask);
                break;
        case MPOL_PREFERRED:
                pol->v.preferred_node = node_remap(pol->v.preferred_node,
-                                                               *old, *new);
+                                               *mpolmask, *newmask);
+               *mpolmask = *newmask;
                break;
        case MPOL_BIND: {
                nodemask_t nodes;
@@ -1201,7 +1459,7 @@ static void rebind_policy(struct mempolicy *pol, const nodemask_t *old,
                nodes_clear(nodes);
                for (z = pol->v.zonelist->zones; *z; z++)
                        node_set((*z)->zone_pgdat->node_id, nodes);
-               nodes_remap(tmp, nodes, *old, *new);
+               nodes_remap(tmp, nodes, *mpolmask, *newmask);
                nodes = tmp;
 
                zonelist = bind_zonelist(&nodes);
@@ -1216,6 +1474,7 @@ static void rebind_policy(struct mempolicy *pol, const nodemask_t *old,
                        kfree(pol->v.zonelist);
                        pol->v.zonelist = zonelist;
                }
+               *mpolmask = *newmask;
                break;
        }
        default:
@@ -1225,12 +1484,156 @@ static void rebind_policy(struct mempolicy *pol, const nodemask_t *old,
 }
 
 /*
- * Someone moved this task to different nodes.  Fixup mempolicies.
+ * Wrapper for mpol_rebind_policy() that just requires task
+ * pointer, and updates task mempolicy.
+ */
+
+void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new)
+{
+       mpol_rebind_policy(tsk->mempolicy, new);
+}
+
+/*
+ * Rebind each vma in mm to new nodemask.
  *
- * TODO - fixup current->mm->vma and shmfs/tmpfs/hugetlbfs policies as well,
- * once we have a cpuset mechanism to mark which cpuset subtree is migrating.
+ * Call holding a reference to mm.  Takes mm->mmap_sem during call.
  */
-void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new)
+
+void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new)
 {
-       rebind_policy(current->mempolicy, old, new);
+       struct vm_area_struct *vma;
+
+       down_write(&mm->mmap_sem);
+       for (vma = mm->mmap; vma; vma = vma->vm_next)
+               mpol_rebind_policy(vma->vm_policy, new);
+       up_write(&mm->mmap_sem);
 }
+
+/*
+ * Display pages allocated per node and memory policy via /proc.
+ */
+
+static const char *policy_types[] = { "default", "prefer", "bind",
+                                     "interleave" };
+
+/*
+ * Convert a mempolicy into a string.
+ * Returns the number of characters in buffer (if positive)
+ * or an error (negative)
+ */
+static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
+{
+       char *p = buffer;
+       int l;
+       nodemask_t nodes;
+       int mode = pol ? pol->policy : MPOL_DEFAULT;
+
+       switch (mode) {
+       case MPOL_DEFAULT:
+               nodes_clear(nodes);
+               break;
+
+       case MPOL_PREFERRED:
+               nodes_clear(nodes);
+               node_set(pol->v.preferred_node, nodes);
+               break;
+
+       case MPOL_BIND:
+               get_zonemask(pol, &nodes);
+               break;
+
+       case MPOL_INTERLEAVE:
+               nodes = pol->v.nodes;
+               break;
+
+       default:
+               BUG();
+               return -EFAULT;
+       }
+
+       l = strlen(policy_types[mode]);
+       if (buffer + maxlen < p + l + 1)
+               return -ENOSPC;
+
+       strcpy(p, policy_types[mode]);
+       p += l;
+
+       if (!nodes_empty(nodes)) {
+               if (buffer + maxlen < p + 2)
+                       return -ENOSPC;
+               *p++ = '=';
+               p += nodelist_scnprintf(p, buffer + maxlen - p, nodes);
+       }
+       return p - buffer;
+}
+
+struct numa_maps {
+       unsigned long pages;
+       unsigned long anon;
+       unsigned long mapped;
+       unsigned long mapcount_max;
+       unsigned long node[MAX_NUMNODES];
+};
+
+static void gather_stats(struct page *page, void *private)
+{
+       struct numa_maps *md = private;
+       int count = page_mapcount(page);
+
+       if (count)
+               md->mapped++;
+
+       if (count > md->mapcount_max)
+               md->mapcount_max = count;
+
+       md->pages++;
+
+       if (PageAnon(page))
+               md->anon++;
+
+       md->node[page_to_nid(page)]++;
+       cond_resched();
+}
+
+int show_numa_map(struct seq_file *m, void *v)
+{
+       struct task_struct *task = m->private;
+       struct vm_area_struct *vma = v;
+       struct numa_maps *md;
+       int n;
+       char buffer[50];
+
+       if (!vma->vm_mm)
+               return 0;
+
+       md = kzalloc(sizeof(struct numa_maps), GFP_KERNEL);
+       if (!md)
+               return 0;
+
+       check_pgd_range(vma, vma->vm_start, vma->vm_end,
+                   &node_online_map, MPOL_MF_STATS, md);
+
+       if (md->pages) {
+               mpol_to_str(buffer, sizeof(buffer),
+                           get_vma_policy(task, vma, vma->vm_start));
+
+               seq_printf(m, "%08lx %s pages=%lu mapped=%lu maxref=%lu",
+                          vma->vm_start, buffer, md->pages,
+                          md->mapped, md->mapcount_max);
+
+               if (md->anon)
+                       seq_printf(m," anon=%lu",md->anon);
+
+               for_each_online_node(n)
+                       if (md->node[n])
+                               seq_printf(m, " N%d=%lu", n, md->node[n]);
+
+               seq_putc(m, '\n');
+       }
+       kfree(md);
+
+       if (m->count < m->size)
+               m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0;
+       return 0;
+}
+
index d348b9035955e5a0ba91af683880ac0e41996fd0..4748b906aff23451c9bbf838ddc1add16bbf1cc9 100644 (file)
@@ -298,7 +298,8 @@ retry:
 
        /*
         * Give "p" a good chance of killing itself before we
-        * retry to allocate memory.
+        * retry to allocate memory unless "p" is current
         */
-       schedule_timeout_interruptible(1);
+       if (!test_thread_flag(TIF_MEMDIE))
+               schedule_timeout_interruptible(1);
 }
index fd47494cb9890b887c55dbd76831819b1c5c645c..e0e84924171b4f28fc0c9c054d5668f4a7036916 100644 (file)
@@ -53,6 +53,7 @@ struct pglist_data *pgdat_list __read_mostly;
 unsigned long totalram_pages __read_mostly;
 unsigned long totalhigh_pages __read_mostly;
 long nr_swap_pages;
+int percpu_pagelist_fraction;
 
 static void fastcall free_hot_cold_page(struct page *page, int cold);
 
@@ -307,7 +308,7 @@ static inline int page_is_buddy(struct page *page, int order)
  * -- wli
  */
 
-static inline void __free_pages_bulk (struct page *page,
+static inline void __free_one_page(struct page *page,
                struct zone *zone, unsigned int order)
 {
        unsigned long page_idx;
@@ -382,40 +383,42 @@ static inline int free_pages_check(struct page *page)
  * And clear the zone's pages_scanned counter, to hold off the "all pages are
  * pinned" detection logic.
  */
-static int
-free_pages_bulk(struct zone *zone, int count,
-               struct list_head *list, unsigned int order)
+static void free_pages_bulk(struct zone *zone, int count,
+                                       struct list_head *list, int order)
 {
-       struct page *page = NULL;
-       int ret = 0;
-
        spin_lock(&zone->lock);
        zone->all_unreclaimable = 0;
        zone->pages_scanned = 0;
-       while (!list_empty(list) && count--) {
+       while (count--) {
+               struct page *page;
+
+               BUG_ON(list_empty(list));
                page = list_entry(list->prev, struct page, lru);
-               /* have to delete it as __free_pages_bulk list manipulates */
+               /* have to delete it as __free_one_page list manipulates */
                list_del(&page->lru);
-               __free_pages_bulk(page, zone, order);
-               ret++;
+               __free_one_page(page, zone, order);
        }
        spin_unlock(&zone->lock);
-       return ret;
 }
 
-void __free_pages_ok(struct page *page, unsigned int order)
+static void free_one_page(struct zone *zone, struct page *page, int order)
 {
-       unsigned long flags;
        LIST_HEAD(list);
+       list_add(&page->lru, &list);
+       free_pages_bulk(zone, 1, &list, order);
+}
+
+static void __free_pages_ok(struct page *page, unsigned int order)
+{
+       unsigned long flags;
        int i;
        int reserved = 0;
 
        arch_free_page(page, order);
 
 #ifndef CONFIG_MMU
-       if (order > 0)
-               for (i = 1 ; i < (1 << order) ; ++i)
-                       __put_page(page + i);
+       for (i = 1 ; i < (1 << order) ; ++i)
+               __put_page(page + i);
 #endif
 
        for (i = 0 ; i < (1 << order) ; ++i)
@@ -423,11 +426,10 @@ void __free_pages_ok(struct page *page, unsigned int order)
        if (reserved)
                return;
 
-       list_add(&page->lru, &list);
-       kernel_map_pages(page, 1<<order, 0);
+       kernel_map_pages(page, 1 << order, 0);
        local_irq_save(flags);
        __mod_page_state(pgfree, 1 << order);
-       free_pages_bulk(page_zone(page), 1, &list, order);
+       free_one_page(page_zone(page), page, order);
        local_irq_restore(flags);
 }
 
@@ -596,14 +598,13 @@ void drain_remote_pages(void)
                if (zone->zone_pgdat->node_id == numa_node_id())
                        continue;
 
-               pset = zone->pageset[smp_processor_id()];
+               pset = zone_pcp(zone, smp_processor_id());
                for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
                        struct per_cpu_pages *pcp;
 
                        pcp = &pset->pcp[i];
-                       if (pcp->count)
-                               pcp->count -= free_pages_bulk(zone, pcp->count,
-                                               &pcp->list, 0);
+                       free_pages_bulk(zone, pcp->count, &pcp->list, 0);
+                       pcp->count = 0;
                }
        }
        local_irq_restore(flags);
@@ -626,8 +627,8 @@ static void __drain_pages(unsigned int cpu)
 
                        pcp = &pset->pcp[i];
                        local_irq_save(flags);
-                       pcp->count -= free_pages_bulk(zone, pcp->count,
-                                               &pcp->list, 0);
+                       free_pages_bulk(zone, pcp->count, &pcp->list, 0);
+                       pcp->count = 0;
                        local_irq_restore(flags);
                }
        }
@@ -718,8 +719,10 @@ static void fastcall free_hot_cold_page(struct page *page, int cold)
        __inc_page_state(pgfree);
        list_add(&page->lru, &pcp->list);
        pcp->count++;
-       if (pcp->count >= pcp->high)
-               pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
+       if (pcp->count >= pcp->high) {
+               free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
+               pcp->count -= pcp->batch;
+       }
        local_irq_restore(flags);
        put_cpu();
 }
@@ -758,7 +761,7 @@ static struct page *buffered_rmqueue(struct zonelist *zonelist,
 
 again:
        cpu  = get_cpu();
-       if (order == 0) {
+       if (likely(order == 0)) {
                struct per_cpu_pages *pcp;
 
                pcp = &zone_pcp(zone, cpu)->pcp[cold];
@@ -973,6 +976,7 @@ rebalance:
        cond_resched();
 
        /* We now go into synchronous reclaim */
+       cpuset_memory_pressure_bump();
        p->flags |= PF_MEMALLOC;
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
@@ -1204,6 +1208,7 @@ static void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask)
        int cpu = 0;
 
        memset(ret, 0, sizeof(*ret));
+       cpus_and(*cpumask, *cpumask, cpu_online_map);
 
        cpu = first_cpu(*cpumask);
        while (cpu < NR_CPUS) {
@@ -1256,7 +1261,7 @@ unsigned long read_page_state_offset(unsigned long offset)
        unsigned long ret = 0;
        int cpu;
 
-       for_each_cpu(cpu) {
+       for_each_online_cpu(cpu) {
                unsigned long in;
 
                in = (unsigned long)&per_cpu(page_states, cpu) + offset;
@@ -1830,6 +1835,24 @@ inline void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
        INIT_LIST_HEAD(&pcp->list);
 }
 
+/*
+ * setup_pagelist_highmark() sets the high water mark for hot per_cpu_pagelist
+ * to the value high for the pageset p.
+ */
+
+static void setup_pagelist_highmark(struct per_cpu_pageset *p,
+                               unsigned long high)
+{
+       struct per_cpu_pages *pcp;
+
+       pcp = &p->pcp[0]; /* hot list */
+       pcp->high = high;
+       pcp->batch = max(1UL, high/4);
+       if ((high/4) > (PAGE_SHIFT * 8))
+               pcp->batch = PAGE_SHIFT * 8;
+}
+
+
 #ifdef CONFIG_NUMA
 /*
  * Boot pageset table. One per cpu which is going to be used for all
@@ -1861,12 +1884,16 @@ static int __devinit process_zones(int cpu)
 
        for_each_zone(zone) {
 
-               zone->pageset[cpu] = kmalloc_node(sizeof(struct per_cpu_pageset),
+               zone_pcp(zone, cpu) = kmalloc_node(sizeof(struct per_cpu_pageset),
                                         GFP_KERNEL, cpu_to_node(cpu));
-               if (!zone->pageset[cpu])
+               if (!zone_pcp(zone, cpu))
                        goto bad;
 
-               setup_pageset(zone->pageset[cpu], zone_batchsize(zone));
+               setup_pageset(zone_pcp(zone, cpu), zone_batchsize(zone));
+
+               if (percpu_pagelist_fraction)
+                       setup_pagelist_highmark(zone_pcp(zone, cpu),
+                               (zone->present_pages / percpu_pagelist_fraction));
        }
 
        return 0;
@@ -1874,15 +1901,14 @@ bad:
        for_each_zone(dzone) {
                if (dzone == zone)
                        break;
-               kfree(dzone->pageset[cpu]);
-               dzone->pageset[cpu] = NULL;
+               kfree(zone_pcp(dzone, cpu));
+               zone_pcp(dzone, cpu) = NULL;
        }
        return -ENOMEM;
 }
 
 static inline void free_zone_pagesets(int cpu)
 {
-#ifdef CONFIG_NUMA
        struct zone *zone;
 
        for_each_zone(zone) {
@@ -1891,7 +1917,6 @@ static inline void free_zone_pagesets(int cpu)
                zone_pcp(zone, cpu) = NULL;
                kfree(pset);
        }
-#endif
 }
 
 static int __devinit pageset_cpuup_callback(struct notifier_block *nfb,
@@ -1962,7 +1987,7 @@ static __devinit void zone_pcp_init(struct zone *zone)
        for (cpu = 0; cpu < NR_CPUS; cpu++) {
 #ifdef CONFIG_NUMA
                /* Early boot. Slab allocator not functional yet */
-               zone->pageset[cpu] = &boot_pageset[cpu];
+               zone_pcp(zone, cpu) = &boot_pageset[cpu];
                setup_pageset(&boot_pageset[cpu],0);
 #else
                setup_pageset(zone_pcp(zone,cpu), batch);
@@ -2205,7 +2230,7 @@ static int zoneinfo_show(struct seq_file *m, void *arg)
                seq_printf(m,
                           ")"
                           "\n  pagesets");
-               for (i = 0; i < ARRAY_SIZE(zone->pageset); i++) {
+               for_each_online_cpu(i) {
                        struct per_cpu_pageset *pageset;
                        int j;
 
@@ -2568,6 +2593,32 @@ int lowmem_reserve_ratio_sysctl_handler(ctl_table *table, int write,
        return 0;
 }
 
+/*
+ * percpu_pagelist_fraction - changes the pcp->high for each zone on each
+ * cpu.  It is the fraction of total pages in each zone that a hot per cpu pagelist
+ * can have before it gets flushed back to buddy allocator.
+ */
+
+int percpu_pagelist_fraction_sysctl_handler(ctl_table *table, int write,
+       struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
+{
+       struct zone *zone;
+       unsigned int cpu;
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, file, buffer, length, ppos);
+       if (!write || (ret == -EINVAL))
+               return ret;
+       for_each_zone(zone) {
+               for_each_online_cpu(cpu) {
+                       unsigned long  high;
+                       high = zone->present_pages / percpu_pagelist_fraction;
+                       setup_pagelist_highmark(zone_pcp(zone, cpu), high);
+               }
+       }
+       return 0;
+}
+
 __initdata int hashdist = HASHDIST_DEFAULT;
 
 #ifdef CONFIG_NUMA
index 52822c98c489c36bc30e24871eef936766b5c784..c4b6d0afd73605cdc446a1cd9fc75aca8afb3693 100644 (file)
@@ -90,7 +90,7 @@ struct pdflush_work {
 
 static int __pdflush(struct pdflush_work *my_work)
 {
-       current->flags |= PF_FLUSHER;
+       current->flags |= PF_FLUSHER | PF_SWAPWRITE;
        my_work->fn = NULL;
        my_work->who = current;
        INIT_LIST_HEAD(&my_work->list);
index 6f3f7db27128d45443ba114e93e8f31802cbef24..66ec43053a4db521a77534888c62aa0327e5f672 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -514,6 +514,13 @@ void page_add_file_rmap(struct page *page)
 void page_remove_rmap(struct page *page)
 {
        if (atomic_add_negative(-1, &page->_mapcount)) {
+               if (page_mapcount(page) < 0) {
+                       printk (KERN_EMERG "Eeek! page_mapcount(page) went negative! (%d)\n", page_mapcount(page));
+                       printk (KERN_EMERG "  page->flags = %lx\n", page->flags);
+                       printk (KERN_EMERG "  page->count = %x\n", page_count(page));
+                       printk (KERN_EMERG "  page->mapping = %p\n", page->mapping);
+               }
+
                BUG_ON(page_mapcount(page) < 0);
                /*
                 * It would be tidy to reset the PageAnon mapping here,
index e5ec26e0c4603c9ee19a7ea5878426ea2420cddd..1c46c6383552ffa82921934bb6ce05715dd0fd88 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
 #define        FORCED_DEBUG    0
 #endif
 
-
 /* Shouldn't this be in a header file somewhere? */
 #define        BYTES_PER_WORD          sizeof(void *)
 
@@ -217,12 +216,12 @@ static unsigned long offslab_limit;
  * Slabs are chained into three list: fully used, partial, fully free slabs.
  */
 struct slab {
-       struct list_head        list;
-       unsigned long           colouroff;
-       void                    *s_mem;         /* including colour offset */
-       unsigned int            inuse;          /* num of objs active in slab */
-       kmem_bufctl_t           free;
-       unsigned short          nodeid;
+       struct list_head list;
+       unsigned long colouroff;
+       void *s_mem;            /* including colour offset */
+       unsigned int inuse;     /* num of objs active in slab */
+       kmem_bufctl_t free;
+       unsigned short nodeid;
 };
 
 /*
@@ -242,9 +241,9 @@ struct slab {
  * We assume struct slab_rcu can overlay struct slab when destroying.
  */
 struct slab_rcu {
-       struct rcu_head         head;
-       kmem_cache_t            *cachep;
-       void                    *addr;
+       struct rcu_head head;
+       kmem_cache_t *cachep;
+       void *addr;
 };
 
 /*
@@ -279,23 +278,23 @@ struct array_cache {
 #define BOOT_CPUCACHE_ENTRIES  1
 struct arraycache_init {
        struct array_cache cache;
-       void * entries[BOOT_CPUCACHE_ENTRIES];
+       void *entries[BOOT_CPUCACHE_ENTRIES];
 };
 
 /*
  * The slab lists for all objects.
  */
 struct kmem_list3 {
-       struct list_head        slabs_partial;  /* partial list first, better asm code */
-       struct list_head        slabs_full;
-       struct list_head        slabs_free;
-       unsigned long   free_objects;
-       unsigned long   next_reap;
-       int             free_touched;
-       unsigned int    free_limit;
-       spinlock_t      list_lock;
-       struct array_cache      *shared;        /* shared per node */
-       struct array_cache      **alien;        /* on other nodes */
+       struct list_head slabs_partial; /* partial list first, better asm code */
+       struct list_head slabs_full;
+       struct list_head slabs_free;
+       unsigned long free_objects;
+       unsigned long next_reap;
+       int free_touched;
+       unsigned int free_limit;
+       spinlock_t list_lock;
+       struct array_cache *shared;     /* shared per node */
+       struct array_cache **alien;     /* on other nodes */
 };
 
 /*
@@ -367,63 +366,63 @@ static inline void kmem_list3_init(struct kmem_list3 *parent)
  *
  * manages a cache.
  */
-       
+
 struct kmem_cache {
 /* 1) per-cpu data, touched during every alloc/free */
-       struct array_cache      *array[NR_CPUS];
-       unsigned int            batchcount;
-       unsigned int            limit;
-       unsigned int            shared;
-       unsigned int            objsize;
+       struct array_cache *array[NR_CPUS];
+       unsigned int batchcount;
+       unsigned int limit;
+       unsigned int shared;
+       unsigned int objsize;
 /* 2) touched by every alloc & free from the backend */
-       struct kmem_list3       *nodelists[MAX_NUMNODES];
-       unsigned int            flags;  /* constant flags */
-       unsigned int            num;    /* # of objs per slab */
-       spinlock_t              spinlock;
+       struct kmem_list3 *nodelists[MAX_NUMNODES];
+       unsigned int flags;     /* constant flags */
+       unsigned int num;       /* # of objs per slab */
+       spinlock_t spinlock;
 
 /* 3) cache_grow/shrink */
        /* order of pgs per slab (2^n) */
-       unsigned int            gfporder;
+       unsigned int gfporder;
 
        /* force GFP flags, e.g. GFP_DMA */
-       gfp_t                   gfpflags;
+       gfp_t gfpflags;
 
-       size_t                  colour;         /* cache colouring range */
-       unsigned int            colour_off;     /* colour offset */
-       unsigned int            colour_next;    /* cache colouring */
-       kmem_cache_t            *slabp_cache;
-       unsigned int            slab_size;
-       unsigned int            dflags;         /* dynamic flags */
+       size_t colour;          /* cache colouring range */
+       unsigned int colour_off;        /* colour offset */
+       unsigned int colour_next;       /* cache colouring */
+       kmem_cache_t *slabp_cache;
+       unsigned int slab_size;
+       unsigned int dflags;    /* dynamic flags */
 
        /* constructor func */
-       void (*ctor)(void *, kmem_cache_t *, unsigned long);
+       void (*ctor) (void *, kmem_cache_t *, unsigned long);
 
        /* de-constructor func */
-       void (*dtor)(void *, kmem_cache_t *, unsigned long);
+       void (*dtor) (void *, kmem_cache_t *, unsigned long);
 
 /* 4) cache creation/removal */
-       const char              *name;
-       struct list_head        next;
+       const char *name;
+       struct list_head next;
 
 /* 5) statistics */
 #if STATS
-       unsigned long           num_active;
-       unsigned long           num_allocations;
-       unsigned long           high_mark;
-       unsigned long           grown;
-       unsigned long           reaped;
-       unsigned long           errors;
-       unsigned long           max_freeable;
-       unsigned long           node_allocs;
-       unsigned long           node_frees;
-       atomic_t                allochit;
-       atomic_t                allocmiss;
-       atomic_t                freehit;
-       atomic_t                freemiss;
+       unsigned long num_active;
+       unsigned long num_allocations;
+       unsigned long high_mark;
+       unsigned long grown;
+       unsigned long reaped;
+       unsigned long errors;
+       unsigned long max_freeable;
+       unsigned long node_allocs;
+       unsigned long node_frees;
+       atomic_t allochit;
+       atomic_t allocmiss;
+       atomic_t freehit;
+       atomic_t freemiss;
 #endif
 #if DEBUG
-       int                     dbghead;
-       int                     reallen;
+       int dbghead;
+       int reallen;
 #endif
 };
 
@@ -523,14 +522,15 @@ static unsigned long *dbg_redzone2(kmem_cache_t *cachep, void *objp)
 {
        BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
        if (cachep->flags & SLAB_STORE_USER)
-               return (unsigned long*) (objp+cachep->objsize-2*BYTES_PER_WORD);
-       return (unsigned long*) (objp+cachep->objsize-BYTES_PER_WORD);
+               return (unsigned long *)(objp + cachep->objsize -
+                                        2 * BYTES_PER_WORD);
+       return (unsigned long *)(objp + cachep->objsize - BYTES_PER_WORD);
 }
 
 static void **dbg_userword(kmem_cache_t *cachep, void *objp)
 {
        BUG_ON(!(cachep->flags & SLAB_STORE_USER));
-       return (void**)(objp+cachep->objsize-BYTES_PER_WORD);
+       return (void **)(objp + cachep->objsize - BYTES_PER_WORD);
 }
 
 #else
@@ -607,31 +607,31 @@ struct cache_names {
 static struct cache_names __initdata cache_names[] = {
 #define CACHE(x) { .name = "size-" #x, .name_dma = "size-" #x "(DMA)" },
 #include <linux/kmalloc_sizes.h>
-       { NULL, }
+       {NULL,}
 #undef CACHE
 };
 
 static struct arraycache_init initarray_cache __initdata =
-       { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
+    { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
 static struct arraycache_init initarray_generic =
-       { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
+    { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
 
 /* internal cache of cache description objs */
 static kmem_cache_t cache_cache = {
-       .batchcount     = 1,
-       .limit          = BOOT_CPUCACHE_ENTRIES,
-       .shared         = 1,
-       .objsize        = sizeof(kmem_cache_t),
-       .flags          = SLAB_NO_REAP,
-       .spinlock       = SPIN_LOCK_UNLOCKED,
-       .name           = "kmem_cache",
+       .batchcount = 1,
+       .limit = BOOT_CPUCACHE_ENTRIES,
+       .shared = 1,
+       .objsize = sizeof(kmem_cache_t),
+       .flags = SLAB_NO_REAP,
+       .spinlock = SPIN_LOCK_UNLOCKED,
+       .name = "kmem_cache",
 #if DEBUG
-       .reallen        = sizeof(kmem_cache_t),
+       .reallen = sizeof(kmem_cache_t),
 #endif
 };
 
 /* Guard access to the cache-chain. */
-static struct semaphore        cache_chain_sem;
+static struct semaphore cache_chain_sem;
 static struct list_head cache_chain;
 
 /*
@@ -655,9 +655,9 @@ static enum {
 
 static DEFINE_PER_CPU(struct work_struct, reap_work);
 
-static void free_block(kmem_cache_t* cachep, void** objpp, int len, int node);
-static void enable_cpucache (kmem_cache_t *cachep);
-static void cache_reap (void *unused);
+static void free_block(kmem_cache_t *cachep, void **objpp, int len, int node);
+static void enable_cpucache(kmem_cache_t *cachep);
+static void cache_reap(void *unused);
 static int __node_shrink(kmem_cache_t *cachep, int node);
 
 static inline struct array_cache *ac_data(kmem_cache_t *cachep)
@@ -671,9 +671,9 @@ static inline kmem_cache_t *__find_general_cachep(size_t size, gfp_t gfpflags)
 
 #if DEBUG
        /* This happens if someone tries to call
-       * kmem_cache_create(), or __kmalloc(), before
-       * the generic caches are initialized.
-       */
+        * kmem_cache_create(), or __kmalloc(), before
+        * the generic caches are initialized.
+        */
        BUG_ON(malloc_sizes[INDEX_AC].cs_cachep == NULL);
 #endif
        while (size > csizep->cs_size)
@@ -697,10 +697,10 @@ EXPORT_SYMBOL(kmem_find_general_cachep);
 
 /* Cal the num objs, wastage, and bytes left over for a given slab size. */
 static void cache_estimate(unsigned long gfporder, size_t size, size_t align,
-                int flags, size_t *left_over, unsigned int *num)
+                          int flags, size_t *left_over, unsigned int *num)
 {
        int i;
-       size_t wastage = PAGE_SIZE<<gfporder;
+       size_t wastage = PAGE_SIZE << gfporder;
        size_t extra = 0;
        size_t base = 0;
 
@@ -709,7 +709,7 @@ static void cache_estimate(unsigned long gfporder, size_t size, size_t align,
                extra = sizeof(kmem_bufctl_t);
        }
        i = 0;
-       while (i*size + ALIGN(base+i*extra, align) <= wastage)
+       while (i * size + ALIGN(base + i * extra, align) <= wastage)
                i++;
        if (i > 0)
                i--;
@@ -718,8 +718,8 @@ static void cache_estimate(unsigned long gfporder, size_t size, size_t align,
                i = SLAB_LIMIT;
 
        *num = i;
-       wastage -= i*size;
-       wastage -= ALIGN(base+i*extra, align);
+       wastage -= i * size;
+       wastage -= ALIGN(base + i * extra, align);
        *left_over = wastage;
 }
 
@@ -728,7 +728,7 @@ static void cache_estimate(unsigned long gfporder, size_t size, size_t align,
 static void __slab_error(const char *function, kmem_cache_t *cachep, char *msg)
 {
        printk(KERN_ERR "slab error in %s(): cache `%s': %s\n",
-               function, cachep->name, msg);
+              function, cachep->name, msg);
        dump_stack();
 }
 
@@ -755,9 +755,9 @@ static void __devinit start_cpu_timer(int cpu)
 }
 
 static struct array_cache *alloc_arraycache(int node, int entries,
-                                               int batchcount)
+                                           int batchcount)
 {
-       int memsize = sizeof(void*)*entries+sizeof(struct array_cache);
+       int memsize = sizeof(void *) * entries + sizeof(struct array_cache);
        struct array_cache *nc = NULL;
 
        nc = kmalloc_node(memsize, GFP_KERNEL, node);
@@ -775,7 +775,7 @@ static struct array_cache *alloc_arraycache(int node, int entries,
 static inline struct array_cache **alloc_alien_cache(int node, int limit)
 {
        struct array_cache **ac_ptr;
-       int memsize = sizeof(void*)*MAX_NUMNODES;
+       int memsize = sizeof(void *) * MAX_NUMNODES;
        int i;
 
        if (limit > 1)
@@ -789,7 +789,7 @@ static inline struct array_cache **alloc_alien_cache(int node, int limit)
                        }
                        ac_ptr[i] = alloc_arraycache(node, limit, 0xbaadf00d);
                        if (!ac_ptr[i]) {
-                               for (i--; i <=0; i--)
+                               for (i--; i <= 0; i--)
                                        kfree(ac_ptr[i]);
                                kfree(ac_ptr);
                                return NULL;
@@ -807,12 +807,13 @@ static inline void free_alien_cache(struct array_cache **ac_ptr)
                return;
 
        for_each_node(i)
-               kfree(ac_ptr[i]);
+           kfree(ac_ptr[i]);
 
        kfree(ac_ptr);
 }
 
-static inline void __drain_alien_cache(kmem_cache_t *cachep, struct array_cache *ac, int node)
+static inline void __drain_alien_cache(kmem_cache_t *cachep,
+                                      struct array_cache *ac, int node)
 {
        struct kmem_list3 *rl3 = cachep->nodelists[node];
 
@@ -826,7 +827,7 @@ static inline void __drain_alien_cache(kmem_cache_t *cachep, struct array_cache
 
 static void drain_alien_cache(kmem_cache_t *cachep, struct kmem_list3 *l3)
 {
-       int i=0;
+       int i = 0;
        struct array_cache *ac;
        unsigned long flags;
 
@@ -846,14 +847,13 @@ static void drain_alien_cache(kmem_cache_t *cachep, struct kmem_list3 *l3)
 #endif
 
 static int __devinit cpuup_callback(struct notifier_block *nfb,
-                                 unsigned long action, void *hcpu)
+                                   unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
-       kmem_cache_tcachep;
+       kmem_cache_t *cachep;
        struct kmem_list3 *l3 = NULL;
        int node = cpu_to_node(cpu);
        int memsize = sizeof(struct kmem_list3);
-       struct array_cache *nc = NULL;
 
        switch (action) {
        case CPU_UP_PREPARE:
@@ -871,27 +871,29 @@ static int __devinit cpuup_callback(struct notifier_block *nfb,
                         */
                        if (!cachep->nodelists[node]) {
                                if (!(l3 = kmalloc_node(memsize,
-                                               GFP_KERNEL, node)))
+                                                       GFP_KERNEL, node)))
                                        goto bad;
                                kmem_list3_init(l3);
                                l3->next_reap = jiffies + REAPTIMEOUT_LIST3 +
-                                 ((unsigned long)cachep)%REAPTIMEOUT_LIST3;
+                                   ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
 
                                cachep->nodelists[node] = l3;
                        }
 
                        spin_lock_irq(&cachep->nodelists[node]->list_lock);
                        cachep->nodelists[node]->free_limit =
-                               (1 + nr_cpus_node(node)) *
-                               cachep->batchcount + cachep->num;
+                           (1 + nr_cpus_node(node)) *
+                           cachep->batchcount + cachep->num;
                        spin_unlock_irq(&cachep->nodelists[node]->list_lock);
                }
 
                /* Now we can go ahead with allocating the shared array's
-                 & array cache's */
+                  & array cache's */
                list_for_each_entry(cachep, &cache_chain, next) {
+                       struct array_cache *nc;
+
                        nc = alloc_arraycache(node, cachep->limit,
-                                       cachep->batchcount);
+                                             cachep->batchcount);
                        if (!nc)
                                goto bad;
                        cachep->array[cpu] = nc;
@@ -900,12 +902,13 @@ static int __devinit cpuup_callback(struct notifier_block *nfb,
                        BUG_ON(!l3);
                        if (!l3->shared) {
                                if (!(nc = alloc_arraycache(node,
-                                       cachep->shared*cachep->batchcount,
-                                       0xbaadf00d)))
-                                       goto  bad;
+                                                           cachep->shared *
+                                                           cachep->batchcount,
+                                                           0xbaadf00d)))
+                                       goto bad;
 
                                /* we are serialised from CPU_DEAD or
-                                 CPU_UP_CANCELLED by the cpucontrol lock */
+                                  CPU_UP_CANCELLED by the cpucontrol lock */
                                l3->shared = nc;
                        }
                }
@@ -942,13 +945,13 @@ static int __devinit cpuup_callback(struct notifier_block *nfb,
                                free_block(cachep, nc->entry, nc->avail, node);
 
                        if (!cpus_empty(mask)) {
-                                spin_unlock(&l3->list_lock);
-                                goto unlock_cache;
-                        }
+                               spin_unlock(&l3->list_lock);
+                               goto unlock_cache;
+                       }
 
                        if (l3->shared) {
                                free_block(cachep, l3->shared->entry,
-                                               l3->shared->avail, node);
+                                          l3->shared->avail, node);
                                kfree(l3->shared);
                                l3->shared = NULL;
                        }
@@ -966,7 +969,7 @@ static int __devinit cpuup_callback(struct notifier_block *nfb,
                        } else {
                                spin_unlock(&l3->list_lock);
                        }
-unlock_cache:
+                     unlock_cache:
                        spin_unlock_irq(&cachep->spinlock);
                        kfree(nc);
                }
@@ -975,7 +978,7 @@ unlock_cache:
 #endif
        }
        return NOTIFY_OK;
-bad:
+      bad:
        up(&cache_chain_sem);
        return NOTIFY_BAD;
 }
@@ -985,8 +988,7 @@ static struct notifier_block cpucache_notifier = { &cpuup_callback, NULL, 0 };
 /*
  * swap the static kmem_list3 with kmalloced memory
  */
-static void init_list(kmem_cache_t *cachep, struct kmem_list3 *list,
-               int nodeid)
+static void init_list(kmem_cache_t *cachep, struct kmem_list3 *list, int nodeid)
 {
        struct kmem_list3 *ptr;
 
@@ -1055,14 +1057,14 @@ void __init kmem_cache_init(void)
        cache_cache.objsize = ALIGN(cache_cache.objsize, cache_line_size());
 
        cache_estimate(0, cache_cache.objsize, cache_line_size(), 0,
-                               &left_over, &cache_cache.num);
+                      &left_over, &cache_cache.num);
        if (!cache_cache.num)
                BUG();
 
-       cache_cache.colour = left_over/cache_cache.colour_off;
+       cache_cache.colour = left_over / cache_cache.colour_off;
        cache_cache.colour_next = 0;
-       cache_cache.slab_size = ALIGN(cache_cache.num*sizeof(kmem_bufctl_t) +
-                               sizeof(struct slab), cache_line_size());
+       cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +
+                                     sizeof(struct slab), cache_line_size());
 
        /* 2+3) create the kmalloc caches */
        sizes = malloc_sizes;
@@ -1074,14 +1076,18 @@ void __init kmem_cache_init(void)
         */
 
        sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name,
-                               sizes[INDEX_AC].cs_size, ARCH_KMALLOC_MINALIGN,
-                               (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL);
+                                                     sizes[INDEX_AC].cs_size,
+                                                     ARCH_KMALLOC_MINALIGN,
+                                                     (ARCH_KMALLOC_FLAGS |
+                                                      SLAB_PANIC), NULL, NULL);
 
        if (INDEX_AC != INDEX_L3)
                sizes[INDEX_L3].cs_cachep =
-                       kmem_cache_create(names[INDEX_L3].name,
-                               sizes[INDEX_L3].cs_size, ARCH_KMALLOC_MINALIGN,
-                               (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL);
+                   kmem_cache_create(names[INDEX_L3].name,
+                                     sizes[INDEX_L3].cs_size,
+                                     ARCH_KMALLOC_MINALIGN,
+                                     (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL,
+                                     NULL);
 
        while (sizes->cs_size != ULONG_MAX) {
                /*
@@ -1091,35 +1097,41 @@ void __init kmem_cache_init(void)
                 * Note for systems short on memory removing the alignment will
                 * allow tighter packing of the smaller caches.
                 */
-               if(!sizes->cs_cachep)
+               if (!sizes->cs_cachep)
                        sizes->cs_cachep = kmem_cache_create(names->name,
-                               sizes->cs_size, ARCH_KMALLOC_MINALIGN,
-                               (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL);
+                                                            sizes->cs_size,
+                                                            ARCH_KMALLOC_MINALIGN,
+                                                            (ARCH_KMALLOC_FLAGS
+                                                             | SLAB_PANIC),
+                                                            NULL, NULL);
 
                /* Inc off-slab bufctl limit until the ceiling is hit. */
                if (!(OFF_SLAB(sizes->cs_cachep))) {
-                       offslab_limit = sizes->cs_size-sizeof(struct slab);
+                       offslab_limit = sizes->cs_size - sizeof(struct slab);
                        offslab_limit /= sizeof(kmem_bufctl_t);
                }
 
                sizes->cs_dmacachep = kmem_cache_create(names->name_dma,
-                       sizes->cs_size, ARCH_KMALLOC_MINALIGN,
-                       (ARCH_KMALLOC_FLAGS | SLAB_CACHE_DMA | SLAB_PANIC),
-                       NULL, NULL);
+                                                       sizes->cs_size,
+                                                       ARCH_KMALLOC_MINALIGN,
+                                                       (ARCH_KMALLOC_FLAGS |
+                                                        SLAB_CACHE_DMA |
+                                                        SLAB_PANIC), NULL,
+                                                       NULL);
 
                sizes++;
                names++;
        }
        /* 4) Replace the bootstrap head arrays */
        {
-               void * ptr;
+               void *ptr;
 
                ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL);
 
                local_irq_disable();
                BUG_ON(ac_data(&cache_cache) != &initarray_cache.cache);
                memcpy(ptr, ac_data(&cache_cache),
-                               sizeof(struct arraycache_init));
+                      sizeof(struct arraycache_init));
                cache_cache.array[smp_processor_id()] = ptr;
                local_irq_enable();
 
@@ -1127,11 +1139,11 @@ void __init kmem_cache_init(void)
 
                local_irq_disable();
                BUG_ON(ac_data(malloc_sizes[INDEX_AC].cs_cachep)
-                               != &initarray_generic.cache);
+                      != &initarray_generic.cache);
                memcpy(ptr, ac_data(malloc_sizes[INDEX_AC].cs_cachep),
-                               sizeof(struct arraycache_init));
+                      sizeof(struct arraycache_init));
                malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] =
-                                               ptr;
+                   ptr;
                local_irq_enable();
        }
        /* 5) Replace the bootstrap kmem_list3's */
@@ -1139,16 +1151,16 @@ void __init kmem_cache_init(void)
                int node;
                /* Replace the static kmem_list3 structures for the boot cpu */
                init_list(&cache_cache, &initkmem_list3[CACHE_CACHE],
-                               numa_node_id());
+                         numa_node_id());
 
                for_each_online_node(node) {
                        init_list(malloc_sizes[INDEX_AC].cs_cachep,
-                                       &initkmem_list3[SIZE_AC+node], node);
+                                 &initkmem_list3[SIZE_AC + node], node);
 
                        if (INDEX_AC != INDEX_L3) {
                                init_list(malloc_sizes[INDEX_L3].cs_cachep,
-                                               &initkmem_list3[SIZE_L3+node],
-                                               node);
+                                         &initkmem_list3[SIZE_L3 + node],
+                                         node);
                        }
                }
        }
@@ -1158,7 +1170,7 @@ void __init kmem_cache_init(void)
                kmem_cache_t *cachep;
                down(&cache_chain_sem);
                list_for_each_entry(cachep, &cache_chain, next)
-                       enable_cpucache(cachep);
+                   enable_cpucache(cachep);
                up(&cache_chain_sem);
        }
 
@@ -1184,7 +1196,7 @@ static int __init cpucache_init(void)
         * pages to gfp.
         */
        for_each_online_cpu(cpu)
-               start_cpu_timer(cpu);
+           start_cpu_timer(cpu);
 
        return 0;
 }
@@ -1226,7 +1238,7 @@ static void *kmem_getpages(kmem_cache_t *cachep, gfp_t flags, int nodeid)
  */
 static void kmem_freepages(kmem_cache_t *cachep, void *addr)
 {
-       unsigned long i = (1<<cachep->gfporder);
+       unsigned long i = (1 << cachep->gfporder);
        struct page *page = virt_to_page(addr);
        const unsigned long nr_freed = i;
 
@@ -1239,13 +1251,13 @@ static void kmem_freepages(kmem_cache_t *cachep, void *addr)
        if (current->reclaim_state)
                current->reclaim_state->reclaimed_slab += nr_freed;
        free_pages((unsigned long)addr, cachep->gfporder);
-       if (cachep->flags & SLAB_RECLAIM_ACCOUNT) 
-               atomic_sub(1<<cachep->gfporder, &slab_reclaim_pages);
+       if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
+               atomic_sub(1 << cachep->gfporder, &slab_reclaim_pages);
 }
 
 static void kmem_rcu_free(struct rcu_head *head)
 {
-       struct slab_rcu *slab_rcu = (struct slab_rcu *) head;
+       struct slab_rcu *slab_rcu = (struct slab_rcu *)head;
        kmem_cache_t *cachep = slab_rcu->cachep;
 
        kmem_freepages(cachep, slab_rcu->addr);
@@ -1257,19 +1269,19 @@ static void kmem_rcu_free(struct rcu_head *head)
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr,
-                               unsigned long caller)
+                           unsigned long caller)
 {
        int size = obj_reallen(cachep);
 
-       addr = (unsigned long *)&((char*)addr)[obj_dbghead(cachep)];
+       addr = (unsigned long *)&((char *)addr)[obj_dbghead(cachep)];
 
-       if (size < 5*sizeof(unsigned long))
+       if (size < 5 * sizeof(unsigned long))
                return;
 
-       *addr++=0x12345678;
-       *addr++=caller;
-       *addr++=smp_processor_id();
-       size -= 3*sizeof(unsigned long);
+       *addr++ = 0x12345678;
+       *addr++ = caller;
+       *addr++ = smp_processor_id();
+       size -= 3 * sizeof(unsigned long);
        {
                unsigned long *sptr = &caller;
                unsigned long svalue;
@@ -1277,7 +1289,7 @@ static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr,
                while (!kstack_end(sptr)) {
                        svalue = *sptr++;
                        if (kernel_text_address(svalue)) {
-                               *addr++=svalue;
+                               *addr++ = svalue;
                                size -= sizeof(unsigned long);
                                if (size <= sizeof(unsigned long))
                                        break;
@@ -1285,25 +1297,25 @@ static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr,
                }
 
        }
-       *addr++=0x87654321;
+       *addr++ = 0x87654321;
 }
 #endif
 
 static void poison_obj(kmem_cache_t *cachep, void *addr, unsigned char val)
 {
        int size = obj_reallen(cachep);
-       addr = &((char*)addr)[obj_dbghead(cachep)];
+       addr = &((char *)addr)[obj_dbghead(cachep)];
 
        memset(addr, val, size);
-       *(unsigned char *)(addr+size-1) = POISON_END;
+       *(unsigned char *)(addr + size - 1) = POISON_END;
 }
 
 static void dump_line(char *data, int offset, int limit)
 {
        int i;
        printk(KERN_ERR "%03x:", offset);
-       for (i=0;i<limit;i++) {
-               printk(" %02x", (unsigned char)data[offset+i]);
+       for (i = 0; i < limit; i++) {
+               printk(" %02x", (unsigned char)data[offset + i]);
        }
        printk("\n");
 }
@@ -1318,24 +1330,24 @@ static void print_objinfo(kmem_cache_t *cachep, void *objp, int lines)
 
        if (cachep->flags & SLAB_RED_ZONE) {
                printk(KERN_ERR "Redzone: 0x%lx/0x%lx.\n",
-                       *dbg_redzone1(cachep, objp),
-                       *dbg_redzone2(cachep, objp));
+                      *dbg_redzone1(cachep, objp),
+                      *dbg_redzone2(cachep, objp));
        }
 
        if (cachep->flags & SLAB_STORE_USER) {
                printk(KERN_ERR "Last user: [<%p>]",
-                               *dbg_userword(cachep, objp));
+                      *dbg_userword(cachep, objp));
                print_symbol("(%s)",
-                               (unsigned long)*dbg_userword(cachep, objp));
+                            (unsigned long)*dbg_userword(cachep, objp));
                printk("\n");
        }
-       realobj = (char*)objp+obj_dbghead(cachep);
+       realobj = (char *)objp + obj_dbghead(cachep);
        size = obj_reallen(cachep);
-       for (i=0; i<size && lines;i+=16, lines--) {
+       for (i = 0; i < size && lines; i += 16, lines--) {
                int limit;
                limit = 16;
-               if (i+limit > size)
-                       limit = size-i;
+               if (i + limit > size)
+                       limit = size - i;
                dump_line(realobj, i, limit);
        }
 }
@@ -1346,27 +1358,28 @@ static void check_poison_obj(kmem_cache_t *cachep, void *objp)
        int size, i;
        int lines = 0;
 
-       realobj = (char*)objp+obj_dbghead(cachep);
+       realobj = (char *)objp + obj_dbghead(cachep);
        size = obj_reallen(cachep);
 
-       for (i=0;i<size;i++) {
+       for (i = 0; i < size; i++) {
                char exp = POISON_FREE;
-               if (i == size-1)
+               if (i == size - 1)
                        exp = POISON_END;
                if (realobj[i] != exp) {
                        int limit;
                        /* Mismatch ! */
                        /* Print header */
                        if (lines == 0) {
-                               printk(KERN_ERR "Slab corruption: start=%p, len=%d\n",
-                                               realobj, size);
+                               printk(KERN_ERR
+                                      "Slab corruption: start=%p, len=%d\n",
+                                      realobj, size);
                                print_objinfo(cachep, objp, 0);
                        }
                        /* Hexdump the affected line */
-                       i = (i/16)*16;
+                       i = (i / 16) * 16;
                        limit = 16;
-                       if (i+limit > size)
-                               limit = size-i;
+                       if (i + limit > size)
+                               limit = size - i;
                        dump_line(realobj, i, limit);
                        i += 16;
                        lines++;
@@ -1382,19 +1395,19 @@ static void check_poison_obj(kmem_cache_t *cachep, void *objp)
                struct slab *slabp = page_get_slab(virt_to_page(objp));
                int objnr;
 
-               objnr = (objp-slabp->s_mem)/cachep->objsize;
+               objnr = (objp - slabp->s_mem) / cachep->objsize;
                if (objnr) {
-                       objp = slabp->s_mem+(objnr-1)*cachep->objsize;
-                       realobj = (char*)objp+obj_dbghead(cachep);
+                       objp = slabp->s_mem + (objnr - 1) * cachep->objsize;
+                       realobj = (char *)objp + obj_dbghead(cachep);
                        printk(KERN_ERR "Prev obj: start=%p, len=%d\n",
-                                               realobj, size);
+                              realobj, size);
                        print_objinfo(cachep, objp, 2);
                }
-               if (objnr+1 < cachep->num) {
-                       objp = slabp->s_mem+(objnr+1)*cachep->objsize;
-                       realobj = (char*)objp+obj_dbghead(cachep);
+               if (objnr + 1 < cachep->num) {
+                       objp = slabp->s_mem + (objnr + 1) * cachep->objsize;
+                       realobj = (char *)objp + obj_dbghead(cachep);
                        printk(KERN_ERR "Next obj: start=%p, len=%d\n",
-                                               realobj, size);
+                              realobj, size);
                        print_objinfo(cachep, objp, 2);
                }
        }
@@ -1405,7 +1418,7 @@ static void check_poison_obj(kmem_cache_t *cachep, void *objp)
  * Before calling the slab must have been unlinked from the cache.
  * The cache-lock is not held/needed.
  */
-static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
+static void slab_destroy(kmem_cache_t *cachep, struct slab *slabp)
 {
        void *addr = slabp->s_mem - slabp->colouroff;
 
@@ -1416,8 +1429,11 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
 
                if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
-                       if ((cachep->objsize%PAGE_SIZE)==0 && OFF_SLAB(cachep))
-                               kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE,1);
+                       if ((cachep->objsize % PAGE_SIZE) == 0
+                           && OFF_SLAB(cachep))
+                               kernel_map_pages(virt_to_page(objp),
+                                                cachep->objsize / PAGE_SIZE,
+                                                1);
                        else
                                check_poison_obj(cachep, objp);
 #else
@@ -1427,20 +1443,20 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
                if (cachep->flags & SLAB_RED_ZONE) {
                        if (*dbg_redzone1(cachep, objp) != RED_INACTIVE)
                                slab_error(cachep, "start of a freed object "
-                                                       "was overwritten");
+                                          "was overwritten");
                        if (*dbg_redzone2(cachep, objp) != RED_INACTIVE)
                                slab_error(cachep, "end of a freed object "
-                                                       "was overwritten");
+                                          "was overwritten");
                }
                if (cachep->dtor && !(cachep->flags & SLAB_POISON))
-                       (cachep->dtor)(objp+obj_dbghead(cachep), cachep, 0);
+                       (cachep->dtor) (objp + obj_dbghead(cachep), cachep, 0);
        }
 #else
        if (cachep->dtor) {
                int i;
                for (i = 0; i < cachep->num; i++) {
-                       void* objp = slabp->s_mem+cachep->objsize*i;
-                       (cachep->dtor)(objp, cachep, 0);
+                       void *objp = slabp->s_mem + cachep->objsize * i;
+                       (cachep->dtor) (objp, cachep, 0);
                }
        }
 #endif
@@ -1448,7 +1464,7 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
        if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) {
                struct slab_rcu *slab_rcu;
 
-               slab_rcu = (struct slab_rcu *) slabp;
+               slab_rcu = (struct slab_rcu *)slabp;
                slab_rcu->cachep = cachep;
                slab_rcu->addr = addr;
                call_rcu(&slab_rcu->head, kmem_rcu_free);
@@ -1466,11 +1482,58 @@ static inline void set_up_list3s(kmem_cache_t *cachep, int index)
        int node;
 
        for_each_online_node(node) {
-               cachep->nodelists[node] = &initkmem_list3[index+node];
+               cachep->nodelists[node] = &initkmem_list3[index + node];
                cachep->nodelists[node]->next_reap = jiffies +
-                       REAPTIMEOUT_LIST3 +
-                       ((unsigned long)cachep)%REAPTIMEOUT_LIST3;
+                   REAPTIMEOUT_LIST3 +
+                   ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
+       }
+}
+
+/**
+ * calculate_slab_order - calculate size (page order) of slabs and the number
+ *                        of objects per slab.
+ *
+ * This could be made much more intelligent.  For now, try to avoid using
+ * high order pages for slabs.  When the gfp() functions are more friendly
+ * towards high-order requests, this should be changed.
+ */
+static inline size_t calculate_slab_order(kmem_cache_t *cachep, size_t size,
+                                         size_t align, gfp_t flags)
+{
+       size_t left_over = 0;
+
+       for (;; cachep->gfporder++) {
+               unsigned int num;
+               size_t remainder;
+
+               if (cachep->gfporder > MAX_GFP_ORDER) {
+                       cachep->num = 0;
+                       break;
+               }
+
+               cache_estimate(cachep->gfporder, size, align, flags,
+                              &remainder, &num);
+               if (!num)
+                       continue;
+               /* More than offslab_limit objects will cause problems */
+               if (flags & CFLGS_OFF_SLAB && cachep->num > offslab_limit)
+                       break;
+
+               cachep->num = num;
+               left_over = remainder;
+
+               /*
+                * Large number of objects is good, but very large slabs are
+                * currently bad for the gfp()s.
+                */
+               if (cachep->gfporder >= slab_break_gfp_order)
+                       break;
+
+               if ((left_over * 8) <= (PAGE_SIZE << cachep->gfporder))
+                       /* Acceptable internal fragmentation */
+                       break;
        }
+       return left_over;
 }
 
 /**
@@ -1519,14 +1582,13 @@ 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 > (1<<MAX_OBJ_ORDER)*PAGE_SIZE) ||
-               (dtor && !ctor)) {
-                       printk(KERN_ERR "%s: Early error in slab %s\n",
-                                       __FUNCTION__, name);
-                       BUG();
-               }
+           in_interrupt() ||
+           (size < BYTES_PER_WORD) ||
+           (size > (1 << MAX_OBJ_ORDER) * PAGE_SIZE) || (dtor && !ctor)) {
+               printk(KERN_ERR "%s: Early error in slab %s\n",
+                      __FUNCTION__, name);
+               BUG();
+       }
 
        down(&cache_chain_sem);
 
@@ -1546,11 +1608,11 @@ kmem_cache_create (const char *name, size_t size, size_t align,
                set_fs(old_fs);
                if (res) {
                        printk("SLAB: cache with size %d has lost its name\n",
-                                       pc->objsize);
+                              pc->objsize);
                        continue;
                }
 
-               if (!strcmp(pc->name,name)) {
+               if (!strcmp(pc->name, name)) {
                        printk("kmem_cache_create: duplicate cache %s\n", name);
                        dump_stack();
                        goto oops;
@@ -1562,10 +1624,9 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
                /* No constructor, but inital state check requested */
                printk(KERN_ERR "%s: No con, but init state check "
-                               "requested - %s\n", __FUNCTION__, name);
+                      "requested - %s\n", __FUNCTION__, name);
                flags &= ~SLAB_DEBUG_INITIAL;
        }
-
 #if FORCED_DEBUG
        /*
         * Enable redzoning and last user accounting, except for caches with
@@ -1573,8 +1634,9 @@ kmem_cache_create (const char *name, size_t size, size_t align,
         * above the next power of two: caches with object sizes just above a
         * power of two have a significant amount of internal fragmentation.
         */
-       if ((size < 4096 || fls(size-1) == fls(size-1+3*BYTES_PER_WORD)))
-               flags |= SLAB_RED_ZONE|SLAB_STORE_USER;
+       if ((size < 4096
+            || fls(size - 1) == fls(size - 1 + 3 * BYTES_PER_WORD)))
+               flags |= SLAB_RED_ZONE | SLAB_STORE_USER;
        if (!(flags & SLAB_DESTROY_BY_RCU))
                flags |= SLAB_POISON;
 #endif
@@ -1595,9 +1657,9 @@ kmem_cache_create (const char *name, size_t size, size_t align,
         * unaligned accesses for some archs when redzoning is used, and makes
         * sure any on-slab bufctl's are also correctly aligned.
         */
-       if (size & (BYTES_PER_WORD-1)) {
-               size += (BYTES_PER_WORD-1);
-               size &= ~(BYTES_PER_WORD-1);
+       if (size & (BYTES_PER_WORD - 1)) {
+               size += (BYTES_PER_WORD - 1);
+               size &= ~(BYTES_PER_WORD - 1);
        }
 
        /* calculate out the final buffer alignment: */
@@ -1608,7 +1670,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
                 * objects into one cacheline.
                 */
                ralign = cache_line_size();
-               while (size <= ralign/2)
+               while (size <= ralign / 2)
                        ralign /= 2;
        } else {
                ralign = BYTES_PER_WORD;
@@ -1617,13 +1679,13 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        if (ralign < ARCH_SLAB_MINALIGN) {
                ralign = ARCH_SLAB_MINALIGN;
                if (ralign > BYTES_PER_WORD)
-                       flags &= ~(SLAB_RED_ZONE|SLAB_STORE_USER);
+                       flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
        }
        /* 3) caller mandated alignment: disables debug if necessary */
        if (ralign < align) {
                ralign = align;
                if (ralign > BYTES_PER_WORD)
-                       flags &= ~(SLAB_RED_ZONE|SLAB_STORE_USER);
+                       flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
        }
        /* 4) Store it. Note that the debug code below can reduce
         *    the alignment to BYTES_PER_WORD.
@@ -1645,7 +1707,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 
                /* add space for red zone words */
                cachep->dbghead += BYTES_PER_WORD;
-               size += 2*BYTES_PER_WORD;
+               size += 2 * BYTES_PER_WORD;
        }
        if (flags & SLAB_STORE_USER) {
                /* user store requires word alignment and
@@ -1656,7 +1718,8 @@ kmem_cache_create (const char *name, size_t size, size_t align,
                size += BYTES_PER_WORD;
        }
 #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC)
-       if (size >= malloc_sizes[INDEX_L3+1].cs_size && cachep->reallen > cache_line_size() && size < PAGE_SIZE) {
+       if (size >= malloc_sizes[INDEX_L3 + 1].cs_size
+           && cachep->reallen > cache_line_size() && size < PAGE_SIZE) {
                cachep->dbghead += PAGE_SIZE - size;
                size = PAGE_SIZE;
        }
@@ -1664,7 +1727,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 #endif
 
        /* Determine if the slab management is 'on' or 'off' slab. */
-       if (size >= (PAGE_SIZE>>3))
+       if (size >= (PAGE_SIZE >> 3))
                /*
                 * Size is large, assume best to place the slab management obj
                 * off-slab (should allow better packing of objs).
@@ -1681,47 +1744,9 @@ kmem_cache_create (const char *name, size_t size, size_t align,
                 */
                cachep->gfporder = 0;
                cache_estimate(cachep->gfporder, size, align, flags,
-                                       &left_over, &cachep->num);
-       } else {
-               /*
-                * Calculate size (in pages) of slabs, and the num of objs per
-                * slab.  This could be made much more intelligent.  For now,
-                * try to avoid using high page-orders for slabs.  When the
-                * gfp() funcs are more friendly towards high-order requests,
-                * this should be changed.
-                */
-               do {
-                       unsigned int break_flag = 0;
-cal_wastage:
-                       cache_estimate(cachep->gfporder, size, align, flags,
-                                               &left_over, &cachep->num);
-                       if (break_flag)
-                               break;
-                       if (cachep->gfporder >= MAX_GFP_ORDER)
-                               break;
-                       if (!cachep->num)
-                               goto next;
-                       if (flags & CFLGS_OFF_SLAB &&
-                                       cachep->num > offslab_limit) {
-                               /* This num of objs will cause problems. */
-                               cachep->gfporder--;
-                               break_flag++;
-                               goto cal_wastage;
-                       }
-
-                       /*
-                        * Large num of objs is good, but v. large slabs are
-                        * currently bad for the gfp()s.
-                        */
-                       if (cachep->gfporder >= slab_break_gfp_order)
-                               break;
-
-                       if ((left_over*8) <= (PAGE_SIZE<<cachep->gfporder))
-                               break;  /* Acceptable internal fragmentation. */
-next:
-                       cachep->gfporder++;
-               } while (1);
-       }
+                              &left_over, &cachep->num);
+       } else
+               left_over = calculate_slab_order(cachep, size, align, flags);
 
        if (!cachep->num) {
                printk("kmem_cache_create: couldn't create cache %s.\n", name);
@@ -1729,8 +1754,8 @@ next:
                cachep = NULL;
                goto oops;
        }
-       slab_size = ALIGN(cachep->num*sizeof(kmem_bufctl_t)
-                               + sizeof(struct slab), align);
+       slab_size = ALIGN(cachep->num * sizeof(kmem_bufctl_t)
+                         + sizeof(struct slab), align);
 
        /*
         * If the slab has been placed off-slab, and we have enough space then
@@ -1743,14 +1768,15 @@ next:
 
        if (flags & CFLGS_OFF_SLAB) {
                /* really off slab. No need for manual alignment */
-               slab_size = cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab);
+               slab_size =
+                   cachep->num * sizeof(kmem_bufctl_t) + sizeof(struct slab);
        }
 
        cachep->colour_off = cache_line_size();
        /* Offset must be a multiple of the alignment. */
        if (cachep->colour_off < align)
                cachep->colour_off = align;
-       cachep->colour = left_over/cachep->colour_off;
+       cachep->colour = left_over / cachep->colour_off;
        cachep->slab_size = slab_size;
        cachep->flags = flags;
        cachep->gfpflags = 0;
@@ -1777,7 +1803,7 @@ next:
                         * the creation of further caches will BUG().
                         */
                        cachep->array[smp_processor_id()] =
-                               &initarray_generic.cache;
+                           &initarray_generic.cache;
 
                        /* If the cache that's used by
                         * kmalloc(sizeof(kmem_list3)) is the first cache,
@@ -1791,8 +1817,7 @@ next:
                                g_cpucache_up = PARTIAL_AC;
                } else {
                        cachep->array[smp_processor_id()] =
-                               kmalloc(sizeof(struct arraycache_init),
-                                               GFP_KERNEL);
+                           kmalloc(sizeof(struct arraycache_init), GFP_KERNEL);
 
                        if (g_cpucache_up == PARTIAL_AC) {
                                set_up_list3s(cachep, SIZE_L3);
@@ -1802,16 +1827,18 @@ next:
                                for_each_online_node(node) {
 
                                        cachep->nodelists[node] =
-                                               kmalloc_node(sizeof(struct kmem_list3),
-                                                               GFP_KERNEL, node);
+                                           kmalloc_node(sizeof
+                                                        (struct kmem_list3),
+                                                        GFP_KERNEL, node);
                                        BUG_ON(!cachep->nodelists[node]);
-                                       kmem_list3_init(cachep->nodelists[node]);
+                                       kmem_list3_init(cachep->
+                                                       nodelists[node]);
                                }
                        }
                }
                cachep->nodelists[numa_node_id()]->next_reap =
-                       jiffies + REAPTIMEOUT_LIST3 +
-                       ((unsigned long)cachep)%REAPTIMEOUT_LIST3;
+                   jiffies + REAPTIMEOUT_LIST3 +
+                   ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
 
                BUG_ON(!ac_data(cachep));
                ac_data(cachep)->avail = 0;
@@ -1820,15 +1847,15 @@ next:
                ac_data(cachep)->touched = 0;
                cachep->batchcount = 1;
                cachep->limit = BOOT_CPUCACHE_ENTRIES;
-       } 
+       }
 
        /* cache setup completed, link it into the list */
        list_add(&cachep->next, &cache_chain);
        unlock_cpu_hotplug();
-oops:
+      oops:
        if (!cachep && (flags & SLAB_PANIC))
                panic("kmem_cache_create(): failed to create slab `%s'\n",
-                       name);
+                     name);
        up(&cache_chain_sem);
        return cachep;
 }
@@ -1871,7 +1898,7 @@ static inline void check_spinlock_acquired_node(kmem_cache_t *cachep, int node)
 /*
  * Waits for all CPUs to execute func().
  */
-static void smp_call_function_all_cpus(void (*func) (void *arg), void *arg)
+static void smp_call_function_all_cpus(void (*func)(void *arg), void *arg)
 {
        check_irq_on();
        preempt_disable();
@@ -1886,12 +1913,12 @@ static void smp_call_function_all_cpus(void (*func) (void *arg), void *arg)
        preempt_enable();
 }
 
-static void drain_array_locked(kmem_cache_t* cachep,
-                               struct array_cache *ac, int force, int node);
+static void drain_array_locked(kmem_cache_t *cachep, struct array_cache *ac,
+                               int force, int node);
 
 static void do_drain(void *arg)
 {
-       kmem_cache_t *cachep = (kmem_cache_t*)arg;
+       kmem_cache_t *cachep = (kmem_cache_t *) arg;
        struct array_cache *ac;
        int node = numa_node_id();
 
@@ -1911,7 +1938,7 @@ static void drain_cpu_caches(kmem_cache_t *cachep)
        smp_call_function_all_cpus(do_drain, cachep);
        check_irq_on();
        spin_lock_irq(&cachep->spinlock);
-       for_each_online_node(node)  {
+       for_each_online_node(node) {
                l3 = cachep->nodelists[node];
                if (l3) {
                        spin_lock(&l3->list_lock);
@@ -1949,8 +1976,7 @@ static int __node_shrink(kmem_cache_t *cachep, int node)
                slab_destroy(cachep, slabp);
                spin_lock_irq(&l3->list_lock);
        }
-       ret = !list_empty(&l3->slabs_full) ||
-               !list_empty(&l3->slabs_partial);
+       ret = !list_empty(&l3->slabs_full) || !list_empty(&l3->slabs_partial);
        return ret;
 }
 
@@ -2006,7 +2032,7 @@ EXPORT_SYMBOL(kmem_cache_shrink);
  * The caller must guarantee that noone will allocate memory from the cache
  * during the kmem_cache_destroy().
  */
-int kmem_cache_destroy(kmem_cache_t * cachep)
+int kmem_cache_destroy(kmem_cache_t *cachep)
 {
        int i;
        struct kmem_list3 *l3;
@@ -2028,7 +2054,7 @@ int kmem_cache_destroy(kmem_cache_t * cachep)
        if (__cache_shrink(cachep)) {
                slab_error(cachep, "Can't free all objects");
                down(&cache_chain_sem);
-               list_add(&cachep->next,&cache_chain);
+               list_add(&cachep->next, &cache_chain);
                up(&cache_chain_sem);
                unlock_cpu_hotplug();
                return 1;
@@ -2038,7 +2064,7 @@ int kmem_cache_destroy(kmem_cache_t * cachep)
                synchronize_rcu();
 
        for_each_online_cpu(i)
-               kfree(cachep->array[i]);
+           kfree(cachep->array[i]);
 
        /* NUMA: free the list3 structures */
        for_each_online_node(i) {
@@ -2057,39 +2083,39 @@ int kmem_cache_destroy(kmem_cache_t * cachep)
 EXPORT_SYMBOL(kmem_cache_destroy);
 
 /* Get the memory for a slab management obj. */
-static struct slaballoc_slabmgmt(kmem_cache_t *cachep, void *objp,
-                       int colour_off, gfp_t local_flags)
+static struct slab *alloc_slabmgmt(kmem_cache_t *cachep, void *objp,
+                                  int colour_off, gfp_t local_flags)
 {
        struct slab *slabp;
-       
+
        if (OFF_SLAB(cachep)) {
                /* Slab management obj is off-slab. */
                slabp = kmem_cache_alloc(cachep->slabp_cache, local_flags);
                if (!slabp)
                        return NULL;
        } else {
-               slabp = objp+colour_off;
+               slabp = objp + colour_off;
                colour_off += cachep->slab_size;
        }
        slabp->inuse = 0;
        slabp->colouroff = colour_off;
-       slabp->s_mem = objp+colour_off;
+       slabp->s_mem = objp + colour_off;
 
        return slabp;
 }
 
 static inline kmem_bufctl_t *slab_bufctl(struct slab *slabp)
 {
-       return (kmem_bufctl_t *)(slabp+1);
+       return (kmem_bufctl_t *) (slabp + 1);
 }
 
 static void cache_init_objs(kmem_cache_t *cachep,
-                       struct slab *slabp, unsigned long ctor_flags)
+                           struct slab *slabp, unsigned long ctor_flags)
 {
        int i;
 
        for (i = 0; i < cachep->num; i++) {
-               void *objp = slabp->s_mem+cachep->objsize*i;
+               void *objp = slabp->s_mem + cachep->objsize * i;
 #if DEBUG
                /* need to poison the objs? */
                if (cachep->flags & SLAB_POISON)
@@ -2107,25 +2133,28 @@ static void cache_init_objs(kmem_cache_t *cachep,
                 * Otherwise, deadlock. They must also be threaded.
                 */
                if (cachep->ctor && !(cachep->flags & SLAB_POISON))
-                       cachep->ctor(objp+obj_dbghead(cachep), cachep, ctor_flags);
+                       cachep->ctor(objp + obj_dbghead(cachep), cachep,
+                                    ctor_flags);
 
                if (cachep->flags & SLAB_RED_ZONE) {
                        if (*dbg_redzone2(cachep, objp) != RED_INACTIVE)
                                slab_error(cachep, "constructor overwrote the"
-                                                       " end of an object");
+                                          " end of an object");
                        if (*dbg_redzone1(cachep, objp) != RED_INACTIVE)
                                slab_error(cachep, "constructor overwrote the"
-                                                       " start of an object");
+                                          " start of an object");
                }
-               if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep) && cachep->flags & SLAB_POISON)
-                       kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0);
+               if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep)
+                   && cachep->flags & SLAB_POISON)
+                       kernel_map_pages(virt_to_page(objp),
+                                        cachep->objsize / PAGE_SIZE, 0);
 #else
                if (cachep->ctor)
                        cachep->ctor(objp, cachep, ctor_flags);
 #endif
-               slab_bufctl(slabp)[i] = i+1;
+               slab_bufctl(slabp)[i] = i + 1;
        }
-       slab_bufctl(slabp)[i-1] = BUFCTL_END;
+       slab_bufctl(slabp)[i - 1] = BUFCTL_END;
        slabp->free = 0;
 }
 
@@ -2161,17 +2190,17 @@ static void set_slab_attr(kmem_cache_t *cachep, struct slab *slabp, void *objp)
  */
 static int cache_grow(kmem_cache_t *cachep, gfp_t flags, int nodeid)
 {
-       struct slab     *slabp;
-       void            *objp;
-       size_t           offset;
-       gfp_t            local_flags;
-       unsigned long    ctor_flags;
+       struct slab *slabp;
+       void *objp;
+       size_t offset;
+       gfp_t local_flags;
+       unsigned long ctor_flags;
        struct kmem_list3 *l3;
 
        /* Be lazy and only check for valid flags here,
-        * keeping it out of the critical path in kmem_cache_alloc().
+        * keeping it out of the critical path in kmem_cache_alloc().
         */
-       if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW))
+       if (flags & ~(SLAB_DMA | SLAB_LEVEL_MASK | SLAB_NO_GROW))
                BUG();
        if (flags & SLAB_NO_GROW)
                return 0;
@@ -2237,9 +2266,9 @@ static int cache_grow(kmem_cache_t *cachep, gfp_t flags, int nodeid)
        l3->free_objects += cachep->num;
        spin_unlock(&l3->list_lock);
        return 1;
-opps1:
+      opps1:
        kmem_freepages(cachep, objp);
-failed:
+      failed:
        if (local_flags & __GFP_WAIT)
                local_irq_disable();
        return 0;
@@ -2259,18 +2288,19 @@ static void kfree_debugcheck(const void *objp)
 
        if (!virt_addr_valid(objp)) {
                printk(KERN_ERR "kfree_debugcheck: out of range ptr %lxh.\n",
-                       (unsigned long)objp);   
-               BUG();  
+                      (unsigned long)objp);
+               BUG();
        }
        page = virt_to_page(objp);
        if (!PageSlab(page)) {
-               printk(KERN_ERR "kfree_debugcheck: bad ptr %lxh.\n", (unsigned long)objp);
+               printk(KERN_ERR "kfree_debugcheck: bad ptr %lxh.\n",
+                      (unsigned long)objp);
                BUG();
        }
 }
 
 static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp,
-                                       void *caller)
+                                  void *caller)
 {
        struct page *page;
        unsigned int objnr;
@@ -2281,20 +2311,26 @@ static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp,
        page = virt_to_page(objp);
 
        if (page_get_cache(page) != cachep) {
-               printk(KERN_ERR "mismatch in kmem_cache_free: expected cache %p, got %p\n",
-                               page_get_cache(page),cachep);
+               printk(KERN_ERR
+                      "mismatch in kmem_cache_free: expected cache %p, got %p\n",
+                      page_get_cache(page), cachep);
                printk(KERN_ERR "%p is %s.\n", cachep, cachep->name);
-               printk(KERN_ERR "%p is %s.\n", page_get_cache(page), page_get_cache(page)->name);
+               printk(KERN_ERR "%p is %s.\n", page_get_cache(page),
+                      page_get_cache(page)->name);
                WARN_ON(1);
        }
        slabp = page_get_slab(page);
 
        if (cachep->flags & SLAB_RED_ZONE) {
-               if (*dbg_redzone1(cachep, objp) != RED_ACTIVE || *dbg_redzone2(cachep, objp) != RED_ACTIVE) {
-                       slab_error(cachep, "double free, or memory outside"
-                                               " object was overwritten");
-                       printk(KERN_ERR "%p: redzone 1: 0x%lx, redzone 2: 0x%lx.\n",
-                                       objp, *dbg_redzone1(cachep, objp), *dbg_redzone2(cachep, objp));
+               if (*dbg_redzone1(cachep, objp) != RED_ACTIVE
+                   || *dbg_redzone2(cachep, objp) != RED_ACTIVE) {
+                       slab_error(cachep,
+                                  "double free, or memory outside"
+                                  " object was overwritten");
+                       printk(KERN_ERR
+                              "%p: redzone 1: 0x%lx, redzone 2: 0x%lx.\n",
+                              objp, *dbg_redzone1(cachep, objp),
+                              *dbg_redzone2(cachep, objp));
                }
                *dbg_redzone1(cachep, objp) = RED_INACTIVE;
                *dbg_redzone2(cachep, objp) = RED_INACTIVE;
@@ -2302,30 +2338,31 @@ static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp,
        if (cachep->flags & SLAB_STORE_USER)
                *dbg_userword(cachep, objp) = caller;
 
-       objnr = (objp-slabp->s_mem)/cachep->objsize;
+       objnr = (objp - slabp->s_mem) / cachep->objsize;
 
        BUG_ON(objnr >= cachep->num);
-       BUG_ON(objp != slabp->s_mem + objnr*cachep->objsize);
+       BUG_ON(objp != slabp->s_mem + objnr * cachep->objsize);
 
        if (cachep->flags & SLAB_DEBUG_INITIAL) {
                /* Need to call the slab's constructor so the
                 * caller can perform a verify of its state (debugging).
                 * Called without the cache-lock held.
                 */
-               cachep->ctor(objp+obj_dbghead(cachep),
-                                       cachep, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY);
+               cachep->ctor(objp + obj_dbghead(cachep),
+                            cachep, SLAB_CTOR_CONSTRUCTOR | SLAB_CTOR_VERIFY);
        }
        if (cachep->flags & SLAB_POISON && cachep->dtor) {
                /* we want to cache poison the object,
                 * call the destruction callback
                 */
-               cachep->dtor(objp+obj_dbghead(cachep), cachep, 0);
+               cachep->dtor(objp + obj_dbghead(cachep), cachep, 0);
        }
        if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
                if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep)) {
                        store_stackinfo(cachep, objp, (unsigned long)caller);
-                       kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0);
+                       kernel_map_pages(virt_to_page(objp),
+                                        cachep->objsize / PAGE_SIZE, 0);
                } else {
                        poison_obj(cachep, objp, POISON_FREE);
                }
@@ -2340,7 +2377,7 @@ static void check_slabp(kmem_cache_t *cachep, struct slab *slabp)
 {
        kmem_bufctl_t i;
        int entries = 0;
-       
+
        /* Check slab's freelist to see if this obj is there. */
        for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) {
                entries++;
@@ -2348,13 +2385,16 @@ static void check_slabp(kmem_cache_t *cachep, struct slab *slabp)
                        goto bad;
        }
        if (entries != cachep->num - slabp->inuse) {
-bad:
-               printk(KERN_ERR "slab: Internal list corruption detected in cache '%s'(%d), slabp %p(%d). Hexdump:\n",
-                               cachep->name, cachep->num, slabp, slabp->inuse);
-               for (i=0;i<sizeof(slabp)+cachep->num*sizeof(kmem_bufctl_t);i++) {
-                       if ((i%16)==0)
+             bad:
+               printk(KERN_ERR
+                      "slab: Internal list corruption detected in cache '%s'(%d), slabp %p(%d). Hexdump:\n",
+                      cachep->name, cachep->num, slabp, slabp->inuse);
+               for (i = 0;
+                    i < sizeof(slabp) + cachep->num * sizeof(kmem_bufctl_t);
+                    i++) {
+                       if ((i % 16) == 0)
                                printk("\n%03x:", i);
-                       printk(" %02x", ((unsigned char*)slabp)[i]);
+                       printk(" %02x", ((unsigned char *)slabp)[i]);
                }
                printk("\n");
                BUG();
@@ -2374,7 +2414,7 @@ static void *cache_alloc_refill(kmem_cache_t *cachep, gfp_t flags)
 
        check_irq_off();
        ac = ac_data(cachep);
-retry:
+      retry:
        batchcount = ac->batchcount;
        if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {
                /* if there was little recent activity on this
@@ -2396,8 +2436,8 @@ retry:
                        shared_array->avail -= batchcount;
                        ac->avail = batchcount;
                        memcpy(ac->entry,
-                               &(shared_array->entry[shared_array->avail]),
-                               sizeof(void*)*batchcount);
+                              &(shared_array->entry[shared_array->avail]),
+                              sizeof(void *) * batchcount);
                        shared_array->touched = 1;
                        goto alloc_done;
                }
@@ -2425,7 +2465,7 @@ retry:
 
                        /* get obj pointer */
                        ac->entry[ac->avail++] = slabp->s_mem +
-                               slabp->free*cachep->objsize;
+                           slabp->free * cachep->objsize;
 
                        slabp->inuse++;
                        next = slab_bufctl(slabp)[slabp->free];
@@ -2433,7 +2473,7 @@ retry:
                        slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE;
                        WARN_ON(numa_node_id() != slabp->nodeid);
 #endif
-                       slabp->free = next;
+                       slabp->free = next;
                }
                check_slabp(cachep, slabp);
 
@@ -2445,9 +2485,9 @@ retry:
                        list_add(&slabp->list, &l3->slabs_partial);
        }
 
-must_grow:
+      must_grow:
        l3->free_objects -= ac->avail;
-alloc_done:
+      alloc_done:
        spin_unlock(&l3->list_lock);
 
        if (unlikely(!ac->avail)) {
@@ -2459,7 +2499,7 @@ alloc_done:
                if (!x && ac->avail == 0)       // no objects in sight? abort
                        return NULL;
 
-               if (!ac->avail)         // objects refilled by interrupt?
+               if (!ac->avail) // objects refilled by interrupt?
                        goto retry;
        }
        ac->touched = 1;
@@ -2476,16 +2516,16 @@ cache_alloc_debugcheck_before(kmem_cache_t *cachep, gfp_t flags)
 }
 
 #if DEBUG
-static void *
-cache_alloc_debugcheck_after(kmem_cache_t *cachep,
-                       gfp_t flags, void *objp, void *caller)
+static void *cache_alloc_debugcheck_after(kmem_cache_t *cachep, gfp_t flags,
+                                       void *objp, void *caller)
 {
-       if (!objp)      
+       if (!objp)
                return objp;
-       if (cachep->flags & SLAB_POISON) {
+       if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
                if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep))
-                       kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 1);
+                       kernel_map_pages(virt_to_page(objp),
+                                        cachep->objsize / PAGE_SIZE, 1);
                else
                        check_poison_obj(cachep, objp);
 #else
@@ -2497,24 +2537,28 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep,
                *dbg_userword(cachep, objp) = caller;
 
        if (cachep->flags & SLAB_RED_ZONE) {
-               if (*dbg_redzone1(cachep, objp) != RED_INACTIVE || *dbg_redzone2(cachep, objp) != RED_INACTIVE) {
-                       slab_error(cachep, "double free, or memory outside"
-                                               " object was overwritten");
-                       printk(KERN_ERR "%p: redzone 1: 0x%lx, redzone 2: 0x%lx.\n",
-                                       objp, *dbg_redzone1(cachep, objp), *dbg_redzone2(cachep, objp));
+               if (*dbg_redzone1(cachep, objp) != RED_INACTIVE
+                   || *dbg_redzone2(cachep, objp) != RED_INACTIVE) {
+                       slab_error(cachep,
+                                  "double free, or memory outside"
+                                  " object was overwritten");
+                       printk(KERN_ERR
+                              "%p: redzone 1: 0x%lx, redzone 2: 0x%lx.\n",
+                              objp, *dbg_redzone1(cachep, objp),
+                              *dbg_redzone2(cachep, objp));
                }
                *dbg_redzone1(cachep, objp) = RED_ACTIVE;
                *dbg_redzone2(cachep, objp) = RED_ACTIVE;
        }
        objp += obj_dbghead(cachep);
        if (cachep->ctor && cachep->flags & SLAB_POISON) {
-               unsigned long   ctor_flags = SLAB_CTOR_CONSTRUCTOR;
+               unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR;
 
                if (!(flags & __GFP_WAIT))
                        ctor_flags |= SLAB_CTOR_ATOMIC;
 
                cachep->ctor(objp, cachep, ctor_flags);
-       }       
+       }
        return objp;
 }
 #else
@@ -2523,7 +2567,7 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep,
 
 static inline void *____cache_alloc(kmem_cache_t *cachep, gfp_t flags)
 {
-       voidobjp;
+       void *objp;
        struct array_cache *ac;
 
        check_irq_off();
@@ -2542,7 +2586,7 @@ static inline void *____cache_alloc(kmem_cache_t *cachep, gfp_t flags)
 static inline void *__cache_alloc(kmem_cache_t *cachep, gfp_t flags)
 {
        unsigned long save_flags;
-       voidobjp;
+       void *objp;
 
        cache_alloc_debugcheck_before(cachep, flags);
 
@@ -2550,7 +2594,7 @@ static inline void *__cache_alloc(kmem_cache_t *cachep, gfp_t flags)
        objp = ____cache_alloc(cachep, flags);
        local_irq_restore(save_flags);
        objp = cache_alloc_debugcheck_after(cachep, flags, objp,
-                                       __builtin_return_address(0));
+                                           __builtin_return_address(0));
        prefetchw(objp);
        return objp;
 }
@@ -2562,74 +2606,75 @@ static inline void *__cache_alloc(kmem_cache_t *cachep, gfp_t flags)
 static void *__cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int nodeid)
 {
        struct list_head *entry;
-       struct slab *slabp;
-       struct kmem_list3 *l3;
-       void *obj;
-       kmem_bufctl_t next;
-       int x;
-
-       l3 = cachep->nodelists[nodeid];
-       BUG_ON(!l3);
-
-retry:
-       spin_lock(&l3->list_lock);
-       entry = l3->slabs_partial.next;
-       if (entry == &l3->slabs_partial) {
-               l3->free_touched = 1;
-               entry = l3->slabs_free.next;
-               if (entry == &l3->slabs_free)
-                       goto must_grow;
-       }
-
-       slabp = list_entry(entry, struct slab, list);
-       check_spinlock_acquired_node(cachep, nodeid);
-       check_slabp(cachep, slabp);
-
-       STATS_INC_NODEALLOCS(cachep);
-       STATS_INC_ACTIVE(cachep);
-       STATS_SET_HIGH(cachep);
-
-       BUG_ON(slabp->inuse == cachep->num);
-
-       /* get obj pointer */
-       obj =  slabp->s_mem + slabp->free*cachep->objsize;
-       slabp->inuse++;
-       next = slab_bufctl(slabp)[slabp->free];
+       struct slab *slabp;
+       struct kmem_list3 *l3;
+       void *obj;
+       kmem_bufctl_t next;
+       int x;
+
+       l3 = cachep->nodelists[nodeid];
+       BUG_ON(!l3);
+
+      retry:
+       spin_lock(&l3->list_lock);
+       entry = l3->slabs_partial.next;
+       if (entry == &l3->slabs_partial) {
+               l3->free_touched = 1;
+               entry = l3->slabs_free.next;
+               if (entry == &l3->slabs_free)
+                       goto must_grow;
+       }
+
+       slabp = list_entry(entry, struct slab, list);
+       check_spinlock_acquired_node(cachep, nodeid);
+       check_slabp(cachep, slabp);
+
+       STATS_INC_NODEALLOCS(cachep);
+       STATS_INC_ACTIVE(cachep);
+       STATS_SET_HIGH(cachep);
+
+       BUG_ON(slabp->inuse == cachep->num);
+
+       /* get obj pointer */
+       obj = slabp->s_mem + slabp->free * cachep->objsize;
+       slabp->inuse++;
+       next = slab_bufctl(slabp)[slabp->free];
 #if DEBUG
-       slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE;
+       slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE;
 #endif
-       slabp->free = next;
-       check_slabp(cachep, slabp);
-       l3->free_objects--;
-       /* move slabp to correct slabp list: */
-       list_del(&slabp->list);
-
-       if (slabp->free == BUFCTL_END) {
-               list_add(&slabp->list, &l3->slabs_full);
-       } else {
-               list_add(&slabp->list, &l3->slabs_partial);
-       }
+       slabp->free = next;
+       check_slabp(cachep, slabp);
+       l3->free_objects--;
+       /* move slabp to correct slabp list: */
+       list_del(&slabp->list);
+
+       if (slabp->free == BUFCTL_END) {
+               list_add(&slabp->list, &l3->slabs_full);
+       } else {
+               list_add(&slabp->list, &l3->slabs_partial);
+       }
 
-       spin_unlock(&l3->list_lock);
-       goto done;
+       spin_unlock(&l3->list_lock);
+       goto done;
 
-must_grow:
-       spin_unlock(&l3->list_lock);
-       x = cache_grow(cachep, flags, nodeid);
+      must_grow:
+       spin_unlock(&l3->list_lock);
+       x = cache_grow(cachep, flags, nodeid);
 
-       if (!x)
-               return NULL;
+       if (!x)
+               return NULL;
 
-       goto retry;
-done:
-       return obj;
+       goto retry;
+      done:
+       return obj;
 }
 #endif
 
 /*
  * Caller needs to acquire correct kmem_list's list_lock
  */
-static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects, int node)
+static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects,
+                      int node)
 {
        int i;
        struct kmem_list3 *l3;
@@ -2652,7 +2697,7 @@ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects, int n
 
                if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) {
                        printk(KERN_ERR "slab: double free detected in cache "
-                                       "'%s', objp %p\n", cachep->name, objp);
+                              "'%s', objp %p\n", cachep->name, objp);
                        BUG();
                }
 #endif
@@ -2696,20 +2741,19 @@ static void cache_flusharray(kmem_cache_t *cachep, struct array_cache *ac)
        spin_lock(&l3->list_lock);
        if (l3->shared) {
                struct array_cache *shared_array = l3->shared;
-               int max = shared_array->limit-shared_array->avail;
+               int max = shared_array->limit - shared_array->avail;
                if (max) {
                        if (batchcount > max)
                                batchcount = max;
                        memcpy(&(shared_array->entry[shared_array->avail]),
-                                       ac->entry,
-                                       sizeof(void*)*batchcount);
+                              ac->entry, sizeof(void *) * batchcount);
                        shared_array->avail += batchcount;
                        goto free_done;
                }
        }
 
        free_block(cachep, ac->entry, batchcount, node);
-free_done:
+      free_done:
 #if STATS
        {
                int i = 0;
@@ -2731,10 +2775,9 @@ free_done:
        spin_unlock(&l3->list_lock);
        ac->avail -= batchcount;
        memmove(ac->entry, &(ac->entry[batchcount]),
-                       sizeof(void*)*ac->avail);
+               sizeof(void *) * ac->avail);
 }
 
-
 /*
  * __cache_free
  * Release an obj back to its cache. If the obj has a constructed
@@ -2759,7 +2802,8 @@ static inline void __cache_free(kmem_cache_t *cachep, void *objp)
                if (unlikely(slabp->nodeid != numa_node_id())) {
                        struct array_cache *alien = NULL;
                        int nodeid = slabp->nodeid;
-                       struct kmem_list3 *l3 = cachep->nodelists[numa_node_id()];
+                       struct kmem_list3 *l3 =
+                           cachep->nodelists[numa_node_id()];
 
                        STATS_INC_NODEFREES(cachep);
                        if (l3->alien && l3->alien[nodeid]) {
@@ -2767,15 +2811,15 @@ static inline void __cache_free(kmem_cache_t *cachep, void *objp)
                                spin_lock(&alien->lock);
                                if (unlikely(alien->avail == alien->limit))
                                        __drain_alien_cache(cachep,
-                                                       alien, nodeid);
+                                                           alien, nodeid);
                                alien->entry[alien->avail++] = objp;
                                spin_unlock(&alien->lock);
                        } else {
                                spin_lock(&(cachep->nodelists[nodeid])->
-                                               list_lock);
+                                         list_lock);
                                free_block(cachep, &objp, 1, nodeid);
                                spin_unlock(&(cachep->nodelists[nodeid])->
-                                               list_lock);
+                                           list_lock);
                        }
                        return;
                }
@@ -2822,9 +2866,9 @@ EXPORT_SYMBOL(kmem_cache_alloc);
  */
 int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)
 {
-       unsigned long addr = (unsigned long) ptr;
+       unsigned long addr = (unsigned long)ptr;
        unsigned long min_addr = PAGE_OFFSET;
-       unsigned long align_mask = BYTES_PER_WORD-1;
+       unsigned long align_mask = BYTES_PER_WORD - 1;
        unsigned long size = cachep->objsize;
        struct page *page;
 
@@ -2844,7 +2888,7 @@ int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)
        if (unlikely(page_get_cache(page) != cachep))
                goto out;
        return 1;
-out:
+      out:
        return 0;
 }
 
@@ -2871,8 +2915,10 @@ void *kmem_cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int nodeid)
 
        if (unlikely(!cachep->nodelists[nodeid])) {
                /* Fall back to __cache_alloc if we run into trouble */
-               printk(KERN_WARNING "slab: not allocating in inactive node %d for cache %s\n", nodeid, cachep->name);
-               return __cache_alloc(cachep,flags);
+               printk(KERN_WARNING
+                      "slab: not allocating in inactive node %d for cache %s\n",
+                      nodeid, cachep->name);
+               return __cache_alloc(cachep, flags);
        }
 
        cache_alloc_debugcheck_before(cachep, flags);
@@ -2882,7 +2928,9 @@ void *kmem_cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int nodeid)
        else
                ptr = __cache_alloc_node(cachep, flags, nodeid);
        local_irq_restore(save_flags);
-       ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, __builtin_return_address(0));
+       ptr =
+           cache_alloc_debugcheck_after(cachep, flags, ptr,
+                                        __builtin_return_address(0));
 
        return ptr;
 }
@@ -2944,12 +2992,11 @@ EXPORT_SYMBOL(__kmalloc);
  * Objects should be dereferenced using the per_cpu_ptr macro only.
  *
  * @size: how many bytes of memory are required.
- * @align: the alignment, which can't be greater than SMP_CACHE_BYTES.
  */
-void *__alloc_percpu(size_t size, size_t align)
+void *__alloc_percpu(size_t size)
 {
        int i;
-       struct percpu_data *pdata = kmalloc(sizeof (*pdata), GFP_KERNEL);
+       struct percpu_data *pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
 
        if (!pdata)
                return NULL;
@@ -2973,9 +3020,9 @@ void *__alloc_percpu(size_t size, size_t align)
        }
 
        /* Catch derefs w/o wrappers */
-       return (void *) (~(unsigned long) pdata);
+       return (void *)(~(unsigned long)pdata);
 
-unwind_oom:
+      unwind_oom:
        while (--i >= 0) {
                if (!cpu_possible(i))
                        continue;
@@ -3005,20 +3052,6 @@ void kmem_cache_free(kmem_cache_t *cachep, void *objp)
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
-/**
- * kzalloc - allocate memory. The memory is set to zero.
- * @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate.
- */
-void *kzalloc(size_t size, gfp_t flags)
-{
-       void *ret = kmalloc(size, flags);
-       if (ret)
-               memset(ret, 0, size);
-       return ret;
-}
-EXPORT_SYMBOL(kzalloc);
-
 /**
  * kfree - free previously allocated memory
  * @objp: pointer returned by kmalloc.
@@ -3038,7 +3071,7 @@ void kfree(const void *objp)
        local_irq_save(flags);
        kfree_debugcheck(objp);
        c = page_get_cache(virt_to_page(objp));
-       __cache_free(c, (void*)objp);
+       __cache_free(c, (void *)objp);
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(kfree);
@@ -3051,17 +3084,16 @@ EXPORT_SYMBOL(kfree);
  * Don't free memory not originally allocated by alloc_percpu()
  * The complemented objp is to check for that.
  */
-void
-free_percpu(const void *objp)
+void free_percpu(const void *objp)
 {
        int i;
-       struct percpu_data *p = (struct percpu_data *) (~(unsigned long) objp);
+       struct percpu_data *p = (struct percpu_data *)(~(unsigned long)objp);
 
        /*
         * We allocate for all cpus so we cannot use for online cpu here.
         */
        for_each_cpu(i)
-               kfree(p->ptrs[i]);
+           kfree(p->ptrs[i]);
        kfree(p);
 }
 EXPORT_SYMBOL(free_percpu);
@@ -3095,44 +3127,44 @@ static int alloc_kmemlist(kmem_cache_t *cachep)
                if (!(new_alien = alloc_alien_cache(node, cachep->limit)))
                        goto fail;
 #endif
-               if (!(new = alloc_arraycache(node, (cachep->shared*
-                               cachep->batchcount), 0xbaadf00d)))
+               if (!(new = alloc_arraycache(node, (cachep->shared *
+                                                   cachep->batchcount),
+                                            0xbaadf00d)))
                        goto fail;
                if ((l3 = cachep->nodelists[node])) {
 
                        spin_lock_irq(&l3->list_lock);
 
                        if ((nc = cachep->nodelists[node]->shared))
-                               free_block(cachep, nc->entry,
-                                                       nc->avail, node);
+                               free_block(cachep, nc->entry, nc->avail, node);
 
                        l3->shared = new;
                        if (!cachep->nodelists[node]->alien) {
                                l3->alien = new_alien;
                                new_alien = NULL;
                        }
-                       l3->free_limit = (1 + nr_cpus_node(node))*
-                               cachep->batchcount + cachep->num;
+                       l3->free_limit = (1 + nr_cpus_node(node)) *
+                           cachep->batchcount + cachep->num;
                        spin_unlock_irq(&l3->list_lock);
                        kfree(nc);
                        free_alien_cache(new_alien);
                        continue;
                }
                if (!(l3 = kmalloc_node(sizeof(struct kmem_list3),
-                                               GFP_KERNEL, node)))
+                                       GFP_KERNEL, node)))
                        goto fail;
 
                kmem_list3_init(l3);
                l3->next_reap = jiffies + REAPTIMEOUT_LIST3 +
-                       ((unsigned long)cachep)%REAPTIMEOUT_LIST3;
+                   ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
                l3->shared = new;
                l3->alien = new_alien;
-               l3->free_limit = (1 + nr_cpus_node(node))*
-                       cachep->batchcount + cachep->num;
+               l3->free_limit = (1 + nr_cpus_node(node)) *
+                   cachep->batchcount + cachep->num;
                cachep->nodelists[node] = l3;
        }
        return err;
-fail:
+      fail:
        err = -ENOMEM;
        return err;
 }
@@ -3154,18 +3186,19 @@ static void do_ccupdate_local(void *info)
        new->new[smp_processor_id()] = old;
 }
 
-
 static int do_tune_cpucache(kmem_cache_t *cachep, int limit, int batchcount,
-                               int shared)
+                           int shared)
 {
        struct ccupdate_struct new;
        int i, err;
 
-       memset(&new.new,0,sizeof(new.new));
+       memset(&new.new, 0, sizeof(new.new));
        for_each_online_cpu(i) {
-               new.new[i] = alloc_arraycache(cpu_to_node(i), limit, batchcount);
+               new.new[i] =
+                   alloc_arraycache(cpu_to_node(i), limit, batchcount);
                if (!new.new[i]) {
-                       for (i--; i >= 0; i--) kfree(new.new[i]);
+                       for (i--; i >= 0; i--)
+                               kfree(new.new[i]);
                        return -ENOMEM;
                }
        }
@@ -3193,13 +3226,12 @@ static int do_tune_cpucache(kmem_cache_t *cachep, int limit, int batchcount,
        err = alloc_kmemlist(cachep);
        if (err) {
                printk(KERN_ERR "alloc_kmemlist failed for %s, error %d.\n",
-                               cachep->name, -err);
+                      cachep->name, -err);
                BUG();
        }
        return 0;
 }
 
-
 static void enable_cpucache(kmem_cache_t *cachep)
 {
        int err;
@@ -3246,14 +3278,14 @@ static void enable_cpucache(kmem_cache_t *cachep)
        if (limit > 32)
                limit = 32;
 #endif
-       err = do_tune_cpucache(cachep, limit, (limit+1)/2, shared);
+       err = do_tune_cpucache(cachep, limit, (limit + 1) / 2, shared);
        if (err)
                printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n",
-                                       cachep->name, -err);
+                      cachep->name, -err);
 }
 
-static void drain_array_locked(kmem_cache_t *cachep,
-                               struct array_cache *ac, int force, int node)
+static void drain_array_locked(kmem_cache_t *cachep, struct array_cache *ac,
+                               int force, int node)
 {
        int tofree;
 
@@ -3261,14 +3293,14 @@ static void drain_array_locked(kmem_cache_t *cachep,
        if (ac->touched && !force) {
                ac->touched = 0;
        } else if (ac->avail) {
-               tofree = force ? ac->avail : (ac->limit+4)/5;
+               tofree = force ? ac->avail : (ac->limit + 4) / 5;
                if (tofree > ac->avail) {
-                       tofree = (ac->avail+1)/2;
+                       tofree = (ac->avail + 1) / 2;
                }
                free_block(cachep, ac->entry, tofree, node);
                ac->avail -= tofree;
                memmove(ac->entry, &(ac->entry[tofree]),
-                                       sizeof(void*)*ac->avail);
+                       sizeof(void *) * ac->avail);
        }
 }
 
@@ -3291,13 +3323,14 @@ static void cache_reap(void *unused)
 
        if (down_trylock(&cache_chain_sem)) {
                /* Give up. Setup the next iteration. */
-               schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC);
+               schedule_delayed_work(&__get_cpu_var(reap_work),
+                                     REAPTIMEOUT_CPUC);
                return;
        }
 
        list_for_each(walk, &cache_chain) {
                kmem_cache_t *searchp;
-               struct list_headp;
+               struct list_head *p;
                int tofree;
                struct slab *slabp;
 
@@ -3314,7 +3347,7 @@ static void cache_reap(void *unused)
                spin_lock_irq(&l3->list_lock);
 
                drain_array_locked(searchp, ac_data(searchp), 0,
-                               numa_node_id());
+                                  numa_node_id());
 
                if (time_after(l3->next_reap, jiffies))
                        goto next_unlock;
@@ -3323,14 +3356,16 @@ static void cache_reap(void *unused)
 
                if (l3->shared)
                        drain_array_locked(searchp, l3->shared, 0,
-                               numa_node_id());
+                                          numa_node_id());
 
                if (l3->free_touched) {
                        l3->free_touched = 0;
                        goto next_unlock;
                }
 
-               tofree = (l3->free_limit+5*searchp->num-1)/(5*searchp->num);
+               tofree =
+                   (l3->free_limit + 5 * searchp->num -
+                    1) / (5 * searchp->num);
                do {
                        p = l3->slabs_free.next;
                        if (p == &(l3->slabs_free))
@@ -3350,10 +3385,10 @@ static void cache_reap(void *unused)
                        spin_unlock_irq(&l3->list_lock);
                        slab_destroy(searchp, slabp);
                        spin_lock_irq(&l3->list_lock);
-               } while(--tofree > 0);
-next_unlock:
+               } while (--tofree > 0);
+             next_unlock:
                spin_unlock_irq(&l3->list_lock);
-next:
+             next:
                cond_resched();
        }
        check_irq_on();
@@ -3365,32 +3400,37 @@ next:
 
 #ifdef CONFIG_PROC_FS
 
-static void *s_start(struct seq_file *m, loff_t *pos)
+static void print_slabinfo_header(struct seq_file *m)
 {
-       loff_t n = *pos;
-       struct list_head *p;
-
-       down(&cache_chain_sem);
-       if (!n) {
-               /*
-                * Output format version, so at least we can change it
-                * without _too_ many complaints.
-                */
+       /*
+        * Output format version, so at least we can change it
+        * without _too_ many complaints.
+        */
 #if STATS
-               seq_puts(m, "slabinfo - version: 2.1 (statistics)\n");
+       seq_puts(m, "slabinfo - version: 2.1 (statistics)\n");
 #else
-               seq_puts(m, "slabinfo - version: 2.1\n");
+       seq_puts(m, "slabinfo - version: 2.1\n");
 #endif
-               seq_puts(m, "# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>");
-               seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
-               seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
+       seq_puts(m, "# name            <active_objs> <num_objs> <objsize> "
+                "<objperslab> <pagesperslab>");
+       seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
+       seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
 #if STATS
-               seq_puts(m, " : globalstat <listallocs> <maxobjs> <grown> <reaped>"
-                               " <error> <maxfreeable> <nodeallocs> <remotefrees>");
-               seq_puts(m, " : cpustat <allochit> <allocmiss> <freehit> <freemiss>");
+       seq_puts(m, " : globalstat <listallocs> <maxobjs> <grown> <reaped> "
+                "<error> <maxfreeable> <nodeallocs> <remotefrees>");
+       seq_puts(m, " : cpustat <allochit> <allocmiss> <freehit> <freemiss>");
 #endif
-               seq_putc(m, '\n');
-       }
+       seq_putc(m, '\n');
+}
+
+static void *s_start(struct seq_file *m, loff_t *pos)
+{
+       loff_t n = *pos;
+       struct list_head *p;
+
+       down(&cache_chain_sem);
+       if (!n)
+               print_slabinfo_header(m);
        p = cache_chain.next;
        while (n--) {
                p = p->next;
@@ -3405,7 +3445,7 @@ static void *s_next(struct seq_file *m, void *p, loff_t *pos)
        kmem_cache_t *cachep = p;
        ++*pos;
        return cachep->next.next == &cache_chain ? NULL
-               : list_entry(cachep->next.next, kmem_cache_t, next);
+           : list_entry(cachep->next.next, kmem_cache_t, next);
 }
 
 static void s_stop(struct seq_file *m, void *p)
@@ -3417,11 +3457,11 @@ static int s_show(struct seq_file *m, void *p)
 {
        kmem_cache_t *cachep = p;
        struct list_head *q;
-       struct slab     *slabp;
-       unsigned long   active_objs;
-       unsigned long   num_objs;
-       unsigned long   active_slabs = 0;
-       unsigned long   num_slabs, free_objects = 0, shared_avail = 0;
+       struct slab *slabp;
+       unsigned long active_objs;
+       unsigned long num_objs;
+       unsigned long active_slabs = 0;
+       unsigned long num_slabs, free_objects = 0, shared_avail = 0;
        const char *name;
        char *error = NULL;
        int node;
@@ -3438,14 +3478,14 @@ static int s_show(struct seq_file *m, void *p)
 
                spin_lock(&l3->list_lock);
 
-               list_for_each(q,&l3->slabs_full) {
+               list_for_each(q, &l3->slabs_full) {
                        slabp = list_entry(q, struct slab, list);
                        if (slabp->inuse != cachep->num && !error)
                                error = "slabs_full accounting error";
                        active_objs += cachep->num;
                        active_slabs++;
                }
-               list_for_each(q,&l3->slabs_partial) {
+               list_for_each(q, &l3->slabs_partial) {
                        slabp = list_entry(q, struct slab, list);
                        if (slabp->inuse == cachep->num && !error)
                                error = "slabs_partial inuse accounting error";
@@ -3454,7 +3494,7 @@ static int s_show(struct seq_file *m, void *p)
                        active_objs += slabp->inuse;
                        active_slabs++;
                }
-               list_for_each(q,&l3->slabs_free) {
+               list_for_each(q, &l3->slabs_free) {
                        slabp = list_entry(q, struct slab, list);
                        if (slabp->inuse && !error)
                                error = "slabs_free/inuse accounting error";
@@ -3465,25 +3505,24 @@ static int s_show(struct seq_file *m, void *p)
 
                spin_unlock(&l3->list_lock);
        }
-       num_slabs+=active_slabs;
-       num_objs = num_slabs*cachep->num;
+       num_slabs += active_slabs;
+       num_objs = num_slabs * cachep->num;
        if (num_objs - active_objs != free_objects && !error)
                error = "free_objects accounting error";
 
-       name = cachep->name; 
+       name = cachep->name;
        if (error)
                printk(KERN_ERR "slab: cache %s error: %s\n", name, error);
 
        seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d",
-               name, active_objs, num_objs, cachep->objsize,
-               cachep->num, (1<<cachep->gfporder));
+                  name, active_objs, num_objs, cachep->objsize,
+                  cachep->num, (1 << cachep->gfporder));
        seq_printf(m, " : tunables %4u %4u %4u",
-                       cachep->limit, cachep->batchcount,
-                       cachep->shared);
+                  cachep->limit, cachep->batchcount, cachep->shared);
        seq_printf(m, " : slabdata %6lu %6lu %6lu",
-                       active_slabs, num_slabs, shared_avail);
+                  active_slabs, num_slabs, shared_avail);
 #if STATS
-       {       /* list3 stats */
+       {                       /* list3 stats */
                unsigned long high = cachep->high_mark;
                unsigned long allocs = cachep->num_allocations;
                unsigned long grown = cachep->grown;
@@ -3494,9 +3533,7 @@ static int s_show(struct seq_file *m, void *p)
                unsigned long node_frees = cachep->node_frees;
 
                seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu \
-                               %4lu %4lu %4lu %4lu",
-                               allocs, high, grown, reaped, errors,
-                               max_freeable, node_allocs, node_frees);
+                               %4lu %4lu %4lu %4lu", allocs, high, grown, reaped, errors, max_freeable, node_allocs, node_frees);
        }
        /* cpu stats */
        {
@@ -3506,7 +3543,7 @@ static int s_show(struct seq_file *m, void *p)
                unsigned long freemiss = atomic_read(&cachep->freemiss);
 
                seq_printf(m, " : cpustat %6lu %6lu %6lu %6lu",
-                       allochit, allocmiss, freehit, freemiss);
+                          allochit, allocmiss, freehit, freemiss);
        }
 #endif
        seq_putc(m, '\n');
@@ -3529,10 +3566,10 @@ static int s_show(struct seq_file *m, void *p)
  */
 
 struct seq_operations slabinfo_op = {
-       .start  = s_start,
-       .next   = s_next,
-       .stop   = s_stop,
-       .show   = s_show,
+       .start = s_start,
+       .next = s_next,
+       .stop = s_stop,
+       .show = s_show,
 };
 
 #define MAX_SLABINFO_WRITE 128
@@ -3543,18 +3580,18 @@ struct seq_operations slabinfo_op = {
  * @count: data length
  * @ppos: unused
  */
-ssize_t slabinfo_write(struct file *file, const char __user *buffer,
-                               size_t count, loff_t *ppos)
+ssize_t slabinfo_write(struct file *file, const char __user * buffer,
+                      size_t count, loff_t *ppos)
 {
-       char kbuf[MAX_SLABINFO_WRITE+1], *tmp;
+       char kbuf[MAX_SLABINFO_WRITE + 1], *tmp;
        int limit, batchcount, shared, res;
        struct list_head *p;
-       
+
        if (count > MAX_SLABINFO_WRITE)
                return -EINVAL;
        if (copy_from_user(&kbuf, buffer, count))
                return -EFAULT;
-       kbuf[MAX_SLABINFO_WRITE] = '\0'; 
+       kbuf[MAX_SLABINFO_WRITE] = '\0';
 
        tmp = strchr(kbuf, ' ');
        if (!tmp)
@@ -3567,18 +3604,17 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
        /* Find the cache in the chain of caches. */
        down(&cache_chain_sem);
        res = -EINVAL;
-       list_for_each(p,&cache_chain) {
+       list_for_each(p, &cache_chain) {
                kmem_cache_t *cachep = list_entry(p, kmem_cache_t, next);
 
                if (!strcmp(cachep->name, kbuf)) {
                        if (limit < 1 ||
                            batchcount < 1 ||
-                           batchcount > limit ||
-                           shared < 0) {
+                           batchcount > limit || shared < 0) {
                                res = 0;
                        } else {
                                res = do_tune_cpucache(cachep, limit,
-                                                       batchcount, shared);
+                                                      batchcount, shared);
                        }
                        break;
                }
@@ -3609,26 +3645,3 @@ unsigned int ksize(const void *objp)
 
        return obj_reallen(page_get_cache(virt_to_page(objp)));
 }
-
-
-/*
- * 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
- */
-char *kstrdup(const char *s, gfp_t gfp)
-{
-       size_t len;
-       char *buf;
-
-       if (!s)
-               return NULL;
-
-       len = strlen(s) + 1;
-       buf = kmalloc(len, gfp);
-       if (buf)
-               memcpy(buf, s, len);
-       return buf;
-}
-EXPORT_SYMBOL(kstrdup);
diff --git a/mm/slob.c b/mm/slob.c
new file mode 100644 (file)
index 0000000..1c240c4
--- /dev/null
+++ b/mm/slob.c
@@ -0,0 +1,385 @@
+/*
+ * SLOB Allocator: Simple List Of Blocks
+ *
+ * Matt Mackall <mpm@selenic.com> 12/30/03
+ *
+ * How SLOB works:
+ *
+ * The core of SLOB is a traditional K&R style heap allocator, with
+ * support for returning aligned objects. The granularity of this
+ * allocator is 8 bytes on x86, though it's perhaps possible to reduce
+ * this to 4 if it's deemed worth the effort. The slob heap is a
+ * singly-linked list of pages from __get_free_page, grown on demand
+ * and allocation from the heap is currently first-fit.
+ *
+ * Above this is an implementation of kmalloc/kfree. Blocks returned
+ * from kmalloc are 8-byte aligned and prepended with a 8-byte header.
+ * If kmalloc is asked for objects of PAGE_SIZE or larger, it calls
+ * __get_free_pages directly so that it can return page-aligned blocks
+ * and keeps a linked list of such pages and their orders. These
+ * objects are detected in kfree() by their page alignment.
+ *
+ * SLAB is emulated on top of SLOB by simply calling constructors and
+ * destructors for every SLAB allocation. Objects are returned with
+ * the 8-byte alignment unless the SLAB_MUST_HWCACHE_ALIGN flag is
+ * set, in which case the low-level allocator will fragment blocks to
+ * create the proper alignment. Again, objects of page-size or greater
+ * are allocated by calling __get_free_pages. As SLAB objects know
+ * their size, no separate size bookkeeping is necessary and there is
+ * essentially no allocation space overhead.
+ */
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/cache.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+
+struct slob_block {
+       int units;
+       struct slob_block *next;
+};
+typedef struct slob_block slob_t;
+
+#define SLOB_UNIT sizeof(slob_t)
+#define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT)
+#define SLOB_ALIGN L1_CACHE_BYTES
+
+struct bigblock {
+       int order;
+       void *pages;
+       struct bigblock *next;
+};
+typedef struct bigblock bigblock_t;
+
+static slob_t arena = { .next = &arena, .units = 1 };
+static slob_t *slobfree = &arena;
+static bigblock_t *bigblocks;
+static DEFINE_SPINLOCK(slob_lock);
+static DEFINE_SPINLOCK(block_lock);
+
+static void slob_free(void *b, int size);
+
+static void *slob_alloc(size_t size, gfp_t gfp, int align)
+{
+       slob_t *prev, *cur, *aligned = 0;
+       int delta = 0, units = SLOB_UNITS(size);
+       unsigned long flags;
+
+       spin_lock_irqsave(&slob_lock, flags);
+       prev = slobfree;
+       for (cur = prev->next; ; prev = cur, cur = cur->next) {
+               if (align) {
+                       aligned = (slob_t *)ALIGN((unsigned long)cur, align);
+                       delta = aligned - cur;
+               }
+               if (cur->units >= units + delta) { /* room enough? */
+                       if (delta) { /* need to fragment head to align? */
+                               aligned->units = cur->units - delta;
+                               aligned->next = cur->next;
+                               cur->next = aligned;
+                               cur->units = delta;
+                               prev = cur;
+                               cur = aligned;
+                       }
+
+                       if (cur->units == units) /* exact fit? */
+                               prev->next = cur->next; /* unlink */
+                       else { /* fragment */
+                               prev->next = cur + units;
+                               prev->next->units = cur->units - units;
+                               prev->next->next = cur->next;
+                               cur->units = units;
+                       }
+
+                       slobfree = prev;
+                       spin_unlock_irqrestore(&slob_lock, flags);
+                       return cur;
+               }
+               if (cur == slobfree) {
+                       spin_unlock_irqrestore(&slob_lock, flags);
+
+                       if (size == PAGE_SIZE) /* trying to shrink arena? */
+                               return 0;
+
+                       cur = (slob_t *)__get_free_page(gfp);
+                       if (!cur)
+                               return 0;
+
+                       slob_free(cur, PAGE_SIZE);
+                       spin_lock_irqsave(&slob_lock, flags);
+                       cur = slobfree;
+               }
+       }
+}
+
+static void slob_free(void *block, int size)
+{
+       slob_t *cur, *b = (slob_t *)block;
+       unsigned long flags;
+
+       if (!block)
+               return;
+
+       if (size)
+               b->units = SLOB_UNITS(size);
+
+       /* Find reinsertion point */
+       spin_lock_irqsave(&slob_lock, flags);
+       for (cur = slobfree; !(b > cur && b < cur->next); cur = cur->next)
+               if (cur >= cur->next && (b > cur || b < cur->next))
+                       break;
+
+       if (b + b->units == cur->next) {
+               b->units += cur->next->units;
+               b->next = cur->next->next;
+       } else
+               b->next = cur->next;
+
+       if (cur + cur->units == b) {
+               cur->units += b->units;
+               cur->next = b->next;
+       } else
+               cur->next = b;
+
+       slobfree = cur;
+
+       spin_unlock_irqrestore(&slob_lock, flags);
+}
+
+static int FASTCALL(find_order(int size));
+static int fastcall find_order(int size)
+{
+       int order = 0;
+       for ( ; size > 4096 ; size >>=1)
+               order++;
+       return order;
+}
+
+void *kmalloc(size_t size, gfp_t gfp)
+{
+       slob_t *m;
+       bigblock_t *bb;
+       unsigned long flags;
+
+       if (size < PAGE_SIZE - SLOB_UNIT) {
+               m = slob_alloc(size + SLOB_UNIT, gfp, 0);
+               return m ? (void *)(m + 1) : 0;
+       }
+
+       bb = slob_alloc(sizeof(bigblock_t), gfp, 0);
+       if (!bb)
+               return 0;
+
+       bb->order = find_order(size);
+       bb->pages = (void *)__get_free_pages(gfp, bb->order);
+
+       if (bb->pages) {
+               spin_lock_irqsave(&block_lock, flags);
+               bb->next = bigblocks;
+               bigblocks = bb;
+               spin_unlock_irqrestore(&block_lock, flags);
+               return bb->pages;
+       }
+
+       slob_free(bb, sizeof(bigblock_t));
+       return 0;
+}
+
+EXPORT_SYMBOL(kmalloc);
+
+void kfree(const void *block)
+{
+       bigblock_t *bb, **last = &bigblocks;
+       unsigned long flags;
+
+       if (!block)
+               return;
+
+       if (!((unsigned long)block & (PAGE_SIZE-1))) {
+               /* might be on the big block list */
+               spin_lock_irqsave(&block_lock, flags);
+               for (bb = bigblocks; bb; last = &bb->next, bb = bb->next) {
+                       if (bb->pages == block) {
+                               *last = bb->next;
+                               spin_unlock_irqrestore(&block_lock, flags);
+                               free_pages((unsigned long)block, bb->order);
+                               slob_free(bb, sizeof(bigblock_t));
+                               return;
+                       }
+               }
+               spin_unlock_irqrestore(&block_lock, flags);
+       }
+
+       slob_free((slob_t *)block - 1, 0);
+       return;
+}
+
+EXPORT_SYMBOL(kfree);
+
+unsigned int ksize(const void *block)
+{
+       bigblock_t *bb;
+       unsigned long flags;
+
+       if (!block)
+               return 0;
+
+       if (!((unsigned long)block & (PAGE_SIZE-1))) {
+               spin_lock_irqsave(&block_lock, flags);
+               for (bb = bigblocks; bb; bb = bb->next)
+                       if (bb->pages == block) {
+                               spin_unlock_irqrestore(&slob_lock, flags);
+                               return PAGE_SIZE << bb->order;
+                       }
+               spin_unlock_irqrestore(&block_lock, flags);
+       }
+
+       return ((slob_t *)block - 1)->units * SLOB_UNIT;
+}
+
+struct kmem_cache {
+       unsigned int size, align;
+       const char *name;
+       void (*ctor)(void *, struct kmem_cache *, unsigned long);
+       void (*dtor)(void *, struct kmem_cache *, unsigned long);
+};
+
+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))
+{
+       struct kmem_cache *c;
+
+       c = slob_alloc(sizeof(struct kmem_cache), flags, 0);
+
+       if (c) {
+               c->name = name;
+               c->size = size;
+               c->ctor = ctor;
+               c->dtor = dtor;
+               /* ignore alignment unless it's forced */
+               c->align = (flags & SLAB_MUST_HWCACHE_ALIGN) ? SLOB_ALIGN : 0;
+               if (c->align < align)
+                       c->align = align;
+       }
+
+       return c;
+}
+EXPORT_SYMBOL(kmem_cache_create);
+
+int kmem_cache_destroy(struct kmem_cache *c)
+{
+       slob_free(c, sizeof(struct kmem_cache));
+       return 0;
+}
+EXPORT_SYMBOL(kmem_cache_destroy);
+
+void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags)
+{
+       void *b;
+
+       if (c->size < PAGE_SIZE)
+               b = slob_alloc(c->size, flags, c->align);
+       else
+               b = (void *)__get_free_pages(flags, find_order(c->size));
+
+       if (c->ctor)
+               c->ctor(b, c, SLAB_CTOR_CONSTRUCTOR);
+
+       return b;
+}
+EXPORT_SYMBOL(kmem_cache_alloc);
+
+void kmem_cache_free(struct kmem_cache *c, void *b)
+{
+       if (c->dtor)
+               c->dtor(b, c, 0);
+
+       if (c->size < PAGE_SIZE)
+               slob_free(b, c->size);
+       else
+               free_pages((unsigned long)b, find_order(c->size));
+}
+EXPORT_SYMBOL(kmem_cache_free);
+
+unsigned int kmem_cache_size(struct kmem_cache *c)
+{
+       return c->size;
+}
+EXPORT_SYMBOL(kmem_cache_size);
+
+const char *kmem_cache_name(struct kmem_cache *c)
+{
+       return c->name;
+}
+EXPORT_SYMBOL(kmem_cache_name);
+
+static struct timer_list slob_timer = TIMER_INITIALIZER(
+       (void (*)(unsigned long))kmem_cache_init, 0, 0);
+
+void kmem_cache_init(void)
+{
+       void *p = slob_alloc(PAGE_SIZE, 0, PAGE_SIZE-1);
+
+       if (p)
+               free_page((unsigned long)p);
+
+       mod_timer(&slob_timer, jiffies + HZ);
+}
+
+atomic_t slab_reclaim_pages = ATOMIC_INIT(0);
+EXPORT_SYMBOL(slab_reclaim_pages);
+
+#ifdef CONFIG_SMP
+
+void *__alloc_percpu(size_t size, size_t align)
+{
+       int i;
+       struct percpu_data *pdata = kmalloc(sizeof (*pdata), GFP_KERNEL);
+
+       if (!pdata)
+               return NULL;
+
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!cpu_possible(i))
+                       continue;
+               pdata->ptrs[i] = kmalloc(size, GFP_KERNEL);
+               if (!pdata->ptrs[i])
+                       goto unwind_oom;
+               memset(pdata->ptrs[i], 0, size);
+       }
+
+       /* Catch derefs w/o wrappers */
+       return (void *) (~(unsigned long) pdata);
+
+unwind_oom:
+       while (--i >= 0) {
+               if (!cpu_possible(i))
+                       continue;
+               kfree(pdata->ptrs[i]);
+       }
+       kfree(pdata);
+       return NULL;
+}
+EXPORT_SYMBOL(__alloc_percpu);
+
+void
+free_percpu(const void *objp)
+{
+       int i;
+       struct percpu_data *p = (struct percpu_data *) (~(unsigned long) objp);
+
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!cpu_possible(i))
+                       continue;
+               kfree(p->ptrs[i]);
+       }
+       kfree(p);
+}
+EXPORT_SYMBOL(free_percpu);
+
+#endif
index 72079b538e2dac74c136bcebfa47bca7dceb0daa..0a51f36ba3a1b9fcaade3481857cbfd4ae1233b2 100644 (file)
  */
 #ifdef CONFIG_SPARSEMEM_EXTREME
 struct mem_section *mem_section[NR_SECTION_ROOTS]
-       ____cacheline_maxaligned_in_smp;
+       ____cacheline_internodealigned_in_smp;
 #else
 struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]
-       ____cacheline_maxaligned_in_smp;
+       ____cacheline_internodealigned_in_smp;
 #endif
 EXPORT_SYMBOL(mem_section);
 
index fc2aecb70a95c9e3559a2d4d1d4a2ae0700ebc50..7b09ac503fec9dde77422705a08b2a1f087d0d70 100644 (file)
@@ -141,7 +141,7 @@ void __delete_from_swap_cache(struct page *page)
  * Allocate swap space for the page and add the page to the
  * swap cache.  Caller needs to hold the page lock. 
  */
-int add_to_swap(struct page * page)
+int add_to_swap(struct page * page, gfp_t gfp_mask)
 {
        swp_entry_t entry;
        int err;
@@ -166,7 +166,7 @@ int add_to_swap(struct page * page)
                 * Add it to the swap cache and mark it dirty
                 */
                err = __add_to_swap_cache(page, entry,
-                               GFP_ATOMIC|__GFP_NOMEMALLOC|__GFP_NOWARN);
+                               gfp_mask|__GFP_NOMEMALLOC|__GFP_NOWARN);
 
                switch (err) {
                case 0:                         /* Success */
index 6da4b28b896b311f681069a3ef45ffec358d4b11..80f948a2028bdc2f850741a802e81b4d207f8f6f 100644 (file)
@@ -1493,7 +1493,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                        goto bad_swap;
                if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
                        goto bad_swap;
-               
+
                /* OK, set up the swap map and apply the bad block list */
                if (!(p->swap_map = vmalloc(maxpages * sizeof(short)))) {
                        error = -ENOMEM;
@@ -1502,17 +1502,17 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
 
                error = 0;
                memset(p->swap_map, 0, maxpages * sizeof(short));
-               for (i=0; i<swap_header->info.nr_badpages; i++) {
-                       int page = swap_header->info.badpages[i];
-                       if (page <= 0 || page >= swap_header->info.last_page)
+               for (i = 0; i < swap_header->info.nr_badpages; i++) {
+                       int page_nr = swap_header->info.badpages[i];
+                       if (page_nr <= 0 || page_nr >= swap_header->info.last_page)
                                error = -EINVAL;
                        else
-                               p->swap_map[page] = SWAP_MAP_BAD;
+                               p->swap_map[page_nr] = SWAP_MAP_BAD;
                }
                nr_good_pages = swap_header->info.last_page -
                                swap_header->info.nr_badpages -
                                1 /* header page */;
-               if (error) 
+               if (error)
                        goto bad_swap;
        }
 
index 7dee327459017f35578178f4b4b97f76d3dffa4e..b1a463d0fe713dbf671a7fa4a8e439e138ee56fa 100644 (file)
@@ -249,7 +249,6 @@ unlock:
                                break;
                }
                pagevec_release(&pvec);
-               cond_resched();
        }
        return ret;
 }
diff --git a/mm/util.c b/mm/util.c
new file mode 100644 (file)
index 0000000..5f4bb59
--- /dev/null
+++ b/mm/util.c
@@ -0,0 +1,39 @@
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+/**
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ */
+void *kzalloc(size_t size, gfp_t flags)
+{
+       void *ret = kmalloc(size, flags);
+       if (ret)
+               memset(ret, 0, size);
+       return ret;
+}
+EXPORT_SYMBOL(kzalloc);
+
+/*
+ * 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
+ */
+char *kstrdup(const char *s, gfp_t gfp)
+{
+       size_t len;
+       char *buf;
+
+       if (!s)
+               return NULL;
+
+       len = strlen(s) + 1;
+       buf = kmalloc(len, gfp);
+       if (buf)
+               memcpy(buf, s, len);
+       return buf;
+}
+EXPORT_SYMBOL(kstrdup);
index be8235fb193945cf15129f4a68ee7e88305078e4..bf903b2d198f0820a2d03041b06de25af7a4d1d7 100644 (file)
@@ -180,8 +180,7 @@ EXPORT_SYMBOL(remove_shrinker);
  *
  * Returns the number of slab objects which we shrunk.
  */
-static int shrink_slab(unsigned long scanned, gfp_t gfp_mask,
-                       unsigned long lru_pages)
+int shrink_slab(unsigned long scanned, gfp_t gfp_mask, unsigned long lru_pages)
 {
        struct shrinker *shrinker;
        int ret = 0;
@@ -269,9 +268,7 @@ static inline int is_page_cache_freeable(struct page *page)
 
 static int may_write_to_queue(struct backing_dev_info *bdi)
 {
-       if (current_is_kswapd())
-               return 1;
-       if (current_is_pdflush())       /* This is unlikely, but why not... */
+       if (current->flags & PF_SWAPWRITE)
                return 1;
        if (!bdi_write_congested(bdi))
                return 1;
@@ -376,6 +373,43 @@ static pageout_t pageout(struct page *page, struct address_space *mapping)
        return PAGE_CLEAN;
 }
 
+static int remove_mapping(struct address_space *mapping, struct page *page)
+{
+       if (!mapping)
+               return 0;               /* truncate got there first */
+
+       write_lock_irq(&mapping->tree_lock);
+
+       /*
+        * The non-racy check for busy page.  It is critical to check
+        * PageDirty _after_ making sure that the page is freeable and
+        * not in use by anybody.       (pagecache + us == 2)
+        */
+       if (unlikely(page_count(page) != 2))
+               goto cannot_free;
+       smp_rmb();
+       if (unlikely(PageDirty(page)))
+               goto cannot_free;
+
+       if (PageSwapCache(page)) {
+               swp_entry_t swap = { .val = page_private(page) };
+               __delete_from_swap_cache(page);
+               write_unlock_irq(&mapping->tree_lock);
+               swap_free(swap);
+               __put_page(page);       /* The pagecache ref */
+               return 1;
+       }
+
+       __remove_from_page_cache(page);
+       write_unlock_irq(&mapping->tree_lock);
+       __put_page(page);
+       return 1;
+
+cannot_free:
+       write_unlock_irq(&mapping->tree_lock);
+       return 0;
+}
+
 /*
  * shrink_list adds the number of reclaimed pages to sc->nr_reclaimed
  */
@@ -424,7 +458,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc)
                 * Try to allocate it some swap space here.
                 */
                if (PageAnon(page) && !PageSwapCache(page)) {
-                       if (!add_to_swap(page))
+                       if (!add_to_swap(page, GFP_ATOMIC))
                                goto activate_locked;
                }
 #endif /* CONFIG_SWAP */
@@ -507,36 +541,8 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc)
                                goto free_it;
                }
 
-               if (!mapping)
-                       goto keep_locked;       /* truncate got there first */
-
-               write_lock_irq(&mapping->tree_lock);
-
-               /*
-                * The non-racy check for busy page.  It is critical to check
-                * PageDirty _after_ making sure that the page is freeable and
-                * not in use by anybody.       (pagecache + us == 2)
-                */
-               if (unlikely(page_count(page) != 2))
-                       goto cannot_free;
-               smp_rmb();
-               if (unlikely(PageDirty(page)))
-                       goto cannot_free;
-
-#ifdef CONFIG_SWAP
-               if (PageSwapCache(page)) {
-                       swp_entry_t swap = { .val = page_private(page) };
-                       __delete_from_swap_cache(page);
-                       write_unlock_irq(&mapping->tree_lock);
-                       swap_free(swap);
-                       __put_page(page);       /* The pagecache ref */
-                       goto free_it;
-               }
-#endif /* CONFIG_SWAP */
-
-               __remove_from_page_cache(page);
-               write_unlock_irq(&mapping->tree_lock);
-               __put_page(page);
+               if (!remove_mapping(mapping, page))
+                       goto keep_locked;
 
 free_it:
                unlock_page(page);
@@ -545,10 +551,6 @@ free_it:
                        __pagevec_release_nonlru(&freed_pvec);
                continue;
 
-cannot_free:
-               write_unlock_irq(&mapping->tree_lock);
-               goto keep_locked;
-
 activate_locked:
                SetPageActive(page);
                pgactivate++;
@@ -566,6 +568,241 @@ keep:
        return reclaimed;
 }
 
+#ifdef CONFIG_MIGRATION
+static inline void move_to_lru(struct page *page)
+{
+       list_del(&page->lru);
+       if (PageActive(page)) {
+               /*
+                * lru_cache_add_active checks that
+                * the PG_active bit is off.
+                */
+               ClearPageActive(page);
+               lru_cache_add_active(page);
+       } else {
+               lru_cache_add(page);
+       }
+       put_page(page);
+}
+
+/*
+ * Add isolated pages on the list back to the LRU
+ *
+ * returns the number of pages put back.
+ */
+int putback_lru_pages(struct list_head *l)
+{
+       struct page *page;
+       struct page *page2;
+       int count = 0;
+
+       list_for_each_entry_safe(page, page2, l, lru) {
+               move_to_lru(page);
+               count++;
+       }
+       return count;
+}
+
+/*
+ * swapout a single page
+ * page is locked upon entry, unlocked on exit
+ */
+static int swap_page(struct page *page)
+{
+       struct address_space *mapping = page_mapping(page);
+
+       if (page_mapped(page) && mapping)
+               if (try_to_unmap(page) != SWAP_SUCCESS)
+                       goto unlock_retry;
+
+       if (PageDirty(page)) {
+               /* Page is dirty, try to write it out here */
+               switch(pageout(page, mapping)) {
+               case PAGE_KEEP:
+               case PAGE_ACTIVATE:
+                       goto unlock_retry;
+
+               case PAGE_SUCCESS:
+                       goto retry;
+
+               case PAGE_CLEAN:
+                       ; /* try to free the page below */
+               }
+       }
+
+       if (PagePrivate(page)) {
+               if (!try_to_release_page(page, GFP_KERNEL) ||
+                   (!mapping && page_count(page) == 1))
+                       goto unlock_retry;
+       }
+
+       if (remove_mapping(mapping, page)) {
+               /* Success */
+               unlock_page(page);
+               return 0;
+       }
+
+unlock_retry:
+       unlock_page(page);
+
+retry:
+       return -EAGAIN;
+}
+/*
+ * migrate_pages
+ *
+ * Two lists are passed to this function. The first list
+ * contains the pages isolated from the LRU to be migrated.
+ * The second list contains new pages that the pages isolated
+ * can be moved to. If the second list is NULL then all
+ * pages are swapped out.
+ *
+ * The function returns after 10 attempts or if no pages
+ * are movable anymore because t has become empty
+ * or no retryable pages exist anymore.
+ *
+ * SIMPLIFIED VERSION: This implementation of migrate_pages
+ * is only swapping out pages and never touches the second
+ * list. The direct migration patchset
+ * extends this function to avoid the use of swap.
+ *
+ * Return: Number of pages not migrated when "to" ran empty.
+ */
+int migrate_pages(struct list_head *from, struct list_head *to,
+                 struct list_head *moved, struct list_head *failed)
+{
+       int retry;
+       int nr_failed = 0;
+       int pass = 0;
+       struct page *page;
+       struct page *page2;
+       int swapwrite = current->flags & PF_SWAPWRITE;
+       int rc;
+
+       if (!swapwrite)
+               current->flags |= PF_SWAPWRITE;
+
+redo:
+       retry = 0;
+
+       list_for_each_entry_safe(page, page2, from, lru) {
+               cond_resched();
+
+               rc = 0;
+               if (page_count(page) == 1)
+                       /* page was freed from under us. So we are done. */
+                       goto next;
+
+               /*
+                * Skip locked pages during the first two passes to give the
+                * functions holding the lock time to release the page. Later we
+                * use lock_page() to have a higher chance of acquiring the
+                * lock.
+                */
+               rc = -EAGAIN;
+               if (pass > 2)
+                       lock_page(page);
+               else
+                       if (TestSetPageLocked(page))
+                               goto next;
+
+               /*
+                * Only wait on writeback if we have already done a pass where
+                * we we may have triggered writeouts for lots of pages.
+                */
+               if (pass > 0) {
+                       wait_on_page_writeback(page);
+               } else {
+                       if (PageWriteback(page))
+                               goto unlock_page;
+               }
+
+               /*
+                * Anonymous pages must have swap cache references otherwise
+                * the information contained in the page maps cannot be
+                * preserved.
+                */
+               if (PageAnon(page) && !PageSwapCache(page)) {
+                       if (!add_to_swap(page, GFP_KERNEL)) {
+                               rc = -ENOMEM;
+                               goto unlock_page;
+                       }
+               }
+
+               /*
+                * Page is properly locked and writeback is complete.
+                * Try to migrate the page.
+                */
+               rc = swap_page(page);
+               goto next;
+
+unlock_page:
+               unlock_page(page);
+
+next:
+               if (rc == -EAGAIN) {
+                       retry++;
+               } else if (rc) {
+                       /* Permanent failure */
+                       list_move(&page->lru, failed);
+                       nr_failed++;
+               } else {
+                       /* Success */
+                       list_move(&page->lru, moved);
+               }
+       }
+       if (retry && pass++ < 10)
+               goto redo;
+
+       if (!swapwrite)
+               current->flags &= ~PF_SWAPWRITE;
+
+       return nr_failed + retry;
+}
+
+static void lru_add_drain_per_cpu(void *dummy)
+{
+       lru_add_drain();
+}
+
+/*
+ * Isolate one page from the LRU lists and put it on the
+ * indicated list. Do necessary cache draining if the
+ * page is not on the LRU lists yet.
+ *
+ * Result:
+ *  0 = page not on LRU list
+ *  1 = page removed from LRU list and added to the specified list.
+ * -ENOENT = page is being freed elsewhere.
+ */
+int isolate_lru_page(struct page *page)
+{
+       int rc = 0;
+       struct zone *zone = page_zone(page);
+
+redo:
+       spin_lock_irq(&zone->lru_lock);
+       rc = __isolate_lru_page(page);
+       if (rc == 1) {
+               if (PageActive(page))
+                       del_page_from_active_list(zone, page);
+               else
+                       del_page_from_inactive_list(zone, page);
+       }
+       spin_unlock_irq(&zone->lru_lock);
+       if (rc == 0) {
+               /*
+                * Maybe this page is still waiting for a cpu to drain it
+                * from one of the lru lists?
+                */
+               rc = schedule_on_each_cpu(lru_add_drain_per_cpu, NULL);
+               if (rc == 0 && PageLRU(page))
+                       goto redo;
+       }
+       return rc;
+}
+#endif
+
 /*
  * zone->lru_lock is heavily contended.  Some of the functions that
  * shrink the lists perform better by taking out a batch of pages
@@ -594,20 +831,18 @@ static int isolate_lru_pages(int nr_to_scan, struct list_head *src,
                page = lru_to_page(src);
                prefetchw_prev_lru_page(page, src, flags);
 
-               if (!TestClearPageLRU(page))
-                       BUG();
-               list_del(&page->lru);
-               if (get_page_testone(page)) {
-                       /*
-                        * It is being freed elsewhere
-                        */
-                       __put_page(page);
-                       SetPageLRU(page);
-                       list_add(&page->lru, src);
-                       continue;
-               } else {
-                       list_add(&page->lru, dst);
+               switch (__isolate_lru_page(page)) {
+               case 1:
+                       /* Succeeded to isolate page */
+                       list_move(&page->lru, dst);
                        nr_taken++;
+                       break;
+               case -ENOENT:
+                       /* Not possible to isolate */
+                       list_move(&page->lru, src);
+                       break;
+               default:
+                       BUG();
                }
        }
 
@@ -1226,7 +1461,7 @@ static int kswapd(void *p)
         * us from recursively trying to free more memory as we're
         * trying to free the first piece of memory in the first place).
         */
-       tsk->flags |= PF_MEMALLOC|PF_KSWAPD;
+       tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
 
        order = 0;
        for ( ; ; ) {
index 01861929591a88f41ab4d356924310f73f75d433..977704a54f6879ae3d3fef2123c6e38793c97112 100644 (file)
@@ -2,8 +2,6 @@
 # Makefile for the Linux 802.x protocol layers.
 #
 
-obj-y                  := p8023.o
-
 # Check the p8022 selections against net/core/Makefile.
 obj-$(CONFIG_SYSCTL)   += sysctl_net_802.o
 obj-$(CONFIG_LLC)      += p8022.o psnap.o
@@ -11,5 +9,5 @@ obj-$(CONFIG_TR)       += p8022.o psnap.o tr.o sysctl_net_802.o
 obj-$(CONFIG_NET_FC)   +=                 fc.o
 obj-$(CONFIG_FDDI)     +=                 fddi.o
 obj-$(CONFIG_HIPPI)    +=                 hippi.o
-obj-$(CONFIG_IPX)      += p8022.o psnap.o
+obj-$(CONFIG_IPX)      += p8022.o psnap.o p8023.o
 obj-$(CONFIG_ATALK)    += p8022.o psnap.o
index 3f244670764ae94fad1826439a748f860d1b808c..00f983226672a6c70aca4a67368cceae2d7a118b 100644 (file)
@@ -986,6 +986,7 @@ int dccp_v4_rcv(struct sk_buff *skb)
 
        if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_and_relse;
+       nf_reset(skb);
 
        return sk_receive_skb(sk, skb);
 
index c609dc78f4871382ac582949497cdeef3b5cc312..df074259f9c3100581f649499dac1ae5554d1770 100644 (file)
@@ -27,6 +27,7 @@
 #include <net/ipv6.h>
 #include <net/protocol.h>
 #include <net/transp_v6.h>
+#include <net/ip6_checksum.h>
 #include <net/xfrm.h>
 
 #include "dccp.h"
@@ -1028,7 +1029,7 @@ discard:
        return 0;
 }
 
-static int dccp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+static int dccp_v6_rcv(struct sk_buff **pskb)
 {
        const struct dccp_hdr *dh;
        struct sk_buff *skb = *pskb;
index 073aebdf0f67cff356d56c50efd0a878a123dd0f..f8dca31be5dd6b23e1090740fff257280078f6ed 100644 (file)
@@ -75,22 +75,14 @@ static void prism2_wep_deinit(void *priv)
        kfree(priv);
 }
 
-/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
- * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
- * so the payload length increases with 8 bytes.
- *
- * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
- */
-static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
+static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv)
 {
        struct prism2_wep_data *wep = priv;
-       u32 crc, klen, len;
-       u8 key[WEP_KEY_LEN + 3];
-       u8 *pos, *icv;
-       struct scatterlist sg;
-
-       if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
-           skb->len < hdr_len)
+       u32 klen, len;
+       u8 *pos;
+       
+       if (skb_headroom(skb) < 4 || skb->len < hdr_len)
                return -1;
 
        len = skb->len - hdr_len;
@@ -112,15 +104,47 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        }
 
        /* Prepend 24-bit IV to RC4 key and TX frame */
-       *pos++ = key[0] = (wep->iv >> 16) & 0xff;
-       *pos++ = key[1] = (wep->iv >> 8) & 0xff;
-       *pos++ = key[2] = wep->iv & 0xff;
+       *pos++ = (wep->iv >> 16) & 0xff;
+       *pos++ = (wep->iv >> 8) & 0xff;
+       *pos++ = wep->iv & 0xff;
        *pos++ = wep->key_idx << 6;
 
+       return 0;
+}
+
+/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
+ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
+ * so the payload length increases with 8 bytes.
+ *
+ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
+ */
+static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct prism2_wep_data *wep = priv;
+       u32 crc, klen, len;
+       u8 *pos, *icv;
+       struct scatterlist sg;
+       u8 key[WEP_KEY_LEN + 3];
+
+       /* other checks are in prism2_wep_build_iv */
+       if (skb_tailroom(skb) < 4)
+               return -1;
+       
+       /* add the IV to the frame */
+       if (prism2_wep_build_iv(skb, hdr_len, priv))
+               return -1;
+       
+       /* Copy the IV into the first 3 bytes of the key */
+       memcpy(key, skb->data + hdr_len, 3);
+
        /* Copy rest of the WEP key (the secret part) */
        memcpy(key + 3, wep->key, wep->key_len);
+       
+       len = skb->len - hdr_len - 4;
+       pos = skb->data + hdr_len + 4;
+       klen = 3 + wep->key_len;
 
-       /* Append little-endian CRC32 and encrypt it to produce ICV */
+       /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */
        crc = ~crc32_le(~0, pos, len);
        icv = skb_put(skb, 4);
        icv[0] = crc;
@@ -231,6 +255,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
        .name = "WEP",
        .init = prism2_wep_init,
        .deinit = prism2_wep_deinit,
+       .build_iv = prism2_wep_build_iv,
        .encrypt_mpdu = prism2_wep_encrypt,
        .decrypt_mpdu = prism2_wep_decrypt,
        .encrypt_msdu = NULL,
index 445f206e65e0ea4b73327b1734d89d8639590958..e5b33c8d5dbcc0e683cc3f4daf60eb7532ff8d9b 100644 (file)
@@ -288,7 +288,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Determine total amount of storage required for TXB packets */
        bytes = skb->len + SNAP_SIZE + sizeof(u16);
 
-       if (host_encrypt)
+       if (host_encrypt || host_build_iv)
                fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
                    IEEE80211_FCTL_PROTECTED;
        else
index 181755f2aa8bf8e53cee7121bd807ee56bc7ec59..406d5b9649059f5ea9af820609db8577029cb015 100644 (file)
@@ -284,7 +284,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
        };
        int i, key, key_provided, len;
        struct ieee80211_crypt_data **crypt;
-       int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
+       int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
 
        IEEE80211_DEBUG_WX("SET_ENCODE\n");
 
index 912c42f57c79089cc1ea581ba60316204cb5704d..de16e944777f5838aa07fd1d2f899da9ac0805f6 100644 (file)
@@ -832,6 +832,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        skb->h.raw = skb->nh.raw;
        skb->nh.raw = skb_push(skb, gre_hlen);
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+       IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE|IPSKB_XFRM_TRANSFORMED);
        dst_release(skb->dst);
        skb->dst = &rt->u.dst;
 
index e45846ae570bba9c3b3da568e5e8b7e46598e7f3..18d7fad474d72510e18177837912e5ff26ea4acb 100644 (file)
@@ -185,7 +185,6 @@ int ip_call_ra_chain(struct sk_buff *skb)
                                        raw_rcv(last, skb2);
                        }
                        last = sk;
-                       nf_reset(skb);
                }
        }
 
@@ -204,10 +203,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
 
        __skb_pull(skb, ihl);
 
-       /* Free reference early: we don't need it any more, and it may
-           hold ip_conntrack module loaded indefinitely. */
-       nf_reset(skb);
-
         /* Point into the IP datagram, just past the header. */
         skb->h.raw = skb->data;
 
@@ -232,10 +227,12 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
                if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
                        int ret;
 
-                       if (!ipprot->no_policy &&
-                           !xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-                               kfree_skb(skb);
-                               goto out;
+                       if (!ipprot->no_policy) {
+                               if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+                                       kfree_skb(skb);
+                                       goto out;
+                               }
+                               nf_reset(skb);
                        }
                        ret = ipprot->handler(skb);
                        if (ret < 0) {
index 8b1c9bd0091e76f8d709b7d2a81be0f02fbafb18..c2169b47ddfd0ddf6f912fe35f85858f5ee313cb 100644 (file)
@@ -85,6 +85,8 @@
 
 int sysctl_ip_default_ttl = IPDEFTTL;
 
+static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*));
+
 /* Generate a checksum for an outgoing IP datagram. */
 __inline__ void ip_send_check(struct iphdr *iph)
 {
@@ -202,6 +204,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
 
 static inline int ip_finish_output(struct sk_buff *skb)
 {
+#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
+       /* Policy lookup after SNAT yielded a new policy */
+       if (skb->dst->xfrm != NULL)
+               return xfrm4_output_finish(skb);
+#endif
        if (skb->len > dst_mtu(skb->dst) &&
            !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
                return ip_fragment(skb, ip_finish_output2);
@@ -409,7 +416,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
  *     single device frame, and queue such a frame for sending.
  */
 
-int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
 {
        struct iphdr *iph;
        int raw = 0;
@@ -1391,7 +1398,6 @@ void __init ip_init(void)
 #endif
 }
 
-EXPORT_SYMBOL(ip_fragment);
 EXPORT_SYMBOL(ip_generic_getfrag);
 EXPORT_SYMBOL(ip_queue_xmit);
 EXPORT_SYMBOL(ip_send_check);
index 35571cff81c6eae38033ee3ce47ba590afff67ea..bbd85f5ec9859ddba5fe3b986894402cde60730d 100644 (file)
@@ -621,6 +621,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        skb->h.raw = skb->nh.raw;
        skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+       IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE|IPSKB_XFRM_TRANSFORMED);
        dst_release(skb->dst);
        skb->dst = &rt->u.dst;
 
index ae0779d82c5d2191744da417b277fdd3c8fbbda6..3321092b0914be3a04f82d850b78c47ccfc6449b 100644 (file)
@@ -7,11 +7,13 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
 
+#include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/icmp.h>
 #include <net/route.h>
-#include <linux/ip.h>
+#include <net/xfrm.h>
+#include <net/ip.h>
 
 /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
 int ip_route_me_harder(struct sk_buff **pskb)
@@ -33,7 +35,6 @@ int ip_route_me_harder(struct sk_buff **pskb)
 #ifdef CONFIG_IP_ROUTE_FWMARK
                fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
 #endif
-               fl.proto = iph->protocol;
                if (ip_route_output_key(&rt, &fl) != 0)
                        return -1;
 
@@ -60,6 +61,13 @@ int ip_route_me_harder(struct sk_buff **pskb)
        if ((*pskb)->dst->error)
                return -1;
 
+#ifdef CONFIG_XFRM
+       if (!(IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED) &&
+           xfrm_decode_session(*pskb, &fl, AF_INET) == 0)
+               if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0))
+                       return -1;
+#endif
+
        /* Change in oif may mean change in hh_len. */
        hh_len = (*pskb)->dst->dev->hard_header_len;
        if (skb_headroom(*pskb) < hh_len) {
@@ -78,6 +86,9 @@ int ip_route_me_harder(struct sk_buff **pskb)
 }
 EXPORT_SYMBOL(ip_route_me_harder);
 
+void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
+EXPORT_SYMBOL(ip_nat_decode_session);
+
 /*
  * Extra routing may needed on local out, as the QUEUE target never
  * returns control to the table.
index 88a60650e6b8d795462c58e9f0a14159bbb96ee6..a9893ec03e029e8b4a656c980399d66bbed5a753 100644 (file)
@@ -487,6 +487,16 @@ config IP_NF_MATCH_STRING
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP_NF_MATCH_POLICY
+       tristate "IPsec policy match support"
+       depends on IP_NF_IPTABLES && XFRM
+       help
+         Policy matching allows you to match packets based on the
+         IPsec policy that was used during decapsulation/will
+         be used during encapsulation.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 # `filter', generic and specific targets
 config IP_NF_FILTER
        tristate "Packet filtering"
index d0a447e520a23c05c7d8751c77b0792fd70617db..549b01a648b31e41f755621b849c5c5164e4afb6 100644 (file)
@@ -72,6 +72,7 @@ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
 obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
 obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
+obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
 obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o
 obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
 
index 977fb59d4563361875826fec0817d92750af00da..0b25050981a16caaef5156fbad2e79a4dc96faca 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
+#include <linux/interrupt.h>
 #include <linux/netfilter.h>
 #include <linux/module.h>
 #include <linux/in.h>
index f04111f74e090dcde7e9b481277c28e6f05d9e0e..8b8a1f00bbf4407e2a8f09d17831dae33fcd656f 100644 (file)
                                 : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  \
                                    : "*ERROR*")))
 
+#ifdef CONFIG_XFRM
+static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
+{
+       struct ip_conntrack *ct;
+       struct ip_conntrack_tuple *t;
+       enum ip_conntrack_info ctinfo;
+       enum ip_conntrack_dir dir;
+       unsigned long statusbit;
+
+       ct = ip_conntrack_get(skb, &ctinfo);
+       if (ct == NULL)
+               return;
+       dir = CTINFO2DIR(ctinfo);
+       t = &ct->tuplehash[dir].tuple;
+
+       if (dir == IP_CT_DIR_ORIGINAL)
+               statusbit = IPS_DST_NAT;
+       else
+               statusbit = IPS_SRC_NAT;
+
+       if (ct->status & statusbit) {
+               fl->fl4_dst = t->dst.ip;
+               if (t->dst.protonum == IPPROTO_TCP ||
+                   t->dst.protonum == IPPROTO_UDP)
+                       fl->fl_ip_dport = t->dst.u.tcp.port;
+       }
+
+       statusbit ^= IPS_NAT_MASK;
+
+       if (ct->status & statusbit) {
+               fl->fl4_src = t->src.ip;
+               if (t->dst.protonum == IPPROTO_TCP ||
+                   t->dst.protonum == IPPROTO_UDP)
+                       fl->fl_ip_sport = t->src.u.tcp.port;
+       }
+}
+#endif
+               
 static unsigned int
 ip_nat_fn(unsigned int hooknum,
          struct sk_buff **pskb,
@@ -162,18 +200,20 @@ ip_nat_in(unsigned int hooknum,
           const struct net_device *out,
           int (*okfn)(struct sk_buff *))
 {
-       u_int32_t saddr, daddr;
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
        unsigned int ret;
 
-       saddr = (*pskb)->nh.iph->saddr;
-       daddr = (*pskb)->nh.iph->daddr;
-
        ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
        if (ret != NF_DROP && ret != NF_STOLEN
-           && ((*pskb)->nh.iph->saddr != saddr
-               || (*pskb)->nh.iph->daddr != daddr)) {
-               dst_release((*pskb)->dst);
-               (*pskb)->dst = NULL;
+           && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
+               enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+
+               if (ct->tuplehash[dir].tuple.src.ip !=
+                   ct->tuplehash[!dir].tuple.dst.ip) {
+                       dst_release((*pskb)->dst);
+                       (*pskb)->dst = NULL;
+               }
        }
        return ret;
 }
@@ -185,12 +225,30 @@ ip_nat_out(unsigned int hooknum,
           const struct net_device *out,
           int (*okfn)(struct sk_buff *))
 {
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+       unsigned int ret;
+
        /* root is playing with raw sockets. */
        if ((*pskb)->len < sizeof(struct iphdr)
            || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
                return NF_ACCEPT;
 
-       return ip_nat_fn(hooknum, pskb, in, out, okfn);
+       ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
+       if (ret != NF_DROP && ret != NF_STOLEN
+           && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
+               enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+
+               if (ct->tuplehash[dir].tuple.src.ip !=
+                   ct->tuplehash[!dir].tuple.dst.ip
+#ifdef CONFIG_XFRM
+                   || ct->tuplehash[dir].tuple.src.u.all !=
+                      ct->tuplehash[!dir].tuple.dst.u.all
+#endif
+                   )
+                       return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+       }
+       return ret;
 }
 
 static unsigned int
@@ -200,7 +258,8 @@ ip_nat_local_fn(unsigned int hooknum,
                const struct net_device *out,
                int (*okfn)(struct sk_buff *))
 {
-       u_int32_t saddr, daddr;
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
        unsigned int ret;
 
        /* root is playing with raw sockets. */
@@ -208,14 +267,20 @@ ip_nat_local_fn(unsigned int hooknum,
            || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
                return NF_ACCEPT;
 
-       saddr = (*pskb)->nh.iph->saddr;
-       daddr = (*pskb)->nh.iph->daddr;
-
        ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
        if (ret != NF_DROP && ret != NF_STOLEN
-           && ((*pskb)->nh.iph->saddr != saddr
-               || (*pskb)->nh.iph->daddr != daddr))
-               return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+           && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
+               enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+
+               if (ct->tuplehash[dir].tuple.dst.ip !=
+                   ct->tuplehash[!dir].tuple.src.ip
+#ifdef CONFIG_XFRM
+                   || ct->tuplehash[dir].tuple.dst.u.all !=
+                      ct->tuplehash[dir].tuple.src.u.all
+#endif
+                   )
+                       return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+       }
        return ret;
 }
 
@@ -303,10 +368,14 @@ static int init_or_cleanup(int init)
 
        if (!init) goto cleanup;
 
+#ifdef CONFIG_XFRM
+       BUG_ON(ip_nat_decode_session != NULL);
+       ip_nat_decode_session = nat_decode_session;
+#endif
        ret = ip_nat_rule_init();
        if (ret < 0) {
                printk("ip_nat_init: can't setup rules.\n");
-               goto cleanup_nothing;
+               goto cleanup_decode_session;
        }
        ret = nf_register_hook(&ip_nat_in_ops);
        if (ret < 0) {
@@ -354,7 +423,11 @@ static int init_or_cleanup(int init)
        nf_unregister_hook(&ip_nat_in_ops);
  cleanup_rule_init:
        ip_nat_rule_cleanup();
- cleanup_nothing:
+ cleanup_decode_session:
+#ifdef CONFIG_XFRM
+       ip_nat_decode_session = NULL;
+       synchronize_net();
+#endif
        return ret;
 }
 
diff --git a/net/ipv4/netfilter/ipt_policy.c b/net/ipv4/netfilter/ipt_policy.c
new file mode 100644 (file)
index 0000000..709debc
--- /dev/null
@@ -0,0 +1,170 @@
+/* IP tables module for matching IPsec policy
+ *
+ * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <net/xfrm.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_policy.h>
+
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("IPtables IPsec policy matching module");
+MODULE_LICENSE("GPL");
+
+
+static inline int
+match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
+{
+#define MATCH(x,y)     (!e->match.x || ((e->x == (y)) ^ e->invert.x))
+
+       return MATCH(saddr, x->props.saddr.a4 & e->smask) &&
+              MATCH(daddr, x->id.daddr.a4 & e->dmask) &&
+              MATCH(proto, x->id.proto) &&
+              MATCH(mode, x->props.mode) &&
+              MATCH(spi, x->id.spi) &&
+              MATCH(reqid, x->props.reqid);
+}
+
+static int
+match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info)
+{
+       const struct ipt_policy_elem *e;
+       struct sec_path *sp = skb->sp;
+       int strict = info->flags & IPT_POLICY_MATCH_STRICT;
+       int i, pos;
+
+       if (sp == NULL)
+               return -1;
+       if (strict && info->len != sp->len)
+               return 0;
+
+       for (i = sp->len - 1; i >= 0; i--) {
+               pos = strict ? i - sp->len + 1 : 0;
+               if (pos >= info->len)
+                       return 0;
+               e = &info->pol[pos];
+
+               if (match_xfrm_state(sp->x[i].xvec, e)) {
+                       if (!strict)
+                               return 1;
+               } else if (strict)
+                       return 0;
+       }
+
+       return strict ? 1 : 0;
+}
+
+static int
+match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
+{
+       const struct ipt_policy_elem *e;
+       struct dst_entry *dst = skb->dst;
+       int strict = info->flags & IPT_POLICY_MATCH_STRICT;
+       int i, pos;
+
+       if (dst->xfrm == NULL)
+               return -1;
+
+       for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
+               pos = strict ? i : 0;
+               if (pos >= info->len)
+                       return 0;
+               e = &info->pol[pos];
+
+               if (match_xfrm_state(dst->xfrm, e)) {
+                       if (!strict)
+                               return 1;
+               } else if (strict)
+                       return 0;
+       }
+
+       return strict ? 1 : 0;
+}
+
+static int match(const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const void *matchinfo, int offset, int *hotdrop)
+{
+       const struct ipt_policy_info *info = matchinfo;
+       int ret;
+
+       if (info->flags & IPT_POLICY_MATCH_IN)
+               ret = match_policy_in(skb, info);
+       else
+               ret = match_policy_out(skb, info);
+
+       if (ret < 0)
+               ret = info->flags & IPT_POLICY_MATCH_NONE ? 1 : 0;
+       else if (info->flags & IPT_POLICY_MATCH_NONE)
+               ret = 0;
+
+       return ret;
+}
+
+static int checkentry(const char *tablename, const struct ipt_ip *ip,
+                      void *matchinfo, unsigned int matchsize,
+                      unsigned int hook_mask)
+{
+       struct ipt_policy_info *info = matchinfo;
+
+       if (matchsize != IPT_ALIGN(sizeof(*info))) {
+               printk(KERN_ERR "ipt_policy: matchsize %u != %zu\n",
+                      matchsize, IPT_ALIGN(sizeof(*info)));
+               return 0;
+       }
+       if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) {
+               printk(KERN_ERR "ipt_policy: neither incoming nor "
+                               "outgoing policy selected\n");
+               return 0;
+       }
+       if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
+           && info->flags & IPT_POLICY_MATCH_OUT) {
+               printk(KERN_ERR "ipt_policy: output policy not valid in "
+                               "PRE_ROUTING and INPUT\n");
+               return 0;
+       }
+       if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
+           && info->flags & IPT_POLICY_MATCH_IN) {
+               printk(KERN_ERR "ipt_policy: input policy not valid in "
+                               "POST_ROUTING and OUTPUT\n");
+               return 0;
+       }
+       if (info->len > IPT_POLICY_MAX_ELEM) {
+               printk(KERN_ERR "ipt_policy: too many policy elements\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct ipt_match policy_match = {
+       .name           = "policy",
+       .match          = match,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       return ipt_register_match(&policy_match);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_match(&policy_match);
+}
+
+module_init(init);
+module_exit(fini);
index 4b0d7e4d62698a44acd992fd3e2a01e14b3037f0..165a4d81efa4a75663e72e12d3cfa12eddb9f969 100644 (file)
@@ -255,6 +255,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb)
                kfree_skb(skb);
                return NET_RX_DROP;
        }
+       nf_reset(skb);
 
        skb_push(skb, skb->data - skb->nh.raw);
 
index e9f83e5b28ce93a7e2a3e76a878526ec227ad497..6ea353907af5757de1abc84e6b87274afa4d26fe 100644 (file)
@@ -1080,6 +1080,7 @@ process:
 
        if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_and_relse;
+       nf_reset(skb);
 
        if (sk_filter(sk, skb, 0))
                goto discard_and_relse;
index 223abaa72bc53b24b0e39356582cacf86c18e988..00840474a44947eaaf8ce917bee7d22ccc4a4a63 100644 (file)
@@ -989,6 +989,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
                kfree_skb(skb);
                return -1;
        }
+       nf_reset(skb);
 
        if (up->encap_type) {
                /*
@@ -1149,6 +1150,7 @@ int udp_rcv(struct sk_buff *skb)
 
        if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
                goto drop;
+       nf_reset(skb);
 
        /* No socket. Drop packet silently, if checksum is wrong */
        if (udp_checksum_complete(skb))
index 2d3849c38a0f8224da7f35a0ecb22b46353aa68d..850d919591d1c817bc196407a90fd338ab0d2316 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
 #include <net/inet_ecn.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
@@ -45,6 +47,23 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
        return xfrm_parse_spi(skb, nexthdr, spi, seq);
 }
 
+#ifdef CONFIG_NETFILTER
+static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
+{
+       struct iphdr *iph = skb->nh.iph;
+
+       if (skb->dst == NULL) {
+               if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
+                                  skb->dev))
+                       goto drop;
+       }
+       return dst_input(skb);
+drop:
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+#endif
+
 int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 {
        int err;
@@ -137,6 +156,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
        memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
        skb->sp->len += xfrm_nr;
 
+       nf_reset(skb);
+
        if (decaps) {
                if (!(skb->dev->flags&IFF_LOOPBACK)) {
                        dst_release(skb->dst);
@@ -145,7 +166,17 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
                netif_rx(skb);
                return 0;
        } else {
+#ifdef CONFIG_NETFILTER
+               __skb_push(skb, skb->data - skb->nh.raw);
+               skb->nh.iph->tot_len = htons(skb->len);
+               ip_send_check(skb->nh.iph);
+
+               NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
+                       xfrm4_rcv_encap_finish);
+               return 0;
+#else
                return -skb->nh.iph->protocol;
+#endif
        }
 
 drop_unlock:
index 66620a95942a5f3f05f0964883eb358706130964..d4df0ddd424b2e9500d27a518c053cf0af3c4b7e 100644 (file)
@@ -8,8 +8,10 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/compiler.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
+#include <linux/netfilter_ipv4.h>
 #include <net/inet_ecn.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
@@ -95,7 +97,7 @@ out:
        return ret;
 }
 
-int xfrm4_output(struct sk_buff *skb)
+static int xfrm4_output_one(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb->dst;
        struct xfrm_state *x = dst->xfrm;
@@ -113,27 +115,33 @@ int xfrm4_output(struct sk_buff *skb)
                        goto error_nolock;
        }
 
-       spin_lock_bh(&x->lock);
-       err = xfrm_state_check(x, skb);
-       if (err)
-               goto error;
+       do {
+               spin_lock_bh(&x->lock);
+               err = xfrm_state_check(x, skb);
+               if (err)
+                       goto error;
 
-       xfrm4_encap(skb);
+               xfrm4_encap(skb);
 
-       err = x->type->output(x, skb);
-       if (err)
-               goto error;
+               err = x->type->output(x, skb);
+               if (err)
+                       goto error;
 
-       x->curlft.bytes += skb->len;
-       x->curlft.packets++;
+               x->curlft.bytes += skb->len;
+               x->curlft.packets++;
 
-       spin_unlock_bh(&x->lock);
+               spin_unlock_bh(&x->lock);
        
-       if (!(skb->dst = dst_pop(dst))) {
-               err = -EHOSTUNREACH;
-               goto error_nolock;
-       }
-       err = NET_XMIT_BYPASS;
+               if (!(skb->dst = dst_pop(dst))) {
+                       err = -EHOSTUNREACH;
+                       goto error_nolock;
+               }
+               dst = skb->dst;
+               x = dst->xfrm;
+       } while (x && !x->props.mode);
+
+       IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+       err = 0;
 
 out_exit:
        return err;
@@ -143,3 +151,33 @@ error_nolock:
        kfree_skb(skb);
        goto out_exit;
 }
+
+int xfrm4_output_finish(struct sk_buff *skb)
+{
+       int err;
+
+       while (likely((err = xfrm4_output_one(skb)) == 0)) {
+               nf_reset(skb);
+
+               err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, &skb, NULL,
+                             skb->dst->dev, dst_output);
+               if (unlikely(err != 1))
+                       break;
+
+               if (!skb->dst->xfrm)
+                       return dst_output(skb);
+
+               err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
+                             skb->dst->dev, xfrm4_output_finish);
+               if (unlikely(err != 1))
+                       break;
+       }
+
+       return err;
+}
+
+int xfrm4_output(struct sk_buff *skb)
+{
+       return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
+                      xfrm4_output_finish);
+}
index 704fb73e6c5ff35f83147a96a84fe45be40d471b..e53e421eeee94b3ecdb842ccd4b1d0d24c4c3b58 100644 (file)
@@ -1228,7 +1228,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
 
 /* Gets referenced address, destroys ifaddr */
 
-void addrconf_dad_stop(struct inet6_ifaddr *ifp)
+static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
 {
        if (ifp->flags&IFA_F_PERMANENT) {
                spin_lock_bh(&ifp->lock);
index 68afc53be6628a0b26c7fc6cf6556ff8c9b4bdc8..25c3fe5005d9f6a9753e131825169e8fb7dd0f9a 100644 (file)
@@ -689,11 +689,11 @@ snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign)
        if (ptr == NULL)
                return -EINVAL;
 
-       ptr[0] = __alloc_percpu(mibsize, mibalign);
+       ptr[0] = __alloc_percpu(mibsize);
        if (!ptr[0])
                goto err0;
 
-       ptr[1] = __alloc_percpu(mibsize, mibalign);
+       ptr[1] = __alloc_percpu(mibsize);
        if (!ptr[1])
                goto err1;
 
index 113374dc342c1fdd116173572131853437076d48..2a1e7e45b890ff9eccb841c3271b3b09e52c8305 100644 (file)
@@ -152,7 +152,7 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = {
        {-1,                    NULL}
 };
 
-static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
+static int ipv6_destopt_rcv(struct sk_buff **skbp)
 {
        struct sk_buff *skb = *skbp;
        struct inet6_skb_parm *opt = IP6CB(skb);
@@ -169,7 +169,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 
        if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
                skb->h.raw += ((skb->h.raw[1]+1)<<3);
-               *nhoffp = opt->dst1;
+               opt->nhoff = opt->dst1;
                return 1;
        }
 
@@ -192,7 +192,7 @@ void __init ipv6_destopt_init(void)
   NONE header. No data in packet.
  ********************************/
 
-static int ipv6_nodata_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
+static int ipv6_nodata_rcv(struct sk_buff **skbp)
 {
        struct sk_buff *skb = *skbp;
 
@@ -215,7 +215,7 @@ void __init ipv6_nodata_init(void)
   Routing header.
  ********************************/
 
-static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
+static int ipv6_rthdr_rcv(struct sk_buff **skbp)
 {
        struct sk_buff *skb = *skbp;
        struct inet6_skb_parm *opt = IP6CB(skb);
@@ -249,7 +249,7 @@ looped_back:
                skb->h.raw += (hdr->hdrlen + 1) << 3;
                opt->dst0 = opt->dst1;
                opt->dst1 = 0;
-               *nhoffp = (&hdr->nexthdr) - skb->nh.raw;
+               opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
                return 1;
        }
 
@@ -487,9 +487,14 @@ static struct tlvtype_proc tlvprochopopt_lst[] = {
 
 int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
 {
-       IP6CB(skb)->hop = sizeof(struct ipv6hdr);
-       if (ip6_parse_tlv(tlvprochopopt_lst, skb))
+       struct inet6_skb_parm *opt = IP6CB(skb);
+
+       opt->hop = sizeof(struct ipv6hdr);
+       if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
+               skb->h.raw += (skb->h.raw[1]+1)<<3;
+               opt->nhoff = sizeof(struct ipv6hdr);
                return sizeof(struct ipv6hdr);
+       }
        return -1;
 }
 
index 6ec6a2b549bbd6d6930230d8bb8ca00d0e208f1f..53c81fcd20ba23b6573c1525a412f700ba10cccd 100644 (file)
@@ -79,7 +79,7 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly;
 static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL;
 #define icmpv6_socket  __get_cpu_var(__icmpv6_socket)
 
-static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
+static int icmpv6_rcv(struct sk_buff **pskb);
 
 static struct inet6_protocol icmpv6_protocol = {
        .handler        =       icmpv6_rcv,
@@ -581,7 +581,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
  *     Handle icmp messages
  */
 
-static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+static int icmpv6_rcv(struct sk_buff **pskb)
 {
        struct sk_buff *skb = *pskb;
        struct net_device *dev = skb->dev;
index 792f90f0f9ece287c0d94a2fbfdf7073c09e7aff..f8f3a37a14948f4d291ba85cac267b33ebdf3079 100644 (file)
@@ -25,6 +25,7 @@
 #include <net/inet_hashtables.h>
 #include <net/ip6_route.h>
 #include <net/sock.h>
+#include <net/inet6_connection_sock.h>
 
 int inet6_csk_bind_conflict(const struct sock *sk,
                            const struct inet_bind_bucket *tb)
index a6026d2787d2c042a05924c33ebba66f91b6f101..29f73592e68e51304c7c6859c82eb44248e3a3ae 100644 (file)
@@ -48,7 +48,7 @@
 
 
 
-static inline int ip6_rcv_finish( struct sk_buff *skb) 
+inline int ip6_rcv_finish( struct sk_buff *skb) 
 {
        if (skb->dst == NULL)
                ip6_route_input(skb);
@@ -97,6 +97,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
        if (hdr->version != 6)
                goto err;
 
+       skb->h.raw = (u8 *)(hdr + 1);
+       IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
+
        pkt_len = ntohs(hdr->payload_len);
 
        /* pkt_len may be zero if Jumbo payload option is present */
@@ -111,8 +114,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
        }
 
        if (hdr->nexthdr == NEXTHDR_HOP) {
-               skb->h.raw = (u8*)(hdr+1);
-               if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) {
+               if (ipv6_parse_hopopts(skb, IP6CB(skb)->nhoff) < 0) {
                        IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
                        return 0;
                }
@@ -143,26 +145,15 @@ static inline int ip6_input_finish(struct sk_buff *skb)
        int nexthdr;
        u8 hash;
 
-       skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
-
        /*
         *      Parse extension headers
         */
 
-       nexthdr = skb->nh.ipv6h->nexthdr;
-       nhoff = offsetof(struct ipv6hdr, nexthdr);
-
-       /* Skip hop-by-hop options, they are already parsed. */
-       if (nexthdr == NEXTHDR_HOP) {
-               nhoff = sizeof(struct ipv6hdr);
-               nexthdr = skb->h.raw[0];
-               skb->h.raw += (skb->h.raw[1]+1)<<3;
-       }
-
        rcu_read_lock();
 resubmit:
        if (!pskb_pull(skb, skb->h.raw - skb->data))
                goto discard;
+       nhoff = IP6CB(skb)->nhoff;
        nexthdr = skb->nh.raw[nhoff];
 
        raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
@@ -194,7 +185,7 @@ resubmit:
                    !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 
                        goto discard;
                
-               ret = ipprot->handler(&skb, &nhoff);
+               ret = ipprot->handler(&skb);
                if (ret > 0)
                        goto resubmit;
                else if (ret == 0)
index e315d0f80af1ef3a531c8293e8c33d56e6b08102..f079621c8b671d3b121354f0da7c25b6824d3109 100644 (file)
@@ -510,7 +510,7 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
  **/
 
 static int 
-ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+ip6ip6_rcv(struct sk_buff **pskb)
 {
        struct sk_buff *skb = *pskb;
        struct ipv6hdr *ipv6h;
index f8626ebf90fd7a2f2fb7bbd4972748498e79bd27..b63678328a3b2c97ce17a58fcbc4cfa8975c7b63 100644 (file)
@@ -10,6 +10,7 @@
 #include <net/dst.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
+#include <net/xfrm.h>
 
 int ip6_route_me_harder(struct sk_buff *skb)
 {
@@ -21,11 +22,17 @@ int ip6_route_me_harder(struct sk_buff *skb)
                { .ip6_u =
                  { .daddr = iph->daddr,
                    .saddr = iph->saddr, } },
-               .proto = iph->nexthdr,
        };
 
        dst = ip6_route_output(skb->sk, &fl);
 
+#ifdef CONFIG_XFRM
+       if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
+           xfrm_decode_session(skb, &fl, AF_INET6) == 0)
+               if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0))
+                       return -1;
+#endif
+
        if (dst->error) {
                IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
                LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
index 04912f9b35c36a8d80cfeb1a6e245035847b4416..105dd69ee9fb54cbe4419ffac31a71cf1205f7ed 100644 (file)
@@ -179,6 +179,16 @@ config IP6_NF_MATCH_PHYSDEV
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_MATCH_POLICY
+       tristate "IPsec policy match support"
+       depends on IP6_NF_IPTABLES && XFRM
+       help
+         Policy matching allows you to match packets based on the
+         IPsec policy that was used during decapsulation/will
+         be used during encapsulation.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 # The targets
 config IP6_NF_FILTER
        tristate "Packet filtering"
index 9ab5b2ca1f59033eb7111432013936298f24e395..c0c809b426e87f244267103342e612fc1c7fcbe5 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
 obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
 obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
+obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c
new file mode 100644 (file)
index 0000000..13fedad
--- /dev/null
@@ -0,0 +1,175 @@
+/* IP tables module for matching IPsec policy
+ *
+ * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <net/xfrm.h>
+
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_policy.h>
+
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("IPtables IPsec policy matching module");
+MODULE_LICENSE("GPL");
+
+
+static inline int
+match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e)
+{
+#define MATCH_ADDR(x,y,z)      (!e->match.x || \
+                                ((ip6_masked_addrcmp((z), &e->x, &e->y)) == 0) ^ e->invert.x)
+#define MATCH(x,y)             (!e->match.x || ((e->x == (y)) ^ e->invert.x))
+       
+       return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) &&
+              MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) &&
+              MATCH(proto, x->id.proto) &&
+              MATCH(mode, x->props.mode) &&
+              MATCH(spi, x->id.spi) &&
+              MATCH(reqid, x->props.reqid);
+}
+
+static int
+match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info)
+{
+       const struct ip6t_policy_elem *e;
+       struct sec_path *sp = skb->sp;
+       int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
+       int i, pos;
+
+       if (sp == NULL)
+               return -1;
+       if (strict && info->len != sp->len)
+               return 0;
+
+       for (i = sp->len - 1; i >= 0; i--) {
+               pos = strict ? i - sp->len + 1 : 0;
+               if (pos >= info->len)
+                       return 0;
+               e = &info->pol[pos];
+
+               if (match_xfrm_state(sp->x[i].xvec, e)) {
+                       if (!strict)
+                               return 1;
+               } else if (strict)
+                       return 0;
+       }
+
+       return strict ? 1 : 0;
+}
+
+static int
+match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info)
+{
+       const struct ip6t_policy_elem *e;
+       struct dst_entry *dst = skb->dst;
+       int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
+       int i, pos;
+
+       if (dst->xfrm == NULL)
+               return -1;
+
+       for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
+               pos = strict ? i : 0;
+               if (pos >= info->len)
+                       return 0;
+               e = &info->pol[pos];
+
+               if (match_xfrm_state(dst->xfrm, e)) {
+                       if (!strict)
+                               return 1;
+               } else if (strict)
+                       return 0;
+       }
+
+       return strict ? 1 : 0;
+}
+
+static int match(const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const void *matchinfo,
+                int offset,
+                unsigned int protoff,
+                int *hotdrop)
+{
+       const struct ip6t_policy_info *info = matchinfo;
+       int ret;
+
+       if (info->flags & IP6T_POLICY_MATCH_IN)
+               ret = match_policy_in(skb, info);
+       else
+               ret = match_policy_out(skb, info);
+
+       if (ret < 0)
+               ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0;
+       else if (info->flags & IP6T_POLICY_MATCH_NONE)
+               ret = 0;
+
+       return ret;
+}
+
+static int checkentry(const char *tablename, const struct ip6t_ip6 *ip,
+                      void *matchinfo, unsigned int matchsize,
+                      unsigned int hook_mask)
+{
+       struct ip6t_policy_info *info = matchinfo;
+
+       if (matchsize != IP6T_ALIGN(sizeof(*info))) {
+               printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n",
+                      matchsize, IP6T_ALIGN(sizeof(*info)));
+               return 0;
+       }
+       if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) {
+               printk(KERN_ERR "ip6t_policy: neither incoming nor "
+                               "outgoing policy selected\n");
+               return 0;
+       }
+       if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN)
+           && info->flags & IP6T_POLICY_MATCH_OUT) {
+               printk(KERN_ERR "ip6t_policy: output policy not valid in "
+                               "PRE_ROUTING and INPUT\n");
+               return 0;
+       }
+       if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT)
+           && info->flags & IP6T_POLICY_MATCH_IN) {
+               printk(KERN_ERR "ip6t_policy: input policy not valid in "
+                               "POST_ROUTING and OUTPUT\n");
+               return 0;
+       }
+       if (info->len > IP6T_POLICY_MAX_ELEM) {
+               printk(KERN_ERR "ip6t_policy: too many policy elements\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match policy_match = {
+       .name           = "policy",
+       .match          = match,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       return ip6t_register_match(&policy_match);
+}
+
+static void __exit fini(void)
+{
+       ip6t_unregister_match(&policy_match);
+}
+
+module_init(init);
+module_exit(fini);
index 5d316cb72ec920f10d448eb69f7f31cd9a54bbd1..15e1456b3f18731f8a5bdc35048845b37d549262 100644 (file)
@@ -581,7 +581,6 @@ err:
  *     the last and the first frames arrived and all the bits are here.
  */
 static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
-                         unsigned int *nhoffp,
                          struct net_device *dev)
 {
        struct sk_buff *fp, *head = fq->fragments;
@@ -654,6 +653,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
        head->dev = dev;
        skb_set_timestamp(head, &fq->stamp);
        head->nh.ipv6h->payload_len = htons(payload_len);
+       IP6CB(head)->nhoff = nhoff;
 
        *skb_in = head;
 
@@ -663,7 +663,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 
        IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
        fq->fragments = NULL;
-       *nhoffp = nhoff;
        return 1;
 
 out_oversize:
@@ -678,7 +677,7 @@ out_fail:
        return -1;
 }
 
-static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
+static int ipv6_frag_rcv(struct sk_buff **skbp)
 {
        struct sk_buff *skb = *skbp; 
        struct net_device *dev = skb->dev;
@@ -710,7 +709,7 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
                skb->h.raw += sizeof(struct frag_hdr);
                IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
 
-               *nhoffp = (u8*)fhdr - skb->nh.raw;
+               IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw;
                return 1;
        }
 
@@ -722,11 +721,11 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 
                spin_lock(&fq->lock);
 
-               ip6_frag_queue(fq, skb, fhdr, *nhoffp);
+               ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff);
 
                if (fq->last_in == (FIRST_IN|LAST_IN) &&
                    fq->meat == fq->len)
-                       ret = ip6_frag_reasm(fq, skbp, nhoffp, dev);
+                       ret = ip6_frag_reasm(fq, skbp, dev);
 
                spin_unlock(&fq->lock);
                fq_put(fq, NULL);
index 577d49732b0fdb04e35587028a7a98e7d21716ec..02872ae8a439b0a664e16cf765c2880ff1ad5fbf 100644 (file)
@@ -381,6 +381,7 @@ static int ipip6_rcv(struct sk_buff *skb)
                skb->mac.raw = skb->nh.raw;
                skb->nh.raw = skb->data;
                memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+               IPCB(skb)->flags = 0;
                skb->protocol = htons(ETH_P_IPV6);
                skb->pkt_type = PACKET_HOST;
                tunnel->stat.rx_packets++;
@@ -552,6 +553,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        skb->h.raw = skb->nh.raw;
        skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+       IPCB(skb)->flags = 0;
        dst_release(skb->dst);
        skb->dst = &rt->u.dst;
 
index 2947bc56d8a025948b803fabd088cf220ef01c4a..a25f4e8a8adae03aa9d08afb7d1c33defdc87ba2 100644 (file)
@@ -1153,7 +1153,7 @@ ipv6_pktoptions:
        return 0;
 }
 
-static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+static int tcp_v6_rcv(struct sk_buff **pskb)
 {
        struct sk_buff *skb = *pskb;
        struct tcphdr *th;      
index d8538dcea8130b0209941ec0f5eb1ab795a49cd0..c47648892c04d421a446dc614aa891f46d2baeac 100644 (file)
@@ -435,7 +435,7 @@ out:
        read_unlock(&udp_hash_lock);
 }
 
-static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+static int udpv6_rcv(struct sk_buff **pskb)
 {
        struct sk_buff *skb = *pskb;
        struct sock *sk;
index 28c29d78338e3a84c259264182b6f5d322f71ac9..1ca2da68ef69c35e420c1badf3c84e079bb88aec 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
 #include <net/dsfield.h>
 #include <net/inet_ecn.h>
 #include <net/ip.h>
@@ -26,7 +28,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
                IP6_ECN_set_ce(inner_iph);
 }
 
-int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
+int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi)
 {
        struct sk_buff *skb = *pskb;
        int err;
@@ -38,7 +40,7 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
        int nexthdr;
        unsigned int nhoff;
 
-       nhoff = *nhoffp;
+       nhoff = IP6CB(skb)->nhoff;
        nexthdr = skb->nh.raw[nhoff];
 
        seq = 0;
@@ -121,6 +123,8 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
        skb->sp->len += xfrm_nr;
        skb->ip_summed = CHECKSUM_NONE;
 
+       nf_reset(skb);
+
        if (decaps) {
                if (!(skb->dev->flags&IFF_LOOPBACK)) {
                        dst_release(skb->dst);
@@ -129,7 +133,16 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
                netif_rx(skb);
                return -1;
        } else {
+#ifdef CONFIG_NETFILTER
+               skb->nh.ipv6h->payload_len = htons(skb->len);
+               __skb_push(skb, skb->data - skb->nh.raw);
+
+               NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
+                       ip6_rcv_finish);
+               return -1;
+#else
                return 1;
+#endif
        }
 
 drop_unlock:
@@ -144,7 +157,7 @@ drop:
 
 EXPORT_SYMBOL(xfrm6_rcv_spi);
 
-int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+int xfrm6_rcv(struct sk_buff **pskb)
 {
-       return xfrm6_rcv_spi(pskb, nhoffp, 0);
+       return xfrm6_rcv_spi(pskb, 0);
 }
index 6b9867717d117a6686edb9424ddbfb6e7a21aa05..80242172a5df260815b087bd80f6160c71615119 100644 (file)
@@ -9,9 +9,11 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/compiler.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/icmpv6.h>
+#include <linux/netfilter_ipv6.h>
 #include <net/dsfield.h>
 #include <net/inet_ecn.h>
 #include <net/ipv6.h>
@@ -92,7 +94,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
        return ret;
 }
 
-int xfrm6_output(struct sk_buff *skb)
+static int xfrm6_output_one(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb->dst;
        struct xfrm_state *x = dst->xfrm;
@@ -110,29 +112,35 @@ int xfrm6_output(struct sk_buff *skb)
                        goto error_nolock;
        }
 
-       spin_lock_bh(&x->lock);
-       err = xfrm_state_check(x, skb);
-       if (err)
-               goto error;
+       do {
+               spin_lock_bh(&x->lock);
+               err = xfrm_state_check(x, skb);
+               if (err)
+                       goto error;
 
-       xfrm6_encap(skb);
+               xfrm6_encap(skb);
 
-       err = x->type->output(x, skb);
-       if (err)
-               goto error;
+               err = x->type->output(x, skb);
+               if (err)
+                       goto error;
 
-       x->curlft.bytes += skb->len;
-       x->curlft.packets++;
+               x->curlft.bytes += skb->len;
+               x->curlft.packets++;
 
-       spin_unlock_bh(&x->lock);
+               spin_unlock_bh(&x->lock);
 
-       skb->nh.raw = skb->data;
-       
-       if (!(skb->dst = dst_pop(dst))) {
-               err = -EHOSTUNREACH;
-               goto error_nolock;
-       }
-       err = NET_XMIT_BYPASS;
+               skb->nh.raw = skb->data;
+               
+               if (!(skb->dst = dst_pop(dst))) {
+                       err = -EHOSTUNREACH;
+                       goto error_nolock;
+               }
+               dst = skb->dst;
+               x = dst->xfrm;
+       } while (x && !x->props.mode);
+
+       IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
+       err = 0;
 
 out_exit:
        return err;
@@ -142,3 +150,33 @@ error_nolock:
        kfree_skb(skb);
        goto out_exit;
 }
+
+static int xfrm6_output_finish(struct sk_buff *skb)
+{
+       int err;
+
+       while (likely((err = xfrm6_output_one(skb)) == 0)) {
+               nf_reset(skb);
+       
+               err = nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, &skb, NULL,
+                             skb->dst->dev, dst_output);
+               if (unlikely(err != 1))
+                       break;
+
+               if (!skb->dst->xfrm)
+                       return dst_output(skb);
+
+               err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
+                             skb->dst->dev, xfrm6_output_finish);
+               if (unlikely(err != 1))
+                       break;
+       }
+
+       return err;
+}
+
+int xfrm6_output(struct sk_buff *skb)
+{
+       return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
+                      xfrm6_output_finish);
+}
index fbef7826a74f610556d02b11b9332f11a823b980..da09ff258648e0be62dbf09e953c4b836edb9c1e 100644 (file)
@@ -397,7 +397,7 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
 
 EXPORT_SYMBOL(xfrm6_tunnel_deregister);
 
-static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+static int xfrm6_tunnel_rcv(struct sk_buff **pskb)
 {
        struct sk_buff *skb = *pskb;
        struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
@@ -405,11 +405,11 @@ static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
        u32 spi;
 
        /* device-like_ip6ip6_handler() */
-       if (handler && handler->handler(pskb, nhoffp) == 0)
+       if (handler && handler->handler(pskb) == 0)
                return 0;
 
        spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
-       return xfrm6_rcv_spi(pskb, nhoffp, spi);
+       return xfrm6_rcv_spi(pskb, spi);
 }
 
 static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
index 7849cac14d3a4ab24d8ab03abd8f959fde19a8f8..a67f1b44c9a385e24c1b8c3330e2e869b2e5d55b 100644 (file)
@@ -402,7 +402,7 @@ static int netlink_create(struct socket *sock, int protocol)
        groups = nl_table[protocol].groups;
        netlink_unlock_table();
 
-       if ((err = __netlink_create(sock, protocol) < 0))
+       if ((err = __netlink_create(sock, protocol)) < 0)
                goto out_module;
 
        nlk = nlk_sk(sock->sk);
index 238f1bffa6845e94b3e0bec1f6d5ad0da4c0e695..4aa6fc60357ca10f76bf3c918a76d88fe1ba2b00 100644 (file)
@@ -225,6 +225,7 @@ int sctp_rcv(struct sk_buff *skb)
 
        if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family))
                goto discard_release;
+       nf_reset(skb);
 
        ret = sk_filter(sk, skb, 1);
        if (ret)
index 15c05165c905173b49a3e109f109a96cc5d607a9..04c7fab4edc42b49068513a455ca2c747b174f8e 100644 (file)
@@ -905,7 +905,7 @@ static struct inet_protosw sctpv6_stream_protosw = {
        .flags         = SCTP_PROTOSW_FLAG,
 };
 
-static int sctp6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+static int sctp6_rcv(struct sk_buff **pskb)
 {
        return sctp_rcv(*pskb) ? -1 : 0;
 }
index 24cc23af9b95d7d0ca1950ce7bcaf5ac098bdc6f..e14c1cae74600d5035b571a50414a65f7429ac8a 100644 (file)
@@ -495,7 +495,7 @@ rpc_depopulate(struct dentry *parent)
 repeat:
        spin_lock(&dcache_lock);
        list_for_each_safe(pos, next, &parent->d_subdirs) {
-               dentry = list_entry(pos, struct dentry, d_child);
+               dentry = list_entry(pos, struct dentry, d_u.d_child);
                spin_lock(&dentry->d_lock);
                if (!d_unhashed(dentry)) {
                        dget_locked(dentry);
index 64a447375fdb7a976e4fabe58da292d3c5817d31..59614a994b4e51c7384200134e08bba86190e82d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/workqueue.h>
 #include <linux/notifier.h>
 #include <linux/netdevice.h>
+#include <linux/netfilter.h>
 #include <linux/module.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
@@ -951,8 +952,8 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
        return start;
 }
 
-static int
-_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family)
+int
+xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family)
 {
        struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
 
@@ -963,6 +964,7 @@ _decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family)
        xfrm_policy_put_afinfo(afinfo);
        return 0;
 }
+EXPORT_SYMBOL(xfrm_decode_session);
 
 static inline int secpath_has_tunnel(struct sec_path *sp, int k)
 {
@@ -982,8 +984,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
        u8 fl_dir = policy_to_flow_dir(dir);
        u32 sk_sid;
 
-       if (_decode_session(skb, &fl, family) < 0)
+       if (xfrm_decode_session(skb, &fl, family) < 0)
                return 0;
+       nf_nat_decode_session(skb, &fl, family);
 
        sk_sid = security_sk_sid(sk, &fl, fl_dir);
 
@@ -1055,7 +1058,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
 {
        struct flowi fl;
 
-       if (_decode_session(skb, &fl, family) < 0)
+       if (xfrm_decode_session(skb, &fl, family) < 0)
                return 0;
 
        return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0;
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
new file mode 100644 (file)
index 0000000..75f21d8
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+#
+# Copyright 2004 Matt Mackall <mpm@selenic.com>
+#
+# inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import sys, os, re
+
+if len(sys.argv) != 3:
+    sys.stderr.write("usage: %s file1 file2\n" % sys.argv[0])
+    sys.exit(-1)
+
+def getsizes(file):
+    sym = {}
+    for l in os.popen("nm --size-sort " + file).readlines():
+        size, type, name = l[:-1].split()
+        if type in "tTdDbB":
+            sym[name] = int(size, 16)
+    return sym
+
+old = getsizes(sys.argv[1])
+new = getsizes(sys.argv[2])
+grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
+delta, common = [], {}
+
+for a in old:
+    if a in new:
+        common[a] = 1
+
+for name in old:
+    if name not in common:
+        remove += 1
+        down += old[name]
+        delta.append((-old[name], name))
+
+for name in new:
+    if name not in common:
+        add += 1
+        up += new[name]
+        delta.append((new[name], name))
+
+for name in common:
+        d = new.get(name, 0) - old.get(name, 0)
+        if d>0: grow, up = grow+1, up+d
+        if d<0: shrink, down = shrink+1, down-d
+        delta.append((d, name))
+
+delta.sort()
+delta.reverse()
+
+print "add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
+      (add, remove, grow, shrink, up, -down, up-down)
+print "%-40s %7s %7s %+7s" % ("function", "old", "new", "delta")
+for d, n in delta:
+    if d: print "%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d)
index 8ba5d29d3d42d1221b2fdc1b6e137ca750513da8..10eeae53d827f904a440c812af8febd13c891776 100644 (file)
@@ -63,6 +63,20 @@ static void check_stdin(void)
        }
 }
 
+static char *fgets_check_stream(char *s, int size, FILE *stream)
+{
+       char *ret = fgets(s, size, stream);
+
+       if (ret == NULL && feof(stream)) {
+               printf(_("aborted!\n\n"));
+               printf(_("Console input is closed. "));
+               printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+               exit(1);
+       }
+
+       return ret;
+}
+
 static void conf_askvalue(struct symbol *sym, const char *def)
 {
        enum symbol_type type = sym_get_type(sym);
@@ -100,7 +114,7 @@ static void conf_askvalue(struct symbol *sym, const char *def)
                check_stdin();
        case ask_all:
                fflush(stdout);
-               fgets(line, 128, stdin);
+               fgets_check_stream(line, 128, stdin);
                return;
        case set_default:
                printf("%s\n", def);
@@ -356,7 +370,7 @@ static int conf_choice(struct menu *menu)
                        check_stdin();
                case ask_all:
                        fflush(stdout);
-                       fgets(line, 128, stdin);
+                       fgets_check_stream(line, 128, stdin);
                        strip(line);
                        if (line[0] == '?') {
                                printf("\n%s\n", menu->sym->help ?
index 7c03927d4c7c23d126f510369e8ada72eb6e36a2..e52f3e90bf0cea264738a9ba0d1117bcf4afa724 100644 (file)
@@ -22,8 +22,8 @@ public:
 
 #if QT_VERSION >= 300
        void readListSettings();
-       QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok);
-       bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value);
+       QValueList<int> readSizes(const QString& key, bool *ok);
+       bool writeSizes(const QString& key, const QValueList<int>& value);
 #endif
 
        bool showAll;
@@ -124,7 +124,7 @@ public:
        void setParentMenu(void);
 
        template <class P>
-       void ConfigList::updateMenuList(P*, struct menu*);
+       void updateMenuList(P*, struct menu*);
 
        bool updateAll;
 
index 3303673c636ef3b735ae48fdf2992d0abe24c11a..bcdb285337339d108160e8fb305220088dec9eb5 100644 (file)
@@ -74,6 +74,12 @@ asmlinkage long compat_sys_keyctl(u32 option,
        case KEYCTL_SET_REQKEY_KEYRING:
                return keyctl_set_reqkey_keyring(arg2);
 
+       case KEYCTL_SET_TIMEOUT:
+               return keyctl_set_timeout(arg2, arg3);
+
+       case KEYCTL_ASSUME_AUTHORITY:
+               return keyctl_assume_authority(arg2);
+
        default:
                return -EOPNOTSUPP;
        }
index 39cba97c5eb9f63e88fd2d23efbbca62f72a165d..e066e6057955d54cd99f431876523fc4742b1d58 100644 (file)
@@ -107,12 +107,13 @@ extern struct key *request_key_and_link(struct key_type *type,
 struct request_key_auth {
        struct key              *target_key;
        struct task_struct      *context;
+       const char              *callout_info;
        pid_t                   pid;
 };
 
 extern struct key_type key_type_request_key_auth;
 extern struct key *request_key_auth_new(struct key *target,
-                                       struct key **_rkakey);
+                                       const char *callout_info);
 
 extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
 
@@ -136,6 +137,8 @@ extern long keyctl_instantiate_key(key_serial_t, const void __user *,
                                   size_t, key_serial_t);
 extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t);
 extern long keyctl_set_reqkey_keyring(int);
+extern long keyctl_set_timeout(key_serial_t, unsigned);
+extern long keyctl_assume_authority(key_serial_t);
 
 
 /*
index b7a468fabdf9a22e4ca1eecfc6da96f055512a58..3d2ebae029c1775b49722314b2def71bc4aabe9d 100644 (file)
@@ -834,6 +834,17 @@ long keyctl_instantiate_key(key_serial_t id,
        if (plen > 32767)
                goto error;
 
+       /* the appropriate instantiation authorisation key must have been
+        * assumed before calling this */
+       ret = -EPERM;
+       instkey = current->request_key_auth;
+       if (!instkey)
+               goto error;
+
+       rka = instkey->payload.data;
+       if (rka->target_key->serial != id)
+               goto error;
+
        /* pull the payload in if one was supplied */
        payload = NULL;
 
@@ -848,15 +859,6 @@ long keyctl_instantiate_key(key_serial_t id,
                        goto error2;
        }
 
-       /* find the instantiation authorisation key */
-       instkey = key_get_instantiation_authkey(id);
-       if (IS_ERR(instkey)) {
-               ret = PTR_ERR(instkey);
-               goto error2;
-       }
-
-       rka = instkey->payload.data;
-
        /* find the destination keyring amongst those belonging to the
         * requesting task */
        keyring_ref = NULL;
@@ -865,7 +867,7 @@ long keyctl_instantiate_key(key_serial_t id,
                                              KEY_WRITE);
                if (IS_ERR(keyring_ref)) {
                        ret = PTR_ERR(keyring_ref);
-                       goto error3;
+                       goto error2;
                }
        }
 
@@ -874,11 +876,17 @@ long keyctl_instantiate_key(key_serial_t id,
                                       key_ref_to_ptr(keyring_ref), instkey);
 
        key_ref_put(keyring_ref);
- error3:
-       key_put(instkey);
- error2:
+
+       /* discard the assumed authority if it's just been disabled by
+        * instantiation of the key */
+       if (ret == 0) {
+               key_put(current->request_key_auth);
+               current->request_key_auth = NULL;
+       }
+
+error2:
        kfree(payload);
- error:
+error:
        return ret;
 
 } /* end keyctl_instantiate_key() */
@@ -895,14 +903,16 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
        key_ref_t keyring_ref;
        long ret;
 
-       /* find the instantiation authorisation key */
-       instkey = key_get_instantiation_authkey(id);
-       if (IS_ERR(instkey)) {
-               ret = PTR_ERR(instkey);
+       /* the appropriate instantiation authorisation key must have been
+        * assumed before calling this */
+       ret = -EPERM;
+       instkey = current->request_key_auth;
+       if (!instkey)
                goto error;
-       }
 
        rka = instkey->payload.data;
+       if (rka->target_key->serial != id)
+               goto error;
 
        /* find the destination keyring if present (which must also be
         * writable) */
@@ -911,7 +921,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
                keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
                if (IS_ERR(keyring_ref)) {
                        ret = PTR_ERR(keyring_ref);
-                       goto error2;
+                       goto error;
                }
        }
 
@@ -920,9 +930,15 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
                                  key_ref_to_ptr(keyring_ref), instkey);
 
        key_ref_put(keyring_ref);
- error2:
-       key_put(instkey);
- error:
+
+       /* discard the assumed authority if it's just been disabled by
+        * instantiation of the key */
+       if (ret == 0) {
+               key_put(current->request_key_auth);
+               current->request_key_auth = NULL;
+       }
+
+error:
        return ret;
 
 } /* end keyctl_negate_key() */
@@ -965,6 +981,88 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
 
 } /* end keyctl_set_reqkey_keyring() */
 
+/*****************************************************************************/
+/*
+ * set or clear the timeout for a key
+ */
+long keyctl_set_timeout(key_serial_t id, unsigned timeout)
+{
+       struct timespec now;
+       struct key *key;
+       key_ref_t key_ref;
+       time_t expiry;
+       long ret;
+
+       key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
+               goto error;
+       }
+
+       key = key_ref_to_ptr(key_ref);
+
+       /* make the changes with the locks held to prevent races */
+       down_write(&key->sem);
+
+       expiry = 0;
+       if (timeout > 0) {
+               now = current_kernel_time();
+               expiry = now.tv_sec + timeout;
+       }
+
+       key->expiry = expiry;
+
+       up_write(&key->sem);
+       key_put(key);
+
+       ret = 0;
+error:
+       return ret;
+
+} /* end keyctl_set_timeout() */
+
+/*****************************************************************************/
+/*
+ * assume the authority to instantiate the specified key
+ */
+long keyctl_assume_authority(key_serial_t id)
+{
+       struct key *authkey;
+       long ret;
+
+       /* special key IDs aren't permitted */
+       ret = -EINVAL;
+       if (id < 0)
+               goto error;
+
+       /* we divest ourselves of authority if given an ID of 0 */
+       if (id == 0) {
+               key_put(current->request_key_auth);
+               current->request_key_auth = NULL;
+               ret = 0;
+               goto error;
+       }
+
+       /* attempt to assume the authority temporarily granted to us whilst we
+        * instantiate the specified key
+        * - the authorisation key must be in the current task's keyrings
+        *   somewhere
+        */
+       authkey = key_get_instantiation_authkey(id);
+       if (IS_ERR(authkey)) {
+               ret = PTR_ERR(authkey);
+               goto error;
+       }
+
+       key_put(current->request_key_auth);
+       current->request_key_auth = authkey;
+       ret = authkey->serial;
+
+error:
+       return ret;
+
+} /* end keyctl_assume_authority() */
+
 /*****************************************************************************/
 /*
  * the key control system call
@@ -1038,6 +1136,13 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
        case KEYCTL_SET_REQKEY_KEYRING:
                return keyctl_set_reqkey_keyring(arg2);
 
+       case KEYCTL_SET_TIMEOUT:
+               return keyctl_set_timeout((key_serial_t) arg2,
+                                         (unsigned) arg3);
+
+       case KEYCTL_ASSUME_AUTHORITY:
+               return keyctl_assume_authority((key_serial_t) arg2);
+
        default:
                return -EOPNOTSUPP;
        }
index 5d22c0388b326bcc64fd134d24534e5d97da4d09..d65a180f888d2475aeb444c04d4c1f9b5b42d23b 100644 (file)
@@ -479,51 +479,6 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
 
 } /* end __keyring_search_one() */
 
-/*****************************************************************************/
-/*
- * search for an instantiation authorisation key matching a target key
- * - the RCU read lock must be held by the caller
- * - a target_id of zero specifies any valid token
- */
-struct key *keyring_search_instkey(struct key *keyring,
-                                  key_serial_t target_id)
-{
-       struct request_key_auth *rka;
-       struct keyring_list *klist;
-       struct key *instkey;
-       int loop;
-
-       klist = rcu_dereference(keyring->payload.subscriptions);
-       if (klist) {
-               for (loop = 0; loop < klist->nkeys; loop++) {
-                       instkey = klist->keys[loop];
-
-                       if (instkey->type != &key_type_request_key_auth)
-                               continue;
-
-                       rka = instkey->payload.data;
-                       if (target_id && rka->target_key->serial != target_id)
-                               continue;
-
-                       /* the auth key is revoked during instantiation */
-                       if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags))
-                               goto found;
-
-                       instkey = ERR_PTR(-EKEYREVOKED);
-                       goto error;
-               }
-       }
-
-       instkey = ERR_PTR(-EACCES);
-       goto error;
-
-found:
-       atomic_inc(&instkey->usage);
-error:
-       return instkey;
-
-} /* end keyring_search_instkey() */
-
 /*****************************************************************************/
 /*
  * find a keyring with the specified name
@@ -682,17 +637,33 @@ static void keyring_link_rcu_disposal(struct rcu_head *rcu)
 
 } /* end keyring_link_rcu_disposal() */
 
+/*****************************************************************************/
+/*
+ * dispose of a keyring list after the RCU grace period, freeing the unlinked
+ * key
+ */
+static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
+{
+       struct keyring_list *klist =
+               container_of(rcu, struct keyring_list, rcu);
+
+       key_put(klist->keys[klist->delkey]);
+       kfree(klist);
+
+} /* end keyring_unlink_rcu_disposal() */
+
 /*****************************************************************************/
 /*
  * link a key into to a keyring
  * - must be called with the keyring's semaphore write-locked
+ * - discard already extant link to matching key if there is one
  */
 int __key_link(struct key *keyring, struct key *key)
 {
        struct keyring_list *klist, *nklist;
        unsigned max;
        size_t size;
-       int ret;
+       int loop, ret;
 
        ret = -EKEYREVOKED;
        if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
@@ -714,6 +685,48 @@ int __key_link(struct key *keyring, struct key *key)
                        goto error2;
        }
 
+       /* see if there's a matching key we can displace */
+       klist = keyring->payload.subscriptions;
+
+       if (klist && klist->nkeys > 0) {
+               struct key_type *type = key->type;
+
+               for (loop = klist->nkeys - 1; loop >= 0; loop--) {
+                       if (klist->keys[loop]->type == type &&
+                           strcmp(klist->keys[loop]->description,
+                                  key->description) == 0
+                           ) {
+                               /* found a match - replace with new key */
+                               size = sizeof(struct key *) * klist->maxkeys;
+                               size += sizeof(*klist);
+                               BUG_ON(size > PAGE_SIZE);
+
+                               ret = -ENOMEM;
+                               nklist = kmalloc(size, GFP_KERNEL);
+                               if (!nklist)
+                                       goto error2;
+
+                               memcpy(nklist, klist, size);
+
+                               /* replace matched key */
+                               atomic_inc(&key->usage);
+                               nklist->keys[loop] = key;
+
+                               rcu_assign_pointer(
+                                       keyring->payload.subscriptions,
+                                       nklist);
+
+                               /* dispose of the old keyring list and the
+                                * displaced key */
+                               klist->delkey = loop;
+                               call_rcu(&klist->rcu,
+                                        keyring_unlink_rcu_disposal);
+
+                               goto done;
+                       }
+               }
+       }
+
        /* check that we aren't going to overrun the user's quota */
        ret = key_payload_reserve(keyring,
                                  keyring->datalen + KEYQUOTA_LINK_BYTES);
@@ -730,8 +743,6 @@ int __key_link(struct key *keyring, struct key *key)
                smp_wmb();
                klist->nkeys++;
                smp_wmb();
-
-               ret = 0;
        }
        else {
                /* grow the key list */
@@ -769,16 +780,16 @@ int __key_link(struct key *keyring, struct key *key)
                /* dispose of the old keyring list */
                if (klist)
                        call_rcu(&klist->rcu, keyring_link_rcu_disposal);
-
-               ret = 0;
        }
 
- error2:
+done:
+       ret = 0;
+error2:
        up_write(&keyring_serialise_link_sem);
- error:
+error:
        return ret;
 
- error3:
+error3:
        /* undo the quota changes */
        key_payload_reserve(keyring,
                            keyring->datalen - KEYQUOTA_LINK_BYTES);
@@ -807,21 +818,6 @@ int key_link(struct key *keyring, struct key *key)
 
 EXPORT_SYMBOL(key_link);
 
-/*****************************************************************************/
-/*
- * dispose of a keyring list after the RCU grace period, freeing the unlinked
- * key
- */
-static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
-{
-       struct keyring_list *klist =
-               container_of(rcu, struct keyring_list, rcu);
-
-       key_put(klist->keys[klist->delkey]);
-       kfree(klist);
-
-} /* end keyring_unlink_rcu_disposal() */
-
 /*****************************************************************************/
 /*
  * unlink the first link to a key from a keyring
index e7f579c0eaf541e393df94815eecffc565dcde3d..3b41f9b52537afc86326ebc62a45380d8aefaf69 100644 (file)
@@ -73,3 +73,35 @@ use_these_perms:
 } /* end key_task_permission() */
 
 EXPORT_SYMBOL(key_task_permission);
+
+/*****************************************************************************/
+/*
+ * validate a key
+ */
+int key_validate(struct key *key)
+{
+       struct timespec now;
+       int ret = 0;
+
+       if (key) {
+               /* check it's still accessible */
+               ret = -EKEYREVOKED;
+               if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
+                   test_bit(KEY_FLAG_DEAD, &key->flags))
+                       goto error;
+
+               /* check it hasn't expired */
+               ret = 0;
+               if (key->expiry) {
+                       now = current_kernel_time();
+                       if (now.tv_sec >= key->expiry)
+                               ret = -EKEYEXPIRED;
+               }
+       }
+
+ error:
+       return ret;
+
+} /* end key_validate() */
+
+EXPORT_SYMBOL(key_validate);
index 566b1cc0118afabcfa051a9d1402144eb9ace0b2..74cb79eb917ea40e1d895f00ff486a00ef153e7b 100644 (file)
@@ -270,9 +270,14 @@ int copy_thread_group_keys(struct task_struct *tsk)
 int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
 {
        key_check(tsk->thread_keyring);
+       key_check(tsk->request_key_auth);
 
        /* no thread keyring yet */
        tsk->thread_keyring = NULL;
+
+       /* copy the request_key() authorisation for this thread */
+       key_get(tsk->request_key_auth);
+
        return 0;
 
 } /* end copy_keys() */
@@ -290,11 +295,12 @@ void exit_thread_group_keys(struct signal_struct *tg)
 
 /*****************************************************************************/
 /*
- * dispose of keys upon thread exit
+ * dispose of per-thread keys upon thread exit
  */
 void exit_keys(struct task_struct *tsk)
 {
        key_put(tsk->thread_keyring);
+       key_put(tsk->request_key_auth);
 
 } /* end exit_keys() */
 
@@ -382,7 +388,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
                                  struct task_struct *context)
 {
        struct request_key_auth *rka;
-       key_ref_t key_ref, ret, err, instkey_ref;
+       key_ref_t key_ref, ret, err;
 
        /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
         * searchable, but we failed to find a key or we found a negative key;
@@ -461,30 +467,12 @@ key_ref_t search_process_keyrings(struct key_type *type,
                        err = key_ref;
                        break;
                }
-
-               /* if this process has a session keyring and that has an
-                * instantiation authorisation key in the bottom level, then we
-                * also search the keyrings of the process mentioned there */
-               if (context != current)
-                       goto no_key;
-
-               rcu_read_lock();
-               instkey_ref = __keyring_search_one(
-                       make_key_ref(rcu_dereference(
-                                            context->signal->session_keyring),
-                                    1),
-                       &key_type_request_key_auth, NULL, 0);
-               rcu_read_unlock();
-
-               if (IS_ERR(instkey_ref))
-                       goto no_key;
-
-               rka = key_ref_to_ptr(instkey_ref)->payload.data;
-
-               key_ref = search_process_keyrings(type, description, match,
-                                                 rka->context);
-               key_ref_put(instkey_ref);
-
+       }
+       /* or search the user-session keyring */
+       else {
+               key_ref = keyring_search_aux(
+                       make_key_ref(context->user->session_keyring, 1),
+                       context, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -500,11 +488,21 @@ key_ref_t search_process_keyrings(struct key_type *type,
                        break;
                }
        }
-       /* or search the user-session keyring */
-       else {
-               key_ref = keyring_search_aux(
-                       make_key_ref(context->user->session_keyring, 1),
-                       context, type, description, match);
+
+       /* if this process has an instantiation authorisation key, then we also
+        * search the keyrings of the process mentioned there
+        * - we don't permit access to request_key auth keys via this method
+        */
+       if (context->request_key_auth &&
+           context == current &&
+           type != &key_type_request_key_auth &&
+           key_validate(context->request_key_auth) == 0
+           ) {
+               rka = context->request_key_auth->payload.data;
+
+               key_ref = search_process_keyrings(type, description, match,
+                                                 rka->context);
+
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -521,8 +519,6 @@ key_ref_t search_process_keyrings(struct key_type *type,
                }
        }
 
-
-no_key:
        /* no key - decide on the error we're going to go for */
        key_ref = ret ? ret : err;
 
@@ -628,6 +624,15 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
                key = ERR_PTR(-EINVAL);
                goto error;
 
+       case KEY_SPEC_REQKEY_AUTH_KEY:
+               key = context->request_key_auth;
+               if (!key)
+                       goto error;
+
+               atomic_inc(&key->usage);
+               key_ref = make_key_ref(key, 1);
+               break;
+
        default:
                key_ref = ERR_PTR(-EINVAL);
                if (id < 1)
index 5cc4bba70db61eab5157bb0bb7ffe6b673a11ab3..f030a0ccbb93f9f70f95cc44833dd48dd6b7e469 100644 (file)
@@ -29,28 +29,36 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
 /*****************************************************************************/
 /*
  * request userspace finish the construction of a key
- * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
+ * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
  */
-static int call_request_key(struct key *key,
-                           const char *op,
-                           const char *callout_info)
+static int call_sbin_request_key(struct key *key,
+                                struct key *authkey,
+                                const char *op)
 {
        struct task_struct *tsk = current;
        key_serial_t prkey, sskey;
-       struct key *session_keyring, *rkakey;
-       char *argv[10], *envp[3], uid_str[12], gid_str[12];
+       struct key *keyring;
+       char *argv[9], *envp[3], uid_str[12], gid_str[12];
        char key_str[12], keyring_str[3][12];
+       char desc[20];
        int ret, i;
 
-       kenter("{%d},%s,%s", key->serial, op, callout_info);
+       kenter("{%d},{%d},%s", key->serial, authkey->serial, op);
 
-       /* generate a new session keyring with an auth key in it */
-       session_keyring = request_key_auth_new(key, &rkakey);
-       if (IS_ERR(session_keyring)) {
-               ret = PTR_ERR(session_keyring);
-               goto error;
+       /* allocate a new session keyring */
+       sprintf(desc, "_req.%u", key->serial);
+
+       keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error_alloc;
        }
 
+       /* attach the auth key to the session keyring */
+       ret = __key_link(keyring, authkey);
+       if (ret < 0)
+               goto error_link;
+
        /* record the UID and GID */
        sprintf(uid_str, "%d", current->fsuid);
        sprintf(gid_str, "%d", current->fsgid);
@@ -95,22 +103,19 @@ static int call_request_key(struct key *key,
        argv[i++] = keyring_str[0];
        argv[i++] = keyring_str[1];
        argv[i++] = keyring_str[2];
-       argv[i++] = (char *) callout_info;
        argv[i] = NULL;
 
        /* do it */
-       ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1);
+       ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1);
 
-       /* dispose of the special keys */
-       key_revoke(rkakey);
-       key_put(rkakey);
-       key_put(session_keyring);
+error_link:
+       key_put(keyring);
 
- error:
+error_alloc:
        kleave(" = %d", ret);
        return ret;
 
-} /* end call_request_key() */
+} /* end call_sbin_request_key() */
 
 /*****************************************************************************/
 /*
@@ -122,9 +127,10 @@ static struct key *__request_key_construction(struct key_type *type,
                                              const char *description,
                                              const char *callout_info)
 {
+       request_key_actor_t actor;
        struct key_construction cons;
        struct timespec now;
-       struct key *key;
+       struct key *key, *authkey;
        int ret, negated;
 
        kenter("%s,%s,%s", type->name, description, callout_info);
@@ -143,8 +149,19 @@ static struct key *__request_key_construction(struct key_type *type,
        /* we drop the construction sem here on behalf of the caller */
        up_write(&key_construction_sem);
 
+       /* allocate an authorisation key */
+       authkey = request_key_auth_new(key, callout_info);
+       if (IS_ERR(authkey)) {
+               ret = PTR_ERR(authkey);
+               authkey = NULL;
+               goto alloc_authkey_failed;
+       }
+
        /* make the call */
-       ret = call_request_key(key, "create", callout_info);
+       actor = call_sbin_request_key;
+       if (type->request_key)
+               actor = type->request_key;
+       ret = actor(key, authkey, "create");
        if (ret < 0)
                goto request_failed;
 
@@ -153,22 +170,29 @@ static struct key *__request_key_construction(struct key_type *type,
        if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                goto request_failed;
 
+       key_revoke(authkey);
+       key_put(authkey);
+
        down_write(&key_construction_sem);
        list_del(&cons.link);
        up_write(&key_construction_sem);
 
        /* also give an error if the key was negatively instantiated */
- check_not_negative:
+check_not_negative:
        if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
                key_put(key);
                key = ERR_PTR(-ENOKEY);
        }
 
- out:
+out:
        kleave(" = %p", key);
        return key;
 
- request_failed:
+request_failed:
+       key_revoke(authkey);
+       key_put(authkey);
+
+alloc_authkey_failed:
        /* it wasn't instantiated
         * - remove from construction queue
         * - mark the key as dead
@@ -217,7 +241,7 @@ static struct key *__request_key_construction(struct key_type *type,
        key = ERR_PTR(ret);
        goto out;
 
- alloc_failed:
+alloc_failed:
        up_write(&key_construction_sem);
        goto out;
 
@@ -464,35 +488,3 @@ struct key *request_key(struct key_type *type,
 } /* end request_key() */
 
 EXPORT_SYMBOL(request_key);
-
-/*****************************************************************************/
-/*
- * validate a key
- */
-int key_validate(struct key *key)
-{
-       struct timespec now;
-       int ret = 0;
-
-       if (key) {
-               /* check it's still accessible */
-               ret = -EKEYREVOKED;
-               if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
-                   test_bit(KEY_FLAG_DEAD, &key->flags))
-                       goto error;
-
-               /* check it hasn't expired */
-               ret = 0;
-               if (key->expiry) {
-                       now = current_kernel_time();
-                       if (now.tv_sec >= key->expiry)
-                               ret = -EKEYEXPIRED;
-               }
-       }
-
- error:
-       return ret;
-
-} /* end key_validate() */
-
-EXPORT_SYMBOL(key_validate);
index a8e4069d48cbf93d91b6bcab3ee173549139221c..cce6ba6b032352aa4cd182db51a521242eea814a 100644 (file)
 #include <linux/sched.h>
 #include <linux/err.h>
 #include <linux/seq_file.h>
+#include <asm/uaccess.h>
 #include "internal.h"
 
 static int request_key_auth_instantiate(struct key *, const void *, size_t);
 static void request_key_auth_describe(const struct key *, struct seq_file *);
 static void request_key_auth_destroy(struct key *);
+static long request_key_auth_read(const struct key *, char __user *, size_t);
 
 /*
  * the request-key authorisation key type definition
@@ -30,51 +32,25 @@ struct key_type key_type_request_key_auth = {
        .instantiate    = request_key_auth_instantiate,
        .describe       = request_key_auth_describe,
        .destroy        = request_key_auth_destroy,
+       .read           = request_key_auth_read,
 };
 
 /*****************************************************************************/
 /*
- * instantiate a request-key authorisation record
+ * instantiate a request-key authorisation key
  */
 static int request_key_auth_instantiate(struct key *key,
                                        const void *data,
                                        size_t datalen)
 {
-       struct request_key_auth *rka, *irka;
-       struct key *instkey;
-       int ret;
-
-       ret = -ENOMEM;
-       rka = kmalloc(sizeof(*rka), GFP_KERNEL);
-       if (rka) {
-               /* see if the calling process is already servicing the key
-                * request of another process */
-               instkey = key_get_instantiation_authkey(0);
-               if (!IS_ERR(instkey)) {
-                       /* it is - use that instantiation context here too */
-                       irka = instkey->payload.data;
-                       rka->context = irka->context;
-                       rka->pid = irka->pid;
-                       key_put(instkey);
-               }
-               else {
-                       /* it isn't - use this process as the context */
-                       rka->context = current;
-                       rka->pid = current->pid;
-               }
-
-               rka->target_key = key_get((struct key *) data);
-               key->payload.data = rka;
-               ret = 0;
-       }
-
-       return ret;
+       key->payload.data = (struct request_key_auth *) data;
+       return 0;
 
 } /* end request_key_auth_instantiate() */
 
 /*****************************************************************************/
 /*
- *
+ * reading a request-key authorisation key retrieves the callout information
  */
 static void request_key_auth_describe(const struct key *key,
                                      struct seq_file *m)
@@ -83,10 +59,38 @@ static void request_key_auth_describe(const struct key *key,
 
        seq_puts(m, "key:");
        seq_puts(m, key->description);
-       seq_printf(m, " pid:%d", rka->pid);
+       seq_printf(m, " pid:%d ci:%zu", rka->pid, strlen(rka->callout_info));
 
 } /* end request_key_auth_describe() */
 
+/*****************************************************************************/
+/*
+ * read the callout_info data
+ * - the key's semaphore is read-locked
+ */
+static long request_key_auth_read(const struct key *key,
+                                 char __user *buffer, size_t buflen)
+{
+       struct request_key_auth *rka = key->payload.data;
+       size_t datalen;
+       long ret;
+
+       datalen = strlen(rka->callout_info);
+       ret = datalen;
+
+       /* we can return the data as is */
+       if (buffer && buflen > 0) {
+               if (buflen > datalen)
+                       buflen = datalen;
+
+               if (copy_to_user(buffer, rka->callout_info, buflen) != 0)
+                       ret = -EFAULT;
+       }
+
+       return ret;
+
+} /* end request_key_auth_read() */
+
 /*****************************************************************************/
 /*
  * destroy an instantiation authorisation token key
@@ -104,54 +108,87 @@ static void request_key_auth_destroy(struct key *key)
 
 /*****************************************************************************/
 /*
- * create a session keyring to be for the invokation of /sbin/request-key and
- * stick an authorisation token in it
+ * create an authorisation token for /sbin/request-key or whoever to gain
+ * access to the caller's security data
  */
-struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
+struct key *request_key_auth_new(struct key *target, const char *callout_info)
 {
-       struct key *keyring, *rkakey = NULL;
+       struct request_key_auth *rka, *irka;
+       struct key *authkey = NULL;
        char desc[20];
        int ret;
 
        kenter("%d,", target->serial);
 
-       /* allocate a new session keyring */
-       sprintf(desc, "_req.%u", target->serial);
+       /* allocate a auth record */
+       rka = kmalloc(sizeof(*rka), GFP_KERNEL);
+       if (!rka) {
+               kleave(" = -ENOMEM");
+               return ERR_PTR(-ENOMEM);
+       }
 
-       keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
-       if (IS_ERR(keyring)) {
-               kleave("= %ld", PTR_ERR(keyring));
-               return keyring;
+       /* see if the calling process is already servicing the key request of
+        * another process */
+       if (current->request_key_auth) {
+               /* it is - use that instantiation context here too */
+               irka = current->request_key_auth->payload.data;
+               rka->context = irka->context;
+               rka->pid = irka->pid;
        }
+       else {
+               /* it isn't - use this process as the context */
+               rka->context = current;
+               rka->pid = current->pid;
+       }
+
+       rka->target_key = key_get(target);
+       rka->callout_info = callout_info;
 
        /* allocate the auth key */
        sprintf(desc, "%x", target->serial);
 
-       rkakey = key_alloc(&key_type_request_key_auth, desc,
-                          current->fsuid, current->fsgid,
-                          KEY_POS_VIEW | KEY_USR_VIEW, 1);
-       if (IS_ERR(rkakey)) {
-               key_put(keyring);
-               kleave("= %ld", PTR_ERR(rkakey));
-               return rkakey;
+       authkey = key_alloc(&key_type_request_key_auth, desc,
+                           current->fsuid, current->fsgid,
+                           KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
+                           KEY_USR_VIEW, 1);
+       if (IS_ERR(authkey)) {
+               ret = PTR_ERR(authkey);
+               goto error_alloc;
        }
 
        /* construct and attach to the keyring */
-       ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL);
-       if (ret < 0) {
-               key_revoke(rkakey);
-               key_put(rkakey);
-               key_put(keyring);
-               kleave("= %d", ret);
-               return ERR_PTR(ret);
-       }
+       ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL);
+       if (ret < 0)
+               goto error_inst;
 
-       *_rkakey = rkakey;
-       kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial);
-       return keyring;
+       kleave(" = {%d})", authkey->serial);
+       return authkey;
+
+error_inst:
+       key_revoke(authkey);
+       key_put(authkey);
+error_alloc:
+       key_put(rka->target_key);
+       kfree(rka);
+       kleave("= %d", ret);
+       return ERR_PTR(ret);
 
 } /* end request_key_auth_new() */
 
+/*****************************************************************************/
+/*
+ * see if an authorisation key is associated with a particular key
+ */
+static int key_get_instantiation_authkey_match(const struct key *key,
+                                              const void *_id)
+{
+       struct request_key_auth *rka = key->payload.data;
+       key_serial_t id = (key_serial_t)(unsigned long) _id;
+
+       return rka->target_key->serial == id;
+
+} /* end key_get_instantiation_authkey_match() */
+
 /*****************************************************************************/
 /*
  * get the authorisation key for instantiation of a specific key if attached to
@@ -162,22 +199,27 @@ struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
  */
 struct key *key_get_instantiation_authkey(key_serial_t target_id)
 {
-       struct task_struct *tsk = current;
-       struct key *instkey;
-
-       /* we must have our own personal session keyring */
-       if (!tsk->signal->session_keyring)
-               return ERR_PTR(-EACCES);
-
-       /* and it must contain a suitable request authorisation key
-        * - lock RCU against session keyring changing
-        */
-       rcu_read_lock();
+       struct key *authkey;
+       key_ref_t authkey_ref;
+
+       authkey_ref = search_process_keyrings(
+               &key_type_request_key_auth,
+               (void *) (unsigned long) target_id,
+               key_get_instantiation_authkey_match,
+               current);
+
+       if (IS_ERR(authkey_ref)) {
+               authkey = ERR_PTR(PTR_ERR(authkey_ref));
+               goto error;
+       }
 
-       instkey = keyring_search_instkey(
-               rcu_dereference(tsk->signal->session_keyring), target_id);
+       authkey = key_ref_to_ptr(authkey_ref);
+       if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) {
+               key_put(authkey);
+               authkey = ERR_PTR(-EKEYREVOKED);
+       }
 
-       rcu_read_unlock();
-       return instkey;
+error:
+       return authkey;
 
 } /* end key_get_instantiation_authkey() */
index 3d496eae1b47ee1ce6a5950f2ffe770c495da705..6647204e46366f59917f4779949988e0ad5912c1 100644 (file)
@@ -1663,7 +1663,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
                                                continue;
                                        }
                                        if (devnull) {
-                                               rcuref_inc(&devnull->f_count);
+                                               get_file(devnull);
                                        } else {
                                                devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
                                                if (!devnull) {
index e59da6398d44508ca902c7dad417ddb0cdba888a..b5fa02d17b1eae8ff3a863ec8520fae951b1de12 100644 (file)
@@ -889,7 +889,7 @@ static void sel_remove_bools(struct dentry *de)
        spin_lock(&dcache_lock);
        node = de->d_subdirs.next;
        while (node != &de->d_subdirs) {
-               struct dentry *d = list_entry(node, struct dentry, d_child);
+               struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
                list_del_init(node);
 
                if (d->d_inode) {
index 5b7776504e4cd7d109c55d27db2d2464d791b533..b2af7ca496c1c925aa75c678565aa07b22559461 100644 (file)
@@ -146,7 +146,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_us
        return rc;
 
 out:
-       *ctxp = 0;
+       *ctxp = NULL;
        kfree(ctx);
        return rc;
 }
index 679d0ae97e4fb61893956dda661831a21a1ece53..ed81eec6e732a4d566ae458b4a3c4d4b878b8e93 100644 (file)
@@ -115,18 +115,11 @@ MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS");
 
 #ifdef WF_DEBUG
 
-#if defined(NEW_MACRO_VARARGS) || __GNUC__ >= 3
 #define DPRINT(cond, ...) \
        if ((dev->debug & (cond)) == (cond)) { \
             snd_printk (__VA_ARGS__); \
        }
 #else
-#define DPRINT(cond, args...) \
-       if ((dev->debug & (cond)) == (cond)) { \
-            snd_printk (args); \
-       }
-#endif
-#else
 #define DPRINT(cond, args...)
 #endif /* WF_DEBUG */
 
index cebd881b91ae97ccc552726b8987549538b0c5c8..74f975676ccb22dae8766c00989e34226275bd4f 100644 (file)
@@ -125,6 +125,7 @@ static int awacs_rate_index;
 static int awacs_subframe;
 static struct device_node* awacs_node;
 static struct device_node* i2s_node;
+static struct resource awacs_rsrc[3];
 
 static char awacs_name[64];
 static int awacs_revision;
@@ -667,9 +668,12 @@ static void PMacIrqCleanup(void)
        iounmap(awacs_txdma);
        iounmap(awacs_rxdma);
 
-       release_OF_resource(awacs_node, 0);
-       release_OF_resource(awacs_node, 1);
-       release_OF_resource(awacs_node, 2);
+       release_mem_region(awacs_rsrc[0].start,
+                          awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+       release_mem_region(awacs_rsrc[1].start,
+                          awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+       release_mem_region(awacs_rsrc[2].start,
+                          awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
 
        kfree(awacs_tx_cmd_space);
        kfree(awacs_rx_cmd_space);
@@ -2863,46 +2867,58 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
         * other info if necessary (early AWACS we want to read chip ids)
         */
 
-       if (io->n_addrs < 3 || io->n_intrs < 3) {
+       if (of_get_address(io, 2, NULL, NULL) == NULL || io->n_intrs < 3) {
                /* OK - maybe we need to use the 'awacs' node (on earlier
                 * machines).
-               */
+                */
                if (awacs_node) {
                        io = awacs_node ;
-                       if (io->n_addrs < 3 || io->n_intrs < 3) {
-                               printk("dmasound_pmac: can't use %s"
-                                       " (%d addrs, %d intrs)\n",
-                                io->full_name, io->n_addrs, io->n_intrs);
+                       if (of_get_address(io, 2, NULL, NULL) == NULL ||
+                           io->n_intrs < 3) {
+                               printk("dmasound_pmac: can't use %s\n",
+                                      io->full_name);
                                return -ENODEV;
                        }
-               } else {
-                       printk("dmasound_pmac: can't use %s (%d addrs, %d intrs)\n",
-                             io->full_name, io->n_addrs, io->n_intrs);
-               }
+               } else
+                       printk("dmasound_pmac: can't use %s\n", io->full_name);
        }
 
-       if (!request_OF_resource(io, 0, NULL)) {
+       if (of_address_to_resource(io, 0, &awacs_rsrc[0]) ||
+           request_mem_region(awacs_rsrc[0].start,
+                              awacs_rsrc[0].end - awacs_rsrc[0].start + 1,
+                              " (IO)") == NULL) {
                printk(KERN_ERR "dmasound: can't request IO resource !\n");
                return -ENODEV;
        }
-       if (!request_OF_resource(io, 1, " (tx dma)")) {
-               release_OF_resource(io, 0);
-               printk(KERN_ERR "dmasound: can't request TX DMA resource !\n");
+       if (of_address_to_resource(io, 1, &awacs_rsrc[1]) ||
+           request_mem_region(awacs_rsrc[1].start,
+                              awacs_rsrc[1].end - awacs_rsrc[1].start + 1,
+                              " (tx dma)") == NULL) {
+               release_mem_region(awacs_rsrc[0].start,
+                                  awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+               printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n");
                return -ENODEV;
        }
-
-       if (!request_OF_resource(io, 2, " (rx dma)")) {
-               release_OF_resource(io, 0);
-               release_OF_resource(io, 1);
-               printk(KERN_ERR "dmasound: can't request RX DMA resource !\n");
+       if (of_address_to_resource(io, 2, &awacs_rsrc[2]) ||
+           request_mem_region(awacs_rsrc[2].start,
+                              awacs_rsrc[2].end - awacs_rsrc[2].start + 1,
+                              " (rx dma)") == NULL) {
+               release_mem_region(awacs_rsrc[0].start,
+                                  awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+               release_mem_region(awacs_rsrc[1].start,
+                                  awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+               printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n");
                return -ENODEV;
        }
 
        awacs_beep_dev = input_allocate_device();
        if (!awacs_beep_dev) {
-               release_OF_resource(io, 0);
-               release_OF_resource(io, 1);
-               release_OF_resource(io, 2);
+               release_mem_region(awacs_rsrc[0].start,
+                                  awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+               release_mem_region(awacs_rsrc[1].start,
+                                  awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+               release_mem_region(awacs_rsrc[2].start,
+                                  awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
                printk(KERN_ERR "dmasound: can't allocate input device !\n");
                return -ENOMEM;
        }
@@ -2916,11 +2932,11 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
 
        /* all OF versions I've seen use this value */
        if (i2s_node)
-               i2s = ioremap(io->addrs[0].address, 0x1000);
+               i2s = ioremap(awacs_rsrc[0].start, 0x1000);
        else
-               awacs = ioremap(io->addrs[0].address, 0x1000);
-       awacs_txdma = ioremap(io->addrs[1].address, 0x100);
-       awacs_rxdma = ioremap(io->addrs[2].address, 0x100);
+               awacs = ioremap(awacs_rsrc[0].start, 0x1000);
+       awacs_txdma = ioremap(awacs_rsrc[1].start, 0x100);
+       awacs_rxdma = ioremap(awacs_rsrc[2].start, 0x100);
 
        /* first of all make sure that the chip is powered up....*/
        pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1);
@@ -3083,9 +3099,10 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
                struct device_node* mio;
                macio_base = NULL;
                for (mio = io->parent; mio; mio = mio->parent) {
-                       if (strcmp(mio->name, "mac-io") == 0
-                           && mio->n_addrs > 0) {
-                               macio_base = ioremap(mio->addrs[0].address, 0x40);
+                       if (strcmp(mio->name, "mac-io") == 0) {
+                               struct resource r;
+                               if (of_address_to_resource(mio, 0, &r) == 0)
+                                       macio_base = ioremap(r.start, 0x40);
                                break;
                        }
                }
index b9a640fe48b10c857867a6c86854a78fee0a73fc..4600cd6742ceaca0c397efd42fcc8d9ef01f852b 100644 (file)
@@ -3359,12 +3359,6 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device
                goto out_region2;
        }
 
-       if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
-                       card_names[pci_id->driver_data], card)) {
-               printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
-               goto out_pio;
-       }
-
        if (card->use_mmio) {
                if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
                        if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
@@ -3395,10 +3389,8 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device
        }
 
        /* initialize AC97 codec and register /dev/mixer */
-       if (i810_ac97_init(card) <= 0) {
-               free_irq(card->irq, card);
+       if (i810_ac97_init(card) <= 0)
                goto out_iospace;
-       }
        pci_set_drvdata(pci_dev, card);
 
        if(clocking == 0) {
@@ -3410,7 +3402,6 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device
        if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
                int i;
                printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
-               free_irq(card->irq, card);
                for (i = 0; i < NR_AC97; i++)
                if (card->ac97_codec[i] != NULL) {
                        unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
@@ -3419,6 +3410,13 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device
                goto out_iospace;
        }
 
+       if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
+                       card_names[pci_id->driver_data], card)) {
+               printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
+               goto out_iospace;
+       }
+
+
        card->initializing = 0;
        return 0;
 
index 9b2b00fdc1ae929f1d251749065bb9ae92f49d15..a642e4cfcf45e2188104b0b4488f26c6d6c12e97 100644 (file)
@@ -803,21 +803,17 @@ static int snd_pmac_free(struct snd_pmac *chip)
                iounmap(chip->playback.dma);
        if (chip->capture.dma)
                iounmap(chip->capture.dma);
-#ifndef CONFIG_PPC64
+
        if (chip->node) {
                int i;
-
                for (i = 0; i < 3; i++) {
-                       if (chip->of_requested & (1 << i)) {
-                               if (chip->is_k2)
-                                       release_OF_resource(chip->node->parent,
-                                                           i);
-                               else
-                                       release_OF_resource(chip->node, i);
-                       }
+                       if (chip->requested & (1 << i))
+                               release_mem_region(chip->rsrc[i].start,
+                                                  chip->rsrc[i].end -
+                                                  chip->rsrc[i].start + 1);
                }
        }
-#endif /* CONFIG_PPC64 */
+
        if (chip->pdev)
                pci_dev_put(chip->pdev);
        kfree(chip);
@@ -991,6 +987,11 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
                        chip->can_byte_swap = 0; /* FIXME: check this */
                        chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
                        break;
+               default:
+                       printk(KERN_ERR "snd: Unknown layout ID 0x%x\n",
+                              layout_id);
+                       return -ENODEV;
+
                }
        }
        prop = (unsigned int *)get_property(sound, "device-id", NULL);
@@ -1175,46 +1176,69 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
        }
 
        np = chip->node;
+       chip->requested = 0;
        if (chip->is_k2) {
-               if (np->parent->n_addrs < 2 || np->n_intrs < 3) {
+               static char *rnames[] = {
+                       "Sound Control", "Sound DMA" };
+               if (np->n_intrs < 3) {
                        err = -ENODEV;
                        goto __error;
                }
-               for (i = 0; i < 2; i++) {
-#ifndef CONFIG_PPC64
-                       static char *name[2] = { "- Control", "- DMA" };
-                       if (! request_OF_resource(np->parent, i, name[i])) {
-                               snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+               for (i = 0; i < 2; i ++) {
+                       if (of_address_to_resource(np->parent, i,
+                                                  &chip->rsrc[i])) {
+                               printk(KERN_ERR "snd: can't translate rsrc "
+                                      " %d (%s)\n", i, rnames[i]);
+                               err = -ENODEV;
+                               goto __error;
+                       }
+                       if (request_mem_region(chip->rsrc[i].start,
+                                              chip->rsrc[i].end -
+                                              chip->rsrc[i].start + 1,
+                                              rnames[i]) == NULL) {
+                               printk(KERN_ERR "snd: can't request rsrc "
+                                      " %d (%s: 0x%08lx:%08lx)\n",
+                                      i, rnames[i], chip->rsrc[i].start,
+                                      chip->rsrc[i].end);
                                err = -ENODEV;
                                goto __error;
                        }
-                       chip->of_requested |= (1 << i);
-#endif /* CONFIG_PPC64 */
-                       ctrl_addr = np->parent->addrs[0].address;
-                       txdma_addr = np->parent->addrs[1].address;
-                       rxdma_addr = txdma_addr + 0x100;
+                       chip->requested |= (1 << i);
                }
-
+               ctrl_addr = chip->rsrc[0].start;
+               txdma_addr = chip->rsrc[1].start;
+               rxdma_addr = txdma_addr + 0x100;
        } else {
-               if (np->n_addrs < 3 || np->n_intrs < 3) {
+               static char *rnames[] = {
+                       "Sound Control", "Sound Tx DMA", "Sound Rx DMA" };
+               if (np->n_intrs < 3) {
                        err = -ENODEV;
                        goto __error;
                }
-
-               for (i = 0; i < 3; i++) {
-#ifndef CONFIG_PPC64
-                       static char *name[3] = { "- Control", "- Tx DMA", "- Rx DMA" };
-                       if (! request_OF_resource(np, i, name[i])) {
-                               snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+               for (i = 0; i < 3; i ++) {
+                       if (of_address_to_resource(np->parent, i,
+                                                  &chip->rsrc[i])) {
+                               printk(KERN_ERR "snd: can't translate rsrc "
+                                      " %d (%s)\n", i, rnames[i]);
+                               err = -ENODEV;
+                               goto __error;
+                       }
+                       if (request_mem_region(chip->rsrc[i].start,
+                                              chip->rsrc[i].end -
+                                              chip->rsrc[i].start + 1,
+                                              rnames[i]) == NULL) {
+                               printk(KERN_ERR "snd: can't request rsrc "
+                                      " %d (%s: 0x%08lx:%08lx)\n",
+                                      i, rnames[i], chip->rsrc[i].start,
+                                      chip->rsrc[i].end);
                                err = -ENODEV;
                                goto __error;
                        }
-                       chip->of_requested |= (1 << i);
-#endif /* CONFIG_PPC64 */
-                       ctrl_addr = np->addrs[0].address;
-                       txdma_addr = np->addrs[1].address;
-                       rxdma_addr = np->addrs[2].address;
+                       chip->requested |= (1 << i);
                }
+               ctrl_addr = chip->rsrc[0].start;
+               txdma_addr = chip->rsrc[1].start;
+               rxdma_addr = chip->rsrc[2].start;
        }
 
        chip->awacs = ioremap(ctrl_addr, 0x1000);
@@ -1266,9 +1290,11 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
        } else if (chip->is_pbook_G3) {
                struct device_node* mio;
                for (mio = chip->node->parent; mio; mio = mio->parent) {
-                       if (strcmp(mio->name, "mac-io") == 0
-                           && mio->n_addrs > 0) {
-                               chip->macio_base = ioremap(mio->addrs[0].address, 0x40);
+                       if (strcmp(mio->name, "mac-io") == 0) {
+                               struct resource r;
+                               if (of_address_to_resource(mio, 0, &r) == 0)
+                                       chip->macio_base =
+                                               ioremap(r.start, 0x40);
                                break;
                        }
                }
index 086da7a1890902edded8becc605895baf92562f4..3a9bd4dbb9a6bfc5ec59a62d25d942f96240e35f 100644 (file)
@@ -113,7 +113,8 @@ struct snd_pmac {
        unsigned int initialized : 1;
        unsigned int feature_is_set : 1;
 
-       unsigned int of_requested;
+       unsigned int requested;
+       struct resource rsrc[3];
 
        int num_freqs;
        int *freq_table;