]> Pileus Git - ~andy/linux/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
authorLinus Torvalds <torvalds@g5.osdl.org>
Thu, 29 Jun 2006 18:32:34 +0000 (11:32 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 29 Jun 2006 18:32:34 +0000 (11:32 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (43 commits)
  [POWERPC] Use little-endian bit from firmware ibm,pa-features property
  [POWERPC] Make sure smp_processor_id works very early in boot
  [POWERPC] U4 DART improvements
  [POWERPC] todc: add support for Time-Of-Day-Clock
  [POWERPC] Make lparcfg.c work when both iseries and pseries are selected
  [POWERPC] Fix idr locking in init_new_context
  [POWERPC] mpc7448hpc2 (taiga) board config file
  [POWERPC] Add tsi108 pci and platform device data register function
  [POWERPC] Add general support for mpc7448hpc2 (Taiga) platform
  [POWERPC] Correct the MAX_CONTEXT definition
  powerpc: minor cleanups for mpc86xx
  [POWERPC] Make sure we select CONFIG_NEW_LEDS if ADB_PMU_LED is set
  [POWERPC] Simplify the code defining the 64-bit CPU features
  [POWERPC] powerpc: kconfig warning fix
  [POWERPC] Consolidate some of kernel/misc*.S
  [POWERPC] Remove unused function call_with_mmu_off
  [POWERPC] update asm-powerpc/time.h
  [POWERPC] Clean up it_lp_queue.h
  [POWERPC] Skip the "copy down" of the kernel if it is already at zero.
  [POWERPC] Add the use of the firmware soft-reset-nmi to kdump.
  ...

1007 files changed:
CREDITS
Documentation/DocBook/Makefile
Documentation/DocBook/genericirq.tmpl [new file with mode: 0644]
Documentation/IRQ.txt [new file with mode: 0644]
Documentation/RCU/torture.txt
Documentation/feature-removal-schedule.txt
Documentation/kernel-parameters.txt
Documentation/keys-request-key.txt
Documentation/keys.txt
Documentation/pi-futex.txt [new file with mode: 0644]
Documentation/robust-futexes.txt
Documentation/rt-mutex-design.txt [new file with mode: 0644]
Documentation/rt-mutex.txt [new file with mode: 0644]
Documentation/video4linux/README.pvrusb2 [new file with mode: 0644]
Documentation/watchdog/pcwd-watchdog.txt
Documentation/watchdog/src/watchdog-simple.c [new file with mode: 0644]
Documentation/watchdog/src/watchdog-test.c [new file with mode: 0644]
Documentation/watchdog/watchdog-api.txt
Documentation/watchdog/watchdog.txt
arch/alpha/kernel/irq.c
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/irq_i8259.c
arch/alpha/kernel/irq_pyxis.c
arch/alpha/kernel/irq_srm.c
arch/alpha/kernel/pci.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_eiger.c
arch/alpha/kernel/sys_jensen.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_noritake.c
arch/alpha/kernel/sys_rawhide.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/sys_takara.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/sys_wildfire.c
arch/arm/Kconfig
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/bios32.c
arch/arm/kernel/crunch-bits.S [new file with mode: 0644]
arch/arm/kernel/crunch.c [new file with mode: 0644]
arch/arm/kernel/entry-armv.S
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/Makefile
arch/arm/lib/backtrace.S
arch/arm/lib/clear_user.S
arch/arm/lib/copy_from_user.S
arch/arm/lib/copy_to_user.S
arch/arm/lib/strncpy_from_user.S
arch/arm/lib/strnlen_user.S
arch/arm/lib/uaccess.S
arch/arm/mach-ep93xx/Kconfig
arch/arm/mach-ep93xx/Makefile
arch/arm/mach-ep93xx/edb9315.c [new file with mode: 0644]
arch/arm/mach-ep93xx/gesbc9312.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-ixp23xx/espresso.c
arch/arm/mach-ixp23xx/ixdp2351.c
arch/arm/mach-ixp23xx/roadrunner.c
arch/arm/mach-pxa/irq.c
arch/arm/mach-s3c2410/s3c244x.c
arch/arm/mm/Kconfig
arch/arm/mm/Makefile
arch/arm/mm/init.c
arch/arm/mm/iomap.c [new file with mode: 0644]
arch/arm/mm/ioremap.c
arch/arm/mm/nommu.c [new file with mode: 0644]
arch/arm/mm/proc-arm1020.S
arch/arm/mm/proc-arm1020e.S
arch/arm/mm/proc-arm1022.S
arch/arm/mm/proc-arm1026.S
arch/arm/mm/proc-arm6_7.S
arch/arm/mm/proc-arm720.S
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm922.S
arch/arm/mm/proc-arm925.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-sa110.S
arch/arm/mm/proc-sa1100.S
arch/arm/mm/proc-v6.S
arch/cris/Kconfig
arch/cris/arch-v10/kernel/irq.c
arch/cris/arch-v32/drivers/pci/bios.c
arch/cris/arch-v32/kernel/irq.c
arch/cris/kernel/irq.c
arch/frv/mb93090-mb00/pci-frv.c
arch/i386/Kconfig
arch/i386/kernel/asm-offsets.c
arch/i386/kernel/cpu/amd.c
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/intel_cacheinfo.c
arch/i386/kernel/cpu/proc.c
arch/i386/kernel/cpuid.c
arch/i386/kernel/efi.c
arch/i386/kernel/entry.S
arch/i386/kernel/i8259.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/msr.c
arch/i386/kernel/scx200.c
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/sysenter.c
arch/i386/kernel/topology.c
arch/i386/kernel/vsyscall-sysenter.S
arch/i386/kernel/vsyscall.lds.S
arch/i386/mach-visws/setup.c
arch/i386/mach-visws/visws_apic.c
arch/i386/mach-voyager/setup.c
arch/i386/mach-voyager/voyager_smp.c
arch/i386/mm/init.c
arch/i386/mm/pageattr.c
arch/i386/pci/i386.c
arch/ia64/Kconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/hp/sim/hpsim_irq.c
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/irq_lsapic.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/topology.c
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/irq.c
arch/ia64/sn/kernel/setup.c
arch/ia64/sn/pci/tioca_provider.c
arch/m32r/kernel/irq.c
arch/m32r/kernel/setup.c
arch/m32r/kernel/setup_m32104ut.c
arch/m32r/kernel/setup_m32700ut.c
arch/m32r/kernel/setup_mappi.c
arch/m32r/kernel/setup_mappi2.c
arch/m32r/kernel/setup_mappi3.c
arch/m32r/kernel/setup_oaks32r.c
arch/m32r/kernel/setup_opsput.c
arch/m32r/kernel/setup_usrv.c
arch/m68knommu/Kconfig
arch/m68knommu/Makefile
arch/m68knommu/defconfig
arch/m68knommu/kernel/comempci.c
arch/m68knommu/kernel/vmlinux.lds.S
arch/m68knommu/platform/68328/Makefile
arch/m68knommu/platform/68328/head-rom.S
arch/m68knommu/platform/68328/ints.c
arch/m68knommu/platform/68328/romvec.S [new file with mode: 0644]
arch/m68knommu/platform/68360/config.c
arch/m68knommu/platform/68360/head-ram.S
arch/m68knommu/platform/68360/head-rom.S
arch/m68knommu/platform/68360/ints.c
arch/m68knommu/platform/68EZ328/config.c
arch/m68knommu/platform/68VZ328/config.c
arch/mips/Kconfig
arch/mips/au1000/common/irq.c
arch/mips/au1000/pb1200/irqmap.c
arch/mips/ddb5xxx/ddb5477/irq_5477.c
arch/mips/dec/ioasic-irq.c
arch/mips/dec/kn02-irq.c
arch/mips/gt64120/ev64120/irq.c
arch/mips/ite-boards/generic/irq.c
arch/mips/jazz/irq.c
arch/mips/jmr3927/rbhma3100/irq.c
arch/mips/kernel/i8259.c
arch/mips/kernel/irq-msc01.c
arch/mips/kernel/irq-mv6434x.c
arch/mips/kernel/irq-rm7000.c
arch/mips/kernel/irq-rm9000.c
arch/mips/kernel/irq.c
arch/mips/kernel/irq_cpu.c
arch/mips/kernel/smp.c
arch/mips/kernel/smtc.c
arch/mips/lasat/interrupt.c
arch/mips/mips-boards/atlas/atlas_int.c
arch/mips/momentum/ocelot_c/cpci-irq.c
arch/mips/momentum/ocelot_c/uart-irq.c
arch/mips/pci/pci.c
arch/mips/philips/pnx8550/common/int.c
arch/mips/pmc-sierra/yosemite/ht.c
arch/mips/sgi-ip22/ip22-eisa.c
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/sb1250/irq.c
arch/mips/sni/irq.c
arch/mips/tx4927/common/tx4927_irq.c
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
arch/mips/tx4938/common/irq.c
arch/mips/tx4938/toshiba_rbtx4938/irq.c
arch/mips/vr41xx/common/icu.c
arch/mips/vr41xx/common/irq.c
arch/mips/vr41xx/common/vrc4173.c
arch/mips/vr41xx/nec-cmbvr4133/irq.c
arch/parisc/Kconfig
arch/parisc/kernel/cache.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/firmware.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/module.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/pdc_chassis.c
arch/parisc/kernel/ptrace.c
arch/parisc/kernel/real2.S
arch/parisc/kernel/setup.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/time.c
arch/parisc/kernel/topology.c
arch/parisc/kernel/traps.c
arch/parisc/kernel/unaligned.c
arch/powerpc/Kconfig
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/83xx/pci.c
arch/powerpc/platforms/85xx/pci.c
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/spider-pic.c
arch/powerpc/platforms/cell/spufs/switch.c
arch/powerpc/platforms/chrp/pci.c
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/maple/pci.c
arch/powerpc/platforms/powermac/backlight.c
arch/powerpc/platforms/powermac/pci.c
arch/powerpc/platforms/powermac/pfunc_core.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/pseries/eeh_event.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/sysdev/i8259.c
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/mmio_nvram.c
arch/powerpc/sysdev/mpic.c
arch/ppc/8xx_io/commproc.c
arch/ppc/kernel/pci.c
arch/ppc/kernel/setup.c
arch/ppc/platforms/apus_setup.c
arch/ppc/platforms/sbc82xx.c
arch/ppc/syslib/cpc700_pic.c
arch/ppc/syslib/cpm2_pic.c
arch/ppc/syslib/gt64260_pic.c
arch/ppc/syslib/m82xx_pci.c
arch/ppc/syslib/m8xx_setup.c
arch/ppc/syslib/mpc52xx_pic.c
arch/ppc/syslib/mv64360_pic.c
arch/ppc/syslib/open_pic.c
arch/ppc/syslib/open_pic2.c
arch/ppc/syslib/ppc403_pic.c
arch/ppc/syslib/ppc4xx_pic.c
arch/ppc/syslib/xilinx_pic.c
arch/s390/appldata/appldata.h
arch/s390/appldata/appldata_base.c
arch/s390/appldata/appldata_mem.c
arch/s390/appldata/appldata_net_sum.c
arch/s390/appldata/appldata_os.c
arch/s390/kernel/binfmt_elf32.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/head.S
arch/s390/kernel/head31.S
arch/s390/kernel/head64.S
arch/s390/kernel/s390_ksyms.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/traps.c
arch/sh/boards/adx/irq_maskreg.c
arch/sh/boards/bigsur/irq.c
arch/sh/boards/cqreek/irq.c
arch/sh/boards/dreamcast/setup.c
arch/sh/boards/ec3104/setup.c
arch/sh/boards/harp/irq.c
arch/sh/boards/mpc1211/pci.c
arch/sh/boards/mpc1211/setup.c
arch/sh/boards/overdrive/galileo.c
arch/sh/boards/overdrive/irq.c
arch/sh/boards/renesas/hs7751rvoip/irq.c
arch/sh/boards/renesas/rts7751r2d/irq.c
arch/sh/boards/renesas/systemh/irq.c
arch/sh/boards/se/73180/irq.c
arch/sh/boards/superh/microdev/irq.c
arch/sh/cchips/hd6446x/hd64461/setup.c
arch/sh/cchips/hd6446x/hd64465/setup.c
arch/sh/cchips/voyagergx/irq.c
arch/sh/drivers/pci/pci.c
arch/sh/kernel/cpu/irq/imask.c
arch/sh/kernel/cpu/irq/intc2.c
arch/sh/kernel/cpu/irq/ipr.c
arch/sh/kernel/cpu/irq/pint.c
arch/sh/kernel/irq.c
arch/sh/kernel/setup.c
arch/sh64/kernel/irq.c
arch/sh64/kernel/irq_intc.c
arch/sh64/kernel/pcibios.c
arch/sh64/kernel/setup.c
arch/sh64/mach-cayman/irq.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/setup.c
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/setup.c
arch/sparc64/mm/init.c
arch/um/kernel/irq.c
arch/v850/kernel/irq.c
arch/v850/kernel/rte_mb_a_pci.c
arch/x86_64/Kconfig
arch/x86_64/kernel/entry.S
arch/x86_64/kernel/i8259.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/irq.c
arch/x86_64/kernel/mce.c
arch/x86_64/kernel/nmi.c
arch/x86_64/kernel/smp.c
arch/x86_64/kernel/smpboot.c
arch/x86_64/mm/init.c
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/pci.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/traps.c
block/ll_rw_blk.c
drivers/acpi/Kconfig
drivers/acpi/acpi_memhotplug.c
drivers/acpi/numa.c
drivers/amba/bus.c
drivers/atm/ambassador.c
drivers/atm/firestream.c
drivers/base/cpu.c
drivers/base/dmapool.c
drivers/base/memory.c
drivers/base/node.c
drivers/base/topology.c
drivers/block/loop.c
drivers/block/paride/pf.c
drivers/block/rd.c
drivers/block/sx8.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/agp/sgi-agp.c
drivers/char/applicom.c
drivers/char/drm/drm_memory_debug.h
drivers/char/drm/via_dmablit.c
drivers/char/epca.c
drivers/char/hvcs.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_watchdog.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/n_tty.c
drivers/char/nsc_gpio.c [new file with mode: 0644]
drivers/char/pc8736x_gpio.c [new file with mode: 0644]
drivers/char/pty.c
drivers/char/scx200_gpio.c
drivers/char/specialix.c
drivers/char/stallion.c
drivers/char/sx.c
drivers/char/tty_io.c
drivers/char/vr41xx_giu.c
drivers/char/watchdog/at91_wdt.c
drivers/char/watchdog/i8xx_tco.c
drivers/char/watchdog/pcwd_pci.c
drivers/char/watchdog/pcwd_usb.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/i2c/busses/i2c-i801.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/hpt34x.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/sc1200.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sl82c105.c
drivers/ide/pci/slc90e66.c
drivers/ieee1394/ohci1394.c
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/input/joystick/db9.c
drivers/input/keyboard/atkbd.c
drivers/input/misc/wistron_btns.c
drivers/input/serio/ct82c710.c
drivers/isdn/gigaset/common.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/telespci.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/i4l/isdn_x25iface.c
drivers/leds/led-core.c
drivers/leds/led-triggers.c
drivers/macintosh/macio_asic.c
drivers/md/raid5.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/cx2341x.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/pvrusb2/Kconfig [new file with mode: 0644]
drivers/media/video/pvrusb2/Makefile [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-audio.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-audio.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-context.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-context.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-ctrl.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-ctrl.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-debug.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-debugifc.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-debugifc.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-demod.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-demod.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-eeprom.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-eeprom.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-encoder.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-encoder.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-hdw.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-hdw.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-core.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-io.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-io.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-ioread.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-ioread.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-main.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-std.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-std.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-sysfs.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-sysfs.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-tuner.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-tuner.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-util.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-v4l2.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-v4l2.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-video-v4l.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-wm8775.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-wm8775.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2.h [new file with mode: 0644]
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/stradis.c
drivers/media/video/tda9887.c
drivers/media/video/tuner-core.c
drivers/media/video/v4l2-common.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptsas.c
drivers/message/i2o/iop.c
drivers/misc/ibmasm/module.c
drivers/mmc/mmci.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/jedec.c
drivers/mtd/chips/map_absent.c
drivers/mtd/chips/map_ram.c
drivers/mtd/chips/map_rom.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/ms02-nv.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/pmc551.c
drivers/mtd/devices/slram.c
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/physmap.c
drivers/mtd/maps/scx200_docflash.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/mtdchar.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/ts7250.c
drivers/net/3c59x.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/dl2k.h
drivers/net/dm9000.c
drivers/net/e100.c
drivers/net/eepro100.c
drivers/net/epic100.c
drivers/net/fealnx.c
drivers/net/fec.c
drivers/net/fs_enet/fs_enet-mii.c
drivers/net/hamradio/dmascc.c
drivers/net/natsemi.c
drivers/net/pcnet32.c
drivers/net/phy/lxt.c
drivers/net/skge.c
drivers/net/sky2.c
drivers/net/tulip/de2104x.c
drivers/net/tulip/tulip_core.c
drivers/net/tulip/winbond-840.c
drivers/net/typhoon.c
drivers/net/wan/c101.c
drivers/net/wan/dscc4.c
drivers/net/wan/n2.c
drivers/net/wan/pc300_drv.c
drivers/net/wan/pci200syn.c
drivers/net/wireless/ipw2200.c
drivers/net/yellowfin.c
drivers/parisc/Kconfig
drivers/parisc/dino.c
drivers/parisc/eisa.c
drivers/parisc/gsc.c
drivers/parisc/iosapic.c
drivers/parisc/pdc_stable.c
drivers/parisc/sba_iommu.c
drivers/parisc/superio.c
drivers/pci/bus.c
drivers/pci/hotplug/cpcihp_zt5550.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/shpchp_sysfs.c
drivers/pci/msi.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/proc.c
drivers/pci/rom.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pcmcia/hd64465_ss.c
drivers/pcmcia/i82365.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/tcic.c
drivers/pnp/interface.c
drivers/pnp/manager.c
drivers/pnp/resource.c
drivers/rapidio/rio-access.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-rs5c348.c [new file with mode: 0644]
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-vr41xx.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3370_erp.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_9336_erp.c
drivers/s390/block/dasd_9343_erp.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_diag.h
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_fba.h
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/char/raw3270.c
drivers/s390/cio/blacklist.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/s390mach.c
drivers/scsi/Kconfig
drivers/scsi/ahci.c
drivers/scsi/ata_piix.c
drivers/scsi/libata-core.c
drivers/scsi/libata-eh.c
drivers/scsi/libata-scsi.c
drivers/scsi/libata.h
drivers/scsi/sata_nv.c
drivers/scsi/sata_sil.c
drivers/scsi/sata_sil24.c
drivers/scsi/sata_svw.c
drivers/scsi/sata_uli.c
drivers/scsi/sata_via.c
drivers/scsi/sata_vsc.c
drivers/serial/68328serial.c
drivers/serial/8250_pci.c
drivers/serial/crisv10.c
drivers/serial/jsm/jsm_tty.c
drivers/sn/ioc3.c
drivers/sn/ioc4.c
drivers/spi/spi.c
drivers/usb/host/sl811-hcd.c
drivers/usb/serial/ir-usb.c
drivers/video/aty/radeon_backlight.c
drivers/video/au1100fb.c
drivers/video/backlight/hp680_bl.c
drivers/video/console/vgacon.c
drivers/video/sgivwfb.c
fs/9p/mux.c
fs/9p/v9fs_vfs.h
fs/9p/vfs_addr.c
fs/9p/vfs_inode.c
fs/Kconfig
fs/adfs/inode.c
fs/affs/affs.h
fs/affs/file.c
fs/affs/symlink.c
fs/afs/file.c
fs/afs/internal.h
fs/befs/linuxvfs.c
fs/bfs/bfs.h
fs/bfs/file.c
fs/block_dev.c
fs/buffer.c
fs/cifs/CHANGES
fs/cifs/Makefile
fs/cifs/README
fs/cifs/asn1.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_debug.h
fs/cifs/cifs_unicode.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/fcntl.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/ntlmssp.c [deleted file]
fs/cifs/readdir.c
fs/cifs/sess.c [new file with mode: 0644]
fs/cifs/smbencrypt.c
fs/cifs/transport.c
fs/coda/symlink.c
fs/configfs/inode.c
fs/cramfs/inode.c
fs/efs/inode.c
fs/efs/symlink.c
fs/ext2/ext2.h
fs/ext2/inode.c
fs/ext3/inode.c
fs/fat/inode.c
fs/freevxfs/vxfs_immed.c
fs/freevxfs/vxfs_inode.c
fs/freevxfs/vxfs_subr.c
fs/fuse/file.c
fs/hfs/hfs_fs.h
fs/hfs/inode.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hpfs/namei.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/isofs/compress.c
fs/isofs/inode.c
fs/isofs/isofs.h
fs/isofs/rock.c
fs/isofs/zisofs.h
fs/jbd/journal.c
fs/jffs/inode-v23.c
fs/jffs2/acl.c
fs/jffs2/erase.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/jffs2_fs_sb.h
fs/jffs2/malloc.c
fs/jffs2/nodelist.c
fs/jffs2/nodemgmt.c
fs/jffs2/os-linux.h
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/summary.c
fs/jffs2/xattr.c
fs/jffs2/xattr.h
fs/jfs/inode.c
fs/jfs/jfs_inode.h
fs/jfs/jfs_metapage.c
fs/jfs/jfs_metapage.h
fs/minix/inode.c
fs/ncpfs/inode.c
fs/ncpfs/symlink.c
fs/nfs/file.c
fs/nfsd/nfs4state.c
fs/ntfs/aops.c
fs/ntfs/ntfs.h
fs/ocfs2/aops.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmlock.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlmglue.c
fs/ocfs2/inode.h
fs/ocfs2/journal.c
fs/ocfs2/vote.c
fs/proc/task_mmu.c
fs/qnx4/inode.c
fs/ramfs/file-mmu.c
fs/ramfs/file-nommu.c
fs/ramfs/internal.h
fs/reiserfs/inode.c
fs/romfs/inode.c
fs/smbfs/file.c
fs/smbfs/proto.h
fs/sysfs/inode.c
fs/sysv/itree.c
fs/sysv/sysv.h
fs/udf/file.c
fs/udf/inode.c
fs/udf/symlink.c
fs/udf/udfdecl.h
fs/ufs/inode.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_aops.h
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_vnode.h
fs/xfs/xfs_behavior.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_vnodeops.c
include/asm-alpha/core_t2.h
include/asm-alpha/hw_irq.h
include/asm-arm/arch-at91rm9200/memory.h
include/asm-arm/arch-h720x/memory.h
include/asm-arm/arch-imx/memory.h
include/asm-arm/arch-ixp23xx/ixp23xx.h
include/asm-arm/arch-ixp23xx/platform.h
include/asm-arm/arch-ixp23xx/uncompress.h
include/asm-arm/arch-s3c2410/regs-dsc.h
include/asm-arm/arch-s3c2410/regs-nand.h
include/asm-arm/bugs.h
include/asm-arm/domain.h
include/asm-arm/fpstate.h
include/asm-arm/mach/map.h
include/asm-arm/mach/pci.h
include/asm-arm/memory.h
include/asm-arm/mmu.h
include/asm-arm/mmu_context.h
include/asm-arm/page-nommu.h [new file with mode: 0644]
include/asm-arm/page.h
include/asm-arm/pgalloc.h
include/asm-arm/pgtable-nommu.h [new file with mode: 0644]
include/asm-arm/pgtable.h
include/asm-arm/proc-fns.h
include/asm-arm/ptrace.h
include/asm-arm/thread_info.h
include/asm-arm/uaccess.h
include/asm-arm/ucontext.h
include/asm-cris/hw_irq.h
include/asm-cris/irq.h
include/asm-generic/bug.h
include/asm-generic/vmlinux.lds.h
include/asm-i386/cpu.h
include/asm-i386/elf.h
include/asm-i386/fixmap.h
include/asm-i386/hw_irq.h
include/asm-i386/mach-visws/setup_arch.h
include/asm-i386/mmu.h
include/asm-i386/node.h [deleted file]
include/asm-i386/page.h
include/asm-i386/processor.h
include/asm-i386/thread_info.h
include/asm-i386/topology.h
include/asm-i386/unwind.h
include/asm-ia64/hw_irq.h
include/asm-ia64/irq.h
include/asm-ia64/nodedata.h
include/asm-ia64/sn/sn_sal.h
include/asm-ia64/topology.h
include/asm-m32r/hw_irq.h
include/asm-m68knommu/bootstd.h
include/asm-m68knommu/ptrace.h
include/asm-mips/hw_irq.h
include/asm-mips/mach-mips/irq.h
include/asm-parisc/assembly.h
include/asm-parisc/compat.h
include/asm-parisc/hw_irq.h
include/asm-parisc/irq.h
include/asm-parisc/pdc.h
include/asm-parisc/pgtable.h
include/asm-parisc/processor.h
include/asm-parisc/system.h
include/asm-parisc/uaccess.h
include/asm-parisc/unistd.h
include/asm-powerpc/hw_irq.h
include/asm-powerpc/irq.h
include/asm-powerpc/pci.h
include/asm-powerpc/topology.h
include/asm-ppc/pci.h
include/asm-s390/bitops.h
include/asm-s390/cio.h
include/asm-s390/cmb.h
include/asm-s390/dasd.h
include/asm-s390/thread_info.h
include/asm-s390/unistd.h
include/asm-sh/hw_irq.h
include/asm-sh64/hw_irq.h
include/asm-sparc64/topology.h
include/asm-um/hw_irq.h
include/asm-v850/hw_irq.h
include/asm-x86_64/hw_irq.h
include/asm-x86_64/topology.h
include/asm-xtensa/hw_irq.h
include/linux/ac97_codec.h
include/linux/acpi.h
include/linux/buffer_head.h
include/linux/coda_linux.h
include/linux/cpu.h
include/linux/dmaengine.h
include/linux/efs_fs.h
include/linux/fs.h
include/linux/futex.h
include/linux/ide.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/ioport.h
include/linux/ipmi.h
include/linux/irq.h
include/linux/isdn/tpam.h [deleted file]
include/linux/jffs2.h
include/linux/kbd_kern.h
include/linux/key.h
include/linux/libata.h
include/linux/list.h
include/linux/memory_hotplug.h
include/linux/mm.h
include/linux/module.h
include/linux/nfs_fs.h
include/linux/node.h
include/linux/nsc_gpio.h [new file with mode: 0644]
include/linux/pci.h
include/linux/pci_ids.h
include/linux/plist.h [new file with mode: 0644]
include/linux/pnp.h
include/linux/poison.h [new file with mode: 0644]
include/linux/rcupdate.h
include/linux/reiserfs_fs.h
include/linux/rtmutex.h [new file with mode: 0644]
include/linux/sched.h
include/linux/scx200.h
include/linux/scx200_gpio.h
include/linux/spi/spi.h
include/linux/swap.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/topology.h
include/linux/tty.h
include/linux/tty_flip.h
include/linux/types.h
include/linux/ufs_fs.h
include/linux/watchdog.h
include/media/cx2341x.h
init/Kconfig
init/main.c
kernel/Makefile
kernel/acct.c
kernel/audit.c
kernel/auditsc.c
kernel/cpu.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/futex_compat.c
kernel/hrtimer.c
kernel/irq/Makefile
kernel/irq/autoprobe.c
kernel/irq/chip.c [new file with mode: 0644]
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/manage.c
kernel/irq/migration.c
kernel/irq/proc.c
kernel/irq/resend.c [new file with mode: 0644]
kernel/irq/spurious.c
kernel/module.c
kernel/mutex-debug.c
kernel/power/Kconfig
kernel/profile.c
kernel/rcupdate.c
kernel/rcutorture.c
kernel/resource.c
kernel/rtmutex-debug.c [new file with mode: 0644]
kernel/rtmutex-debug.h [new file with mode: 0644]
kernel/rtmutex-tester.c [new file with mode: 0644]
kernel/rtmutex.c [new file with mode: 0644]
kernel/rtmutex.h [new file with mode: 0644]
kernel/rtmutex_common.h [new file with mode: 0644]
kernel/sched.c
kernel/softirq.c
kernel/softlockup.c
kernel/sysctl.c
kernel/timer.c
kernel/workqueue.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/plist.c [new file with mode: 0644]
lib/vsprintf.c
lib/zlib_inflate/inffast.c
lib/zlib_inflate/inftrees.c
mm/Kconfig
mm/filemap.c
mm/filemap.h
mm/filemap_xip.c
mm/memory_hotplug.c
mm/page-writeback.c
mm/page_alloc.c
mm/shmem.c
mm/slab.c
mm/sparse.c
mm/swap_state.c
mm/vmscan.c
net/bluetooth/rfcomm/tty.c
net/ipv6/route.c
net/sunrpc/auth_gss/gss_krb5_seal.c
net/tipc/bcast.c
net/tipc/bearer.c
net/tipc/config.c
net/tipc/dbg.c
net/tipc/handler.c
net/tipc/name_table.c
net/tipc/net.c
net/tipc/node.c
net/tipc/port.c
net/tipc/ref.c
net/tipc/subscr.c
net/tipc/user_reg.c
scripts/rt-tester/check-all.sh [new file with mode: 0644]
scripts/rt-tester/rt-tester.py [new file with mode: 0644]
scripts/rt-tester/t2-l1-2rt-sameprio.tst [new file with mode: 0644]
scripts/rt-tester/t2-l1-pi.tst [new file with mode: 0644]
scripts/rt-tester/t2-l1-signal.tst [new file with mode: 0644]
scripts/rt-tester/t2-l2-2rt-deadlock.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-1rt.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-2rt.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-3rt.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-signal.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-steal.tst [new file with mode: 0644]
scripts/rt-tester/t3-l2-pi.tst [new file with mode: 0644]
scripts/rt-tester/t4-l2-pi-deboost.tst [new file with mode: 0644]
scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst [new file with mode: 0644]
scripts/rt-tester/t5-l4-pi-boost-deboost.tst [new file with mode: 0644]
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/request_key.c
security/selinux/hooks.c
sound/arm/aaci.c
sound/drivers/mpu401/mpu401.c
sound/isa/es18xx.c
sound/isa/gus/interwave.c
sound/isa/sb/sb16.c
sound/oss/Kconfig
sound/oss/cs4232.c
sound/oss/forte.c
sound/oss/via82cxxx_audio.c
sound/pci/bt87x.c
sound/pci/sonicvibes.c
sound/ppc/pmac.c
sound/ppc/toonie.c [deleted file]
sound/sparc/cs4231.c
sound/sparc/dbri.c

diff --git a/CREDITS b/CREDITS
index 85c7c70b7044bb9e098e6d87949709033ebdc3d5..66b9e7a9abff509fef1d8e7c9425fe0dfbb06ece 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -3401,10 +3401,10 @@ S: Czech Republic
 
 N: Thibaut Varene
 E: T-Bone@parisc-linux.org
-W: http://www.parisc-linux.org/
+W: http://www.parisc-linux.org/~varenet/
 P: 1024D/B7D2F063 E67C 0D43 A75E 12A5 BB1C  FA2F 1E32 C3DA B7D2 F063
 D: PA-RISC port minion, PDC and GSCPS2 drivers, debuglocks and other bits
-D: Some bits in an ARM port, S1D13XXX FB driver, random patches here and there
+D: Some ARM at91rm9200 bits, S1D13XXX FB driver, random patches here and there
 D: AD1889 sound driver
 S: Paris, France
 
index 5a2882d275ba5b3beabb305c62a22f38aa5cff44..66e1cf733571ccc4122dcc745bf9c713ee6559b6 100644 (file)
@@ -10,7 +10,8 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
            kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
            procfs-guide.xml writing_usb_driver.xml \
            kernel-api.xml journal-api.xml lsm.xml usb.xml \
-           gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml
+           gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
+           genericirq.xml
 
 ###
 # The build process is as follows (targets):
diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl
new file mode 100644 (file)
index 0000000..0f4a4b6
--- /dev/null
@@ -0,0 +1,474 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="Generic-IRQ-Guide">
+ <bookinfo>
+  <title>Linux generic IRQ handling</title>
+
+  <authorgroup>
+   <author>
+    <firstname>Thomas</firstname>
+    <surname>Gleixner</surname>
+    <affiliation>
+     <address>
+      <email>tglx@linutronix.de</email>
+     </address>
+    </affiliation>
+   </author>
+   <author>
+    <firstname>Ingo</firstname>
+    <surname>Molnar</surname>
+    <affiliation>
+     <address>
+      <email>mingo@elte.hu</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2005-2006</year>
+   <holder>Thomas Gleixner</holder>
+  </copyright>
+  <copyright>
+   <year>2005-2006</year>
+   <holder>Ingo Molnar</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+
+   <para>
+     This program is distributed in the hope that it will be
+     useful, but WITHOUT ANY WARRANTY; without even the implied
+     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+     See the GNU General Public License for more details.
+   </para>
+
+   <para>
+     You should have received a copy of the GNU General Public
+     License along with this program; if not, write to the Free
+     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="intro">
+    <title>Introduction</title>
+    <para>
+       The generic interrupt handling layer is designed to provide a
+       complete abstraction of interrupt handling for device drivers.
+       It is able to handle all the different types of interrupt controller
+       hardware. Device drivers use generic API functions to request, enable,
+       disable and free interrupts. The drivers do not have to know anything
+       about interrupt hardware details, so they can be used on different
+       platforms without code changes.
+    </para>
+    <para>
+       This documentation is provided to developers who want to implement
+       an interrupt subsystem based for their architecture, with the help
+       of the generic IRQ handling layer.
+    </para>
+  </chapter>
+
+  <chapter id="rationale">
+    <title>Rationale</title>
+       <para>
+       The original implementation of interrupt handling in Linux is using
+       the __do_IRQ() super-handler, which is able to deal with every
+       type of interrupt logic.
+       </para>
+       <para>
+       Originally, Russell King identified different types of handlers to
+       build a quite universal set for the ARM interrupt handler
+       implementation in Linux 2.5/2.6. He distinguished between:
+       <itemizedlist>
+         <listitem><para>Level type</para></listitem>
+         <listitem><para>Edge type</para></listitem>
+         <listitem><para>Simple type</para></listitem>
+       </itemizedlist>
+       In the SMP world of the __do_IRQ() super-handler another type
+       was identified:
+       <itemizedlist>
+         <listitem><para>Per CPU type</para></listitem>
+       </itemizedlist>
+       </para>
+       <para>
+       This split implementation of highlevel IRQ handlers allows us to
+       optimize the flow of the interrupt handling for each specific
+       interrupt type. This reduces complexity in that particular codepath
+       and allows the optimized handling of a given type.
+       </para>
+       <para>
+       The original general IRQ implementation used hw_interrupt_type
+       structures and their ->ack(), ->end() [etc.] callbacks to
+       differentiate the flow control in the super-handler. This leads to
+       a mix of flow logic and lowlevel hardware logic, and it also leads
+       to unnecessary code duplication: for example in i386, there is a
+       ioapic_level_irq and a ioapic_edge_irq irq-type which share many
+       of the lowlevel details but have different flow handling.
+       </para>
+       <para>
+       A more natural abstraction is the clean separation of the
+       'irq flow' and the 'chip details'.
+       </para>
+       <para>
+       Analysing a couple of architecture's IRQ subsystem implementations
+       reveals that most of them can use a generic set of 'irq flow'
+       methods and only need to add the chip level specific code.
+       The separation is also valuable for (sub)architectures
+       which need specific quirks in the irq flow itself but not in the
+       chip-details - and thus provides a more transparent IRQ subsystem
+       design.
+       </para>
+       <para>
+       Each interrupt descriptor is assigned its own highlevel flow
+       handler, which is normally one of the generic
+       implementations. (This highlevel flow handler implementation also
+       makes it simple to provide demultiplexing handlers which can be
+       found in embedded platforms on various architectures.)
+       </para>
+       <para>
+       The separation makes the generic interrupt handling layer more
+       flexible and extensible. For example, an (sub)architecture can
+       use a generic irq-flow implementation for 'level type' interrupts
+       and add a (sub)architecture specific 'edge type' implementation.
+       </para>
+       <para>
+       To make the transition to the new model easier and prevent the
+       breakage of existing implementations, the __do_IRQ() super-handler
+       is still available. This leads to a kind of duality for the time
+       being. Over time the new model should be used in more and more
+       architectures, as it enables smaller and cleaner IRQ subsystems.
+       </para>
+  </chapter>
+  <chapter id="bugs">
+    <title>Known Bugs And Assumptions</title>
+    <para>
+       None (knock on wood).
+    </para>
+  </chapter>
+
+  <chapter id="Abstraction">
+    <title>Abstraction layers</title>
+    <para>
+       There are three main levels of abstraction in the interrupt code:
+       <orderedlist>
+         <listitem><para>Highlevel driver API</para></listitem>
+         <listitem><para>Highlevel IRQ flow handlers</para></listitem>
+         <listitem><para>Chiplevel hardware encapsulation</para></listitem>
+       </orderedlist>
+    </para>
+    <sect1>
+       <title>Interrupt control flow</title>
+       <para>
+       Each interrupt is described by an interrupt descriptor structure
+       irq_desc. The interrupt is referenced by an 'unsigned int' numeric
+       value which selects the corresponding interrupt decription structure
+       in the descriptor structures array.
+       The descriptor structure contains status information and pointers
+       to the interrupt flow method and the interrupt chip structure
+       which are assigned to this interrupt.
+       </para>
+       <para>
+       Whenever an interrupt triggers, the lowlevel arch code calls into
+       the generic interrupt code by calling desc->handle_irq().
+       This highlevel IRQ handling function only uses desc->chip primitives
+       referenced by the assigned chip descriptor structure.
+       </para>
+    </sect1>
+    <sect1>
+       <title>Highlevel Driver API</title>
+       <para>
+         The highlevel Driver API consists of following functions:
+         <itemizedlist>
+         <listitem><para>request_irq()</para></listitem>
+         <listitem><para>free_irq()</para></listitem>
+         <listitem><para>disable_irq()</para></listitem>
+         <listitem><para>enable_irq()</para></listitem>
+         <listitem><para>disable_irq_nosync() (SMP only)</para></listitem>
+         <listitem><para>synchronize_irq() (SMP only)</para></listitem>
+         <listitem><para>set_irq_type()</para></listitem>
+         <listitem><para>set_irq_wake()</para></listitem>
+         <listitem><para>set_irq_data()</para></listitem>
+         <listitem><para>set_irq_chip()</para></listitem>
+         <listitem><para>set_irq_chip_data()</para></listitem>
+          </itemizedlist>
+         See the autogenerated function documentation for details.
+       </para>
+    </sect1>
+    <sect1>
+       <title>Highlevel IRQ flow handlers</title>
+       <para>
+         The generic layer provides a set of pre-defined irq-flow methods:
+         <itemizedlist>
+         <listitem><para>handle_level_irq</para></listitem>
+         <listitem><para>handle_edge_irq</para></listitem>
+         <listitem><para>handle_simple_irq</para></listitem>
+         <listitem><para>handle_percpu_irq</para></listitem>
+         </itemizedlist>
+         The interrupt flow handlers (either predefined or architecture
+         specific) are assigned to specific interrupts by the architecture
+         either during bootup or during device initialization.
+       </para>
+       <sect2>
+       <title>Default flow implementations</title>
+           <sect3>
+               <title>Helper functions</title>
+               <para>
+               The helper functions call the chip primitives and
+               are used by the default flow implementations.
+               The following helper functions are implemented (simplified excerpt):
+               <programlisting>
+default_enable(irq)
+{
+       desc->chip->unmask(irq);
+}
+
+default_disable(irq)
+{
+       if (!delay_disable(irq))
+               desc->chip->mask(irq);
+}
+
+default_ack(irq)
+{
+       chip->ack(irq);
+}
+
+default_mask_ack(irq)
+{
+       if (chip->mask_ack) {
+               chip->mask_ack(irq);
+       } else {
+               chip->mask(irq);
+               chip->ack(irq);
+       }
+}
+
+noop(irq)
+{
+}
+
+               </programlisting>
+               </para>
+           </sect3>
+       </sect2>
+       <sect2>
+       <title>Default flow handler implementations</title>
+           <sect3>
+               <title>Default Level IRQ flow handler</title>
+               <para>
+               handle_level_irq provides a generic implementation
+               for level-triggered interrupts.
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+desc->chip->start();
+handle_IRQ_event(desc->action);
+desc->chip->end();
+               </programlisting>
+               </para>
+           </sect3>
+           <sect3>
+               <title>Default Edge IRQ flow handler</title>
+               <para>
+               handle_edge_irq provides a generic implementation
+               for edge-triggered interrupts.
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+if (desc->status &amp; running) {
+       desc->chip->hold();
+       desc->status |= pending | masked;
+       return;
+}
+desc->chip->start();
+desc->status |= running;
+do {
+       if (desc->status &amp; masked)
+               desc->chip->enable();
+       desc-status &amp;= ~pending;
+       handle_IRQ_event(desc->action);
+} while (status &amp; pending);
+desc-status &amp;= ~running;
+desc->chip->end();
+               </programlisting>
+               </para>
+           </sect3>
+           <sect3>
+               <title>Default simple IRQ flow handler</title>
+               <para>
+               handle_simple_irq provides a generic implementation
+               for simple interrupts.
+               </para>
+               <para>
+               Note: The simple flow handler does not call any
+               handler/chip primitives.
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+handle_IRQ_event(desc->action);
+               </programlisting>
+               </para>
+           </sect3>
+           <sect3>
+               <title>Default per CPU flow handler</title>
+               <para>
+               handle_percpu_irq provides a generic implementation
+               for per CPU interrupts.
+               </para>
+               <para>
+               Per CPU interrupts are only available on SMP and
+               the handler provides a simplified version without
+               locking.
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+desc->chip->start();
+handle_IRQ_event(desc->action);
+desc->chip->end();
+               </programlisting>
+               </para>
+           </sect3>
+       </sect2>
+       <sect2>
+       <title>Quirks and optimizations</title>
+       <para>
+       The generic functions are intended for 'clean' architectures and chips,
+       which have no platform-specific IRQ handling quirks. If an architecture
+       needs to implement quirks on the 'flow' level then it can do so by
+       overriding the highlevel irq-flow handler.
+       </para>
+       </sect2>
+       <sect2>
+       <title>Delayed interrupt disable</title>
+       <para>
+       This per interrupt selectable feature, which was introduced by Russell
+       King in the ARM interrupt implementation, does not mask an interrupt
+       at the hardware level when disable_irq() is called. The interrupt is
+       kept enabled and is masked in the flow handler when an interrupt event
+       happens. This prevents losing edge interrupts on hardware which does
+       not store an edge interrupt event while the interrupt is disabled at
+       the hardware level. When an interrupt arrives while the IRQ_DISABLED
+       flag is set, then the interrupt is masked at the hardware level and
+       the IRQ_PENDING bit is set. When the interrupt is re-enabled by
+       enable_irq() the pending bit is checked and if it is set, the
+       interrupt is resent either via hardware or by a software resend
+       mechanism. (It's necessary to enable CONFIG_HARDIRQS_SW_RESEND when
+       you want to use the delayed interrupt disable feature and your
+       hardware is not capable of retriggering an interrupt.)
+       The delayed interrupt disable can be runtime enabled, per interrupt,
+       by setting the IRQ_DELAYED_DISABLE flag in the irq_desc status field.
+       </para>
+       </sect2>
+    </sect1>
+    <sect1>
+       <title>Chiplevel hardware encapsulation</title>
+       <para>
+       The chip level hardware descriptor structure irq_chip
+       contains all the direct chip relevant functions, which
+       can be utilized by the irq flow implementations.
+         <itemizedlist>
+         <listitem><para>ack()</para></listitem>
+         <listitem><para>mask_ack() - Optional, recommended for performance</para></listitem>
+         <listitem><para>mask()</para></listitem>
+         <listitem><para>unmask()</para></listitem>
+         <listitem><para>retrigger() - Optional</para></listitem>
+         <listitem><para>set_type() - Optional</para></listitem>
+         <listitem><para>set_wake() - Optional</para></listitem>
+         </itemizedlist>
+       These primitives are strictly intended to mean what they say: ack means
+       ACK, masking means masking of an IRQ line, etc. It is up to the flow
+       handler(s) to use these basic units of lowlevel functionality.
+       </para>
+    </sect1>
+  </chapter>
+
+  <chapter id="doirq">
+     <title>__do_IRQ entry point</title>
+     <para>
+       The original implementation __do_IRQ() is an alternative entry
+       point for all types of interrupts.
+     </para>
+     <para>
+       This handler turned out to be not suitable for all
+       interrupt hardware and was therefore reimplemented with split
+       functionality for egde/level/simple/percpu interrupts. This is not
+       only a functional optimization. It also shortens code paths for
+       interrupts.
+      </para>
+      <para>
+       To make use of the split implementation, replace the call to
+       __do_IRQ by a call to desc->chip->handle_irq() and associate
+        the appropriate handler function to desc->chip->handle_irq().
+       In most cases the generic handler implementations should
+       be sufficient.
+     </para>
+  </chapter>
+
+  <chapter id="locking">
+     <title>Locking on SMP</title>
+     <para>
+       The locking of chip registers is up to the architecture that
+       defines the chip primitives. There is a chip->lock field that can be used
+       for serialization, but the generic layer does not touch it. The per-irq
+       structure is protected via desc->lock, by the generic layer.
+     </para>
+  </chapter>
+  <chapter id="structs">
+     <title>Structures</title>
+     <para>
+     This chapter contains the autogenerated documentation of the structures which are
+     used in the generic IRQ layer.
+     </para>
+!Iinclude/linux/irq.h
+  </chapter>
+
+  <chapter id="pubfunctions">
+     <title>Public Functions Provided</title>
+     <para>
+     This chapter contains the autogenerated documentation of the kernel API functions
+      which are exported.
+     </para>
+!Ekernel/irq/manage.c
+!Ekernel/irq/chip.c
+  </chapter>
+
+  <chapter id="intfunctions">
+     <title>Internal Functions Provided</title>
+     <para>
+     This chapter contains the autogenerated documentation of the internal functions.
+     </para>
+!Ikernel/irq/handle.c
+!Ikernel/irq/chip.c
+  </chapter>
+
+  <chapter id="credits">
+     <title>Credits</title>
+       <para>
+               The following people have contributed to this document:
+               <orderedlist>
+                       <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem>
+                       <listitem><para>Ingo Molnar<email>mingo@elte.hu</email></para></listitem>
+               </orderedlist>
+       </para>
+  </chapter>
+</book>
diff --git a/Documentation/IRQ.txt b/Documentation/IRQ.txt
new file mode 100644 (file)
index 0000000..1011e71
--- /dev/null
@@ -0,0 +1,22 @@
+What is an IRQ?
+
+An IRQ is an interrupt request from a device.
+Currently they can come in over a pin, or over a packet.
+Several devices may be connected to the same pin thus
+sharing an IRQ.
+
+An IRQ number is a kernel identifier used to talk about a hardware
+interrupt source.  Typically this is an index into the global irq_desc
+array, but except for what linux/interrupt.h implements the details
+are architecture specific.
+
+An IRQ number is an enumeration of the possible interrupt sources on a
+machine.  Typically what is enumerated is the number of input pins on
+all of the interrupt controller in the system.  In the case of ISA
+what is enumerated are the 16 input pins on the two i8259 interrupt
+controllers.
+
+Architectures can assign additional meaning to the IRQ numbers, and
+are encouraged to in the case  where there is any manual configuration
+of the hardware involved.  The ISA IRQs are a classic example of
+assigning this kind of additional meaning.
index e4c38152f7f799b94a70493f90dbf36b830e9cde..a4948591607d0e1d7b653ce1f66c08e4831cbad1 100644 (file)
@@ -7,7 +7,7 @@ The CONFIG_RCU_TORTURE_TEST config option is available for all RCU
 implementations.  It creates an rcutorture kernel module that can
 be loaded to run a torture test.  The test periodically outputs
 status messages via printk(), which can be examined via the dmesg
-command (perhaps grepping for "rcutorture").  The test is started
+command (perhaps grepping for "torture").  The test is started
 when the module is loaded, and stops when the module is unloaded.
 
 However, actually setting this config option to "y" results in the system
@@ -35,6 +35,19 @@ stat_interval        The number of seconds between output of torture
                be printed -only- when the module is unloaded, and this
                is the default.
 
+shuffle_interval
+               The number of seconds to keep the test threads affinitied
+               to a particular subset of the CPUs.  Used in conjunction
+               with test_no_idle_hz.
+
+test_no_idle_hz        Whether or not to test the ability of RCU to operate in
+               a kernel that disables the scheduling-clock interrupt to
+               idle CPUs.  Boolean parameter, "1" to test, "0" otherwise.
+
+torture_type   The type of RCU to test: "rcu" for the rcu_read_lock()
+               API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu"
+               for the "srcu_read_lock()" API.
+
 verbose                Enable debug printk()s.  Default is disabled.
 
 
@@ -42,14 +55,14 @@ OUTPUT
 
 The statistics output is as follows:
 
-       rcutorture: --- Start of test: nreaders=16 stat_interval=0 verbose=0
-       rcutorture: rtc: 0000000000000000 ver: 1916 tfle: 0 rta: 1916 rtaf: 0 rtf: 1915
-       rcutorture: Reader Pipe:  1466408 9747 0 0 0 0 0 0 0 0 0
-       rcutorture: Reader Batch:  1464477 11678 0 0 0 0 0 0 0 0
-       rcutorture: Free-Block Circulation:  1915 1915 1915 1915 1915 1915 1915 1915 1915 1915 0
-       rcutorture: --- End of test
+       rcu-torture: --- Start of test: nreaders=16 stat_interval=0 verbose=0
+       rcu-torture: rtc: 0000000000000000 ver: 1916 tfle: 0 rta: 1916 rtaf: 0 rtf: 1915
+       rcu-torture: Reader Pipe:  1466408 9747 0 0 0 0 0 0 0 0 0
+       rcu-torture: Reader Batch:  1464477 11678 0 0 0 0 0 0 0 0
+       rcu-torture: Free-Block Circulation:  1915 1915 1915 1915 1915 1915 1915 1915 1915 1915 0
+       rcu-torture: --- End of test
 
-The command "dmesg | grep rcutorture:" will extract this information on
+The command "dmesg | grep torture:" will extract this information on
 most systems.  On more esoteric configurations, it may be necessary to
 use other commands to access the output of the printk()s used by
 the RCU torture test.  The printk()s use KERN_ALERT, so they should
@@ -115,8 +128,9 @@ The following script may be used to torture RCU:
        modprobe rcutorture
        sleep 100
        rmmod rcutorture
-       dmesg | grep rcutorture:
+       dmesg | grep torture:
 
 The output can be manually inspected for the error flag of "!!!".
 One could of course create a more elaborate script that automatically
-checked for such errors.
+checked for such errors.  The "rmmod" command forces a "SUCCESS" or
+"FAILURE" indication to be printk()ed.
index 027285d0c26c1e4e366237e2893b12c231b37a78..033ac91da07a81f0038b05dd52a4ab029d13f509 100644 (file)
@@ -177,6 +177,16 @@ Who:       Jean Delvare <khali@linux-fr.org>
 
 ---------------------------
 
+What:  Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
+       (temporary transition config option provided until then)
+       The transition config option will also be removed at the same time.
+When:  before 2.6.19
+Why:   Unused symbols are both increasing the size of the kernel binary
+       and are often a sign of "wrong API"
+Who:   Arjan van de Ven <arjan@linux.intel.com>
+
+---------------------------
+
 What:  remove EXPORT_SYMBOL(tasklist_lock)
 When:  August 2006
 Files: kernel/fork.c
index 2e352a605fcfef3a6dcb83d4c875635f9f89a71a..25f8d20dac534f07a0bf285feb35de115e2ac514 100644 (file)
@@ -1669,6 +1669,10 @@ running once the system is up.
        usbhid.mousepoll=
                        [USBHID] The interval which mice are to be polled at.
 
+       vdso=           [IA-32]
+                       vdso=1: enable VDSO (default)
+                       vdso=0: disable VDSO mapping
+
        video=          [FB] Frame buffer configuration
                        See Documentation/fb/modedb.txt.
 
@@ -1685,9 +1689,14 @@ running once the system is up.
                        decrease the size and leave more room for directly
                        mapped kernel RAM.
 
-       vmhalt=         [KNL,S390]
+       vmhalt=         [KNL,S390] Perform z/VM CP command after system halt.
+                       Format: <command>
+
+       vmpanic=        [KNL,S390] Perform z/VM CP command after kernel panic.
+                       Format: <command>
 
-       vmpoff=         [KNL,S390]
+       vmpoff=         [KNL,S390] Perform z/VM CP command after power off.
+                       Format: <command>
 
        waveartist=     [HW,OSS]
                        Format: <io>,<irq>,<dma>,<dma2>
index 22488d7911681e8b40cf43a93439f550fa0f93dc..c1f64fdf84cba2ba6a9f04fc1d5315da7a732ecc 100644 (file)
@@ -3,16 +3,23 @@
                              ===================
 
 The key request service is part of the key retention service (refer to
-Documentation/keys.txt). This document explains more fully how that the
-requesting algorithm works.
+Documentation/keys.txt).  This document explains more fully how the requesting
+algorithm works.
 
 The process starts by either the kernel requesting a service by calling
-request_key():
+request_key*():
 
        struct key *request_key(const struct key_type *type,
                                const char *description,
                                const char *callout_string);
 
+or:
+
+       struct key *request_key_with_auxdata(const struct key_type *type,
+                                            const char *description,
+                                            const char *callout_string,
+                                            void *aux);
+
 Or by userspace invoking the request_key system call:
 
        key_serial_t request_key(const char *type,
@@ -20,16 +27,26 @@ Or by userspace invoking the request_key system call:
                                 const char *callout_info,
                                 key_serial_t dest_keyring);
 
-The main difference between the two access points is that the in-kernel
-interface does not need to link the key to a keyring to prevent it from being
-immediately destroyed. The kernel interface returns a pointer directly to the
-key, and it's up to the caller to destroy the key.
+The main difference between the access points is that the in-kernel interface
+does not need to link the key to a keyring to prevent it from being immediately
+destroyed.  The kernel interface returns a pointer directly to the key, and
+it's up to the caller to destroy the key.
+
+The request_key_with_auxdata() call is like the in-kernel request_key() call,
+except that it permits auxiliary data to be passed to the upcaller (the default
+is NULL).  This is only useful for those key types that define their own upcall
+mechanism rather than using /sbin/request-key.
 
 The userspace interface links the key to a keyring associated with the process
 to prevent the key from going away, and returns the serial number of the key to
 the caller.
 
 
+The following example assumes that the key types involved don't define their
+own upcall mechanisms.  If they do, then those should be substituted for the
+forking and execution of /sbin/request-key.
+
+
 ===========
 THE PROCESS
 ===========
@@ -40,8 +57,8 @@ A request proceeds in the following manner:
      interface].
 
  (2) request_key() searches the process's subscribed keyrings to see if there's
-     a suitable key there. If there is, it returns the key. If there isn't, and
-     callout_info is not set, an error is returned. Otherwise the process
+     a suitable key there.  If there is, it returns the key.  If there isn't,
+     and callout_info is not set, an error is returned.  Otherwise the process
      proceeds to the next step.
 
  (3) request_key() sees that A doesn't have the desired key yet, so it creates
@@ -62,7 +79,7 @@ A request proceeds in the following manner:
      instantiation.
 
  (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
+     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.
 
      This will permit it to then search the keyrings of process A with the
@@ -79,10 +96,11 @@ A request proceeds in the following manner:
 (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 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 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
 /sbin/request-key at the appropriate places because (a) execve will discard two
@@ -118,17 +136,17 @@ A search of any particular keyring proceeds in the following fashion:
 
  (2) It considers all the non-keyring keys within that keyring and, if any key
      matches the criteria specified, calls key_permission(SEARCH) on it to see
-     if the key is allowed to be found. If it is, that key is returned; if
+     if the key is allowed to be found.  If it is, that key is returned; if
      not, the search continues, and the error code is retained if of higher
      priority than the one currently set.
 
  (3) It then considers all the keyring-type keys in the keyring it's currently
-     searching. It calls key_permission(SEARCH) on each keyring, and if this
+     searching.  It calls key_permission(SEARCH) on each keyring, and if this
      grants permission, it recurses, executing steps (2) and (3) on that
      keyring.
 
 The process stops immediately a valid key is found with permission granted to
-use it. Any error from a previous match attempt is discarded and the key is
+use it.  Any error from a previous match attempt is discarded and the key is
 returned.
 
 When search_process_keyrings() is invoked, it performs the following searches
@@ -153,7 +171,7 @@ The moment one succeeds, all pending errors are discarded and the found key is
 returned.
 
 Only if all these fail does the whole thing fail with the highest priority
-error. Note that several errors may have come from LSM.
+error.  Note that several errors may have come from LSM.
 
 The error priority is:
 
index 61c0fad2fe2fa01ca14b14d218b56282940bafa6..e373f02128434277bc53098185b393df0a7c36d5 100644 (file)
@@ -780,6 +780,17 @@ payload contents" for more information.
     See also Documentation/keys-request-key.txt.
 
 
+(*) To search for a key, passing auxiliary data to the upcaller, call:
+
+       struct key *request_key_with_auxdata(const struct key_type *type,
+                                            const char *description,
+                                            const char *callout_string,
+                                            void *aux);
+
+    This is identical to request_key(), except that the auxiliary data is
+    passed to the key_type->request_key() op if it exists.
+
+
 (*) When it is no longer required, the key should be released using:
 
        void key_put(struct key *key);
@@ -1031,6 +1042,24 @@ The structure has a number of fields, some of which are mandatory:
      as might happen when the userspace buffer is accessed.
 
 
+ (*) int (*request_key)(struct key *key, struct key *authkey, const char *op,
+                       void *aux);
+
+     This method is optional.  If provided, request_key() and
+     request_key_with_auxdata() will invoke this function rather than
+     upcalling to /sbin/request-key to operate upon a key of this type.
+
+     The aux parameter is as passed to request_key_with_auxdata() or is NULL
+     otherwise.  Also passed are the key to be operated upon, the
+     authorisation key for this operation and the operation type (currently
+     only "create").
+
+     This function should return only when the upcall is complete.  Upon return
+     the authorisation key will be revoked, and the target key will be
+     negatively instantiated if it is still uninstantiated.  The error will be
+     returned to the caller of request_key*().
+
+
 ============================
 REQUEST-KEY CALLBACK SERVICE
 ============================
diff --git a/Documentation/pi-futex.txt b/Documentation/pi-futex.txt
new file mode 100644 (file)
index 0000000..5d61dac
--- /dev/null
@@ -0,0 +1,121 @@
+Lightweight PI-futexes
+----------------------
+
+We are calling them lightweight for 3 reasons:
+
+ - in the user-space fastpath a PI-enabled futex involves no kernel work
+   (or any other PI complexity) at all. No registration, no extra kernel
+   calls - just pure fast atomic ops in userspace.
+
+ - even in the slowpath, the system call and scheduling pattern is very
+   similar to normal futexes.
+
+ - the in-kernel PI implementation is streamlined around the mutex
+   abstraction, with strict rules that keep the implementation
+   relatively simple: only a single owner may own a lock (i.e. no
+   read-write lock support), only the owner may unlock a lock, no
+   recursive locking, etc.
+
+Priority Inheritance - why?
+---------------------------
+
+The short reply: user-space PI helps achieving/improving determinism for
+user-space applications. In the best-case, it can help achieve
+determinism and well-bound latencies. Even in the worst-case, PI will
+improve the statistical distribution of locking related application
+delays.
+
+The longer reply:
+-----------------
+
+Firstly, sharing locks between multiple tasks is a common programming
+technique that often cannot be replaced with lockless algorithms. As we
+can see it in the kernel [which is a quite complex program in itself],
+lockless structures are rather the exception than the norm - the current
+ratio of lockless vs. locky code for shared data structures is somewhere
+between 1:10 and 1:100. Lockless is hard, and the complexity of lockless
+algorithms often endangers to ability to do robust reviews of said code.
+I.e. critical RT apps often choose lock structures to protect critical
+data structures, instead of lockless algorithms. Furthermore, there are
+cases (like shared hardware, or other resource limits) where lockless
+access is mathematically impossible.
+
+Media players (such as Jack) are an example of reasonable application
+design with multiple tasks (with multiple priority levels) sharing
+short-held locks: for example, a highprio audio playback thread is
+combined with medium-prio construct-audio-data threads and low-prio
+display-colory-stuff threads. Add video and decoding to the mix and
+we've got even more priority levels.
+
+So once we accept that synchronization objects (locks) are an
+unavoidable fact of life, and once we accept that multi-task userspace
+apps have a very fair expectation of being able to use locks, we've got
+to think about how to offer the option of a deterministic locking
+implementation to user-space.
+
+Most of the technical counter-arguments against doing priority
+inheritance only apply to kernel-space locks. But user-space locks are
+different, there we cannot disable interrupts or make the task
+non-preemptible in a critical section, so the 'use spinlocks' argument
+does not apply (user-space spinlocks have the same priority inversion
+problems as other user-space locking constructs). Fact is, pretty much
+the only technique that currently enables good determinism for userspace
+locks (such as futex-based pthread mutexes) is priority inheritance:
+
+Currently (without PI), if a high-prio and a low-prio task shares a lock
+[this is a quite common scenario for most non-trivial RT applications],
+even if all critical sections are coded carefully to be deterministic
+(i.e. all critical sections are short in duration and only execute a
+limited number of instructions), the kernel cannot guarantee any
+deterministic execution of the high-prio task: any medium-priority task
+could preempt the low-prio task while it holds the shared lock and
+executes the critical section, and could delay it indefinitely.
+
+Implementation:
+---------------
+
+As mentioned before, the userspace fastpath of PI-enabled pthread
+mutexes involves no kernel work at all - they behave quite similarly to
+normal futex-based locks: a 0 value means unlocked, and a value==TID
+means locked. (This is the same method as used by list-based robust
+futexes.) Userspace uses atomic ops to lock/unlock these mutexes without
+entering the kernel.
+
+To handle the slowpath, we have added two new futex ops:
+
+  FUTEX_LOCK_PI
+  FUTEX_UNLOCK_PI
+
+If the lock-acquire fastpath fails, [i.e. an atomic transition from 0 to
+TID fails], then FUTEX_LOCK_PI is called. The kernel does all the
+remaining work: if there is no futex-queue attached to the futex address
+yet then the code looks up the task that owns the futex [it has put its
+own TID into the futex value], and attaches a 'PI state' structure to
+the futex-queue. The pi_state includes an rt-mutex, which is a PI-aware,
+kernel-based synchronization object. The 'other' task is made the owner
+of the rt-mutex, and the FUTEX_WAITERS bit is atomically set in the
+futex value. Then this task tries to lock the rt-mutex, on which it
+blocks. Once it returns, it has the mutex acquired, and it sets the
+futex value to its own TID and returns. Userspace has no other work to
+perform - it now owns the lock, and futex value contains
+FUTEX_WAITERS|TID.
+
+If the unlock side fastpath succeeds, [i.e. userspace manages to do a
+TID -> 0 atomic transition of the futex value], then no kernel work is
+triggered.
+
+If the unlock fastpath fails (because the FUTEX_WAITERS bit is set),
+then FUTEX_UNLOCK_PI is called, and the kernel unlocks the futex on the
+behalf of userspace - and it also unlocks the attached
+pi_state->rt_mutex and thus wakes up any potential waiters.
+
+Note that under this approach, contrary to previous PI-futex approaches,
+there is no prior 'registration' of a PI-futex. [which is not quite
+possible anyway, due to existing ABI properties of pthread mutexes.]
+
+Also, under this scheme, 'robustness' and 'PI' are two orthogonal
+properties of futexes, and all four combinations are possible: futex,
+robust-futex, PI-futex, robust+PI-futex.
+
+More details about priority inheritance can be found in
+Documentation/rtmutex.txt.
index df82d75245a01b5055c6793fa822efe949982a2e..76e8064b8c3a5ccb60e6cbb2f55ad5d455d097b0 100644 (file)
@@ -95,7 +95,7 @@ comparison. If the thread has registered a list, then normally the list
 is empty. If the thread/process crashed or terminated in some incorrect
 way then the list might be non-empty: in this case the kernel carefully
 walks the list [not trusting it], and marks all locks that are owned by
-this thread with the FUTEX_OWNER_DEAD bit, and wakes up one waiter (if
+this thread with the FUTEX_OWNER_DIED bit, and wakes up one waiter (if
 any).
 
 The list is guaranteed to be private and per-thread at do_exit() time,
diff --git a/Documentation/rt-mutex-design.txt b/Documentation/rt-mutex-design.txt
new file mode 100644 (file)
index 0000000..c472ffa
--- /dev/null
@@ -0,0 +1,781 @@
+#
+# Copyright (c) 2006 Steven Rostedt
+# Licensed under the GNU Free Documentation License, Version 1.2
+#
+
+RT-mutex implementation design
+------------------------------
+
+This document tries to describe the design of the rtmutex.c implementation.
+It doesn't describe the reasons why rtmutex.c exists. For that please see
+Documentation/rt-mutex.txt.  Although this document does explain problems
+that happen without this code, but that is in the concept to understand
+what the code actually is doing.
+
+The goal of this document is to help others understand the priority
+inheritance (PI) algorithm that is used, as well as reasons for the
+decisions that were made to implement PI in the manner that was done.
+
+
+Unbounded Priority Inversion
+----------------------------
+
+Priority inversion is when a lower priority process executes while a higher
+priority process wants to run.  This happens for several reasons, and
+most of the time it can't be helped.  Anytime a high priority process wants
+to use a resource that a lower priority process has (a mutex for example),
+the high priority process must wait until the lower priority process is done
+with the resource.  This is a priority inversion.  What we want to prevent
+is something called unbounded priority inversion.  That is when the high
+priority process is prevented from running by a lower priority process for
+an undetermined amount of time.
+
+The classic example of unbounded priority inversion is were you have three
+processes, let's call them processes A, B, and C, where A is the highest
+priority process, C is the lowest, and B is in between. A tries to grab a lock
+that C owns and must wait and lets C run to release the lock. But in the
+meantime, B executes, and since B is of a higher priority than C, it preempts C,
+but by doing so, it is in fact preempting A which is a higher priority process.
+Now there's no way of knowing how long A will be sleeping waiting for C
+to release the lock, because for all we know, B is a CPU hog and will
+never give C a chance to release the lock.  This is called unbounded priority
+inversion.
+
+Here's a little ASCII art to show the problem.
+
+   grab lock L1 (owned by C)
+     |
+A ---+
+        C preempted by B
+          |
+C    +----+
+
+B         +-------->
+                B now keeps A from running.
+
+
+Priority Inheritance (PI)
+-------------------------
+
+There are several ways to solve this issue, but other ways are out of scope
+for this document.  Here we only discuss PI.
+
+PI is where a process inherits the priority of another process if the other
+process blocks on a lock owned by the current process.  To make this easier
+to understand, let's use the previous example, with processes A, B, and C again.
+
+This time, when A blocks on the lock owned by C, C would inherit the priority
+of A.  So now if B becomes runnable, it would not preempt C, since C now has
+the high priority of A.  As soon as C releases the lock, it loses its
+inherited priority, and A then can continue with the resource that C had.
+
+Terminology
+-----------
+
+Here I explain some terminology that is used in this document to help describe
+the design that is used to implement PI.
+
+PI chain - The PI chain is an ordered series of locks and processes that cause
+           processes to inherit priorities from a previous process that is
+           blocked on one of its locks.  This is described in more detail
+           later in this document.
+
+mutex    - In this document, to differentiate from locks that implement
+           PI and spin locks that are used in the PI code, from now on
+           the PI locks will be called a mutex.
+
+lock     - In this document from now on, I will use the term lock when
+           referring to spin locks that are used to protect parts of the PI
+           algorithm.  These locks disable preemption for UP (when
+           CONFIG_PREEMPT is enabled) and on SMP prevents multiple CPUs from
+           entering critical sections simultaneously.
+
+spin lock - Same as lock above.
+
+waiter   - A waiter is a struct that is stored on the stack of a blocked
+           process.  Since the scope of the waiter is within the code for
+           a process being blocked on the mutex, it is fine to allocate
+           the waiter on the process's stack (local variable).  This
+           structure holds a pointer to the task, as well as the mutex that
+           the task is blocked on.  It also has the plist node structures to
+           place the task in the waiter_list of a mutex as well as the
+           pi_list of a mutex owner task (described below).
+
+           waiter is sometimes used in reference to the task that is waiting
+           on a mutex. This is the same as waiter->task.
+
+waiters  - A list of processes that are blocked on a mutex.
+
+top waiter - The highest priority process waiting on a specific mutex.
+
+top pi waiter - The highest priority process waiting on one of the mutexes
+                that a specific process owns.
+
+Note:  task and process are used interchangeably in this document, mostly to
+       differentiate between two processes that are being described together.
+
+
+PI chain
+--------
+
+The PI chain is a list of processes and mutexes that may cause priority
+inheritance to take place.  Multiple chains may converge, but a chain
+would never diverge, since a process can't be blocked on more than one
+mutex at a time.
+
+Example:
+
+   Process:  A, B, C, D, E
+   Mutexes:  L1, L2, L3, L4
+
+   A owns: L1
+           B blocked on L1
+           B owns L2
+                  C blocked on L2
+                  C owns L3
+                         D blocked on L3
+                         D owns L4
+                                E blocked on L4
+
+The chain would be:
+
+   E->L4->D->L3->C->L2->B->L1->A
+
+To show where two chains merge, we could add another process F and
+another mutex L5 where B owns L5 and F is blocked on mutex L5.
+
+The chain for F would be:
+
+   F->L5->B->L1->A
+
+Since a process may own more than one mutex, but never be blocked on more than
+one, the chains merge.
+
+Here we show both chains:
+
+   E->L4->D->L3->C->L2-+
+                       |
+                       +->B->L1->A
+                       |
+                 F->L5-+
+
+For PI to work, the processes at the right end of these chains (or we may
+also call it the Top of the chain) must be equal to or higher in priority
+than the processes to the left or below in the chain.
+
+Also since a mutex may have more than one process blocked on it, we can
+have multiple chains merge at mutexes.  If we add another process G that is
+blocked on mutex L2:
+
+  G->L2->B->L1->A
+
+And once again, to show how this can grow I will show the merging chains
+again.
+
+   E->L4->D->L3->C-+
+                   +->L2-+
+                   |     |
+                 G-+     +->B->L1->A
+                         |
+                   F->L5-+
+
+
+Plist
+-----
+
+Before I go further and talk about how the PI chain is stored through lists
+on both mutexes and processes, I'll explain the plist.  This is similar to
+the struct list_head functionality that is already in the kernel.
+The implementation of plist is out of scope for this document, but it is
+very important to understand what it does.
+
+There are a few differences between plist and list, the most important one
+being that plist is a priority sorted linked list.  This means that the
+priorities of the plist are sorted, such that it takes O(1) to retrieve the
+highest priority item in the list.  Obviously this is useful to store processes
+based on their priorities.
+
+Another difference, which is important for implementation, is that, unlike
+list, the head of the list is a different element than the nodes of a list.
+So the head of the list is declared as struct plist_head and nodes that will
+be added to the list are declared as struct plist_node.
+
+
+Mutex Waiter List
+-----------------
+
+Every mutex keeps track of all the waiters that are blocked on itself. The mutex
+has a plist to store these waiters by priority.  This list is protected by
+a spin lock that is located in the struct of the mutex. This lock is called
+wait_lock.  Since the modification of the waiter list is never done in
+interrupt context, the wait_lock can be taken without disabling interrupts.
+
+
+Task PI List
+------------
+
+To keep track of the PI chains, each process has its own PI list.  This is
+a list of all top waiters of the mutexes that are owned by the process.
+Note that this list only holds the top waiters and not all waiters that are
+blocked on mutexes owned by the process.
+
+The top of the task's PI list is always the highest priority task that
+is waiting on a mutex that is owned by the task.  So if the task has
+inherited a priority, it will always be the priority of the task that is
+at the top of this list.
+
+This list is stored in the task structure of a process as a plist called
+pi_list.  This list is protected by a spin lock also in the task structure,
+called pi_lock.  This lock may also be taken in interrupt context, so when
+locking the pi_lock, interrupts must be disabled.
+
+
+Depth of the PI Chain
+---------------------
+
+The maximum depth of the PI chain is not dynamic, and could actually be
+defined.  But is very complex to figure it out, since it depends on all
+the nesting of mutexes.  Let's look at the example where we have 3 mutexes,
+L1, L2, and L3, and four separate functions func1, func2, func3 and func4.
+The following shows a locking order of L1->L2->L3, but may not actually
+be directly nested that way.
+
+void func1(void)
+{
+       mutex_lock(L1);
+
+       /* do anything */
+
+       mutex_unlock(L1);
+}
+
+void func2(void)
+{
+       mutex_lock(L1);
+       mutex_lock(L2);
+
+       /* do something */
+
+       mutex_unlock(L2);
+       mutex_unlock(L1);
+}
+
+void func3(void)
+{
+       mutex_lock(L2);
+       mutex_lock(L3);
+
+       /* do something else */
+
+       mutex_unlock(L3);
+       mutex_unlock(L2);
+}
+
+void func4(void)
+{
+       mutex_lock(L3);
+
+       /* do something again */
+
+       mutex_unlock(L3);
+}
+
+Now we add 4 processes that run each of these functions separately.
+Processes A, B, C, and D which run functions func1, func2, func3 and func4
+respectively, and such that D runs first and A last.  With D being preempted
+in func4 in the "do something again" area, we have a locking that follows:
+
+D owns L3
+       C blocked on L3
+       C owns L2
+              B blocked on L2
+              B owns L1
+                     A blocked on L1
+
+And thus we have the chain A->L1->B->L2->C->L3->D.
+
+This gives us a PI depth of 4 (four processes), but looking at any of the
+functions individually, it seems as though they only have at most a locking
+depth of two.  So, although the locking depth is defined at compile time,
+it still is very difficult to find the possibilities of that depth.
+
+Now since mutexes can be defined by user-land applications, we don't want a DOS
+type of application that nests large amounts of mutexes to create a large
+PI chain, and have the code holding spin locks while looking at a large
+amount of data.  So to prevent this, the implementation not only implements
+a maximum lock depth, but also only holds at most two different locks at a
+time, as it walks the PI chain.  More about this below.
+
+
+Mutex owner and flags
+---------------------
+
+The mutex structure contains a pointer to the owner of the mutex.  If the
+mutex is not owned, this owner is set to NULL.  Since all architectures
+have the task structure on at least a four byte alignment (and if this is
+not true, the rtmutex.c code will be broken!), this allows for the two
+least significant bits to be used as flags.  This part is also described
+in Documentation/rt-mutex.txt, but will also be briefly described here.
+
+Bit 0 is used as the "Pending Owner" flag.  This is described later.
+Bit 1 is used as the "Has Waiters" flags.  This is also described later
+  in more detail, but is set whenever there are waiters on a mutex.
+
+
+cmpxchg Tricks
+--------------
+
+Some architectures implement an atomic cmpxchg (Compare and Exchange).  This
+is used (when applicable) to keep the fast path of grabbing and releasing
+mutexes short.
+
+cmpxchg is basically the following function performed atomically:
+
+unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
+{
+        unsigned long T = *A;
+        if (*A == *B) {
+                *A = *C;
+        }
+        return T;
+}
+#define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
+
+This is really nice to have, since it allows you to only update a variable
+if the variable is what you expect it to be.  You know if it succeeded if
+the return value (the old value of A) is equal to B.
+
+The macro rt_mutex_cmpxchg is used to try to lock and unlock mutexes. If
+the architecture does not support CMPXCHG, then this macro is simply set
+to fail every time.  But if CMPXCHG is supported, then this will
+help out extremely to keep the fast path short.
+
+The use of rt_mutex_cmpxchg with the flags in the owner field help optimize
+the system for architectures that support it.  This will also be explained
+later in this document.
+
+
+Priority adjustments
+--------------------
+
+The implementation of the PI code in rtmutex.c has several places that a
+process must adjust its priority.  With the help of the pi_list of a
+process this is rather easy to know what needs to be adjusted.
+
+The functions implementing the task adjustments are rt_mutex_adjust_prio,
+__rt_mutex_adjust_prio (same as the former, but expects the task pi_lock
+to already be taken), rt_mutex_get_prio, and rt_mutex_setprio.
+
+rt_mutex_getprio and rt_mutex_setprio are only used in __rt_mutex_adjust_prio.
+
+rt_mutex_getprio returns the priority that the task should have.  Either the
+task's own normal priority, or if a process of a higher priority is waiting on
+a mutex owned by the task, then that higher priority should be returned.
+Since the pi_list of a task holds an order by priority list of all the top
+waiters of all the mutexes that the task owns, rt_mutex_getprio simply needs
+to compare the top pi waiter to its own normal priority, and return the higher
+priority back.
+
+(Note:  if looking at the code, you will notice that the lower number of
+        prio is returned.  This is because the prio field in the task structure
+        is an inverse order of the actual priority.  So a "prio" of 5 is
+        of higher priority than a "prio" of 10.)
+
+__rt_mutex_adjust_prio examines the result of rt_mutex_getprio, and if the
+result does not equal the task's current priority, then rt_mutex_setprio
+is called to adjust the priority of the task to the new priority.
+Note that rt_mutex_setprio is defined in kernel/sched.c to implement the
+actual change in priority.
+
+It is interesting to note that __rt_mutex_adjust_prio can either increase
+or decrease the priority of the task.  In the case that a higher priority
+process has just blocked on a mutex owned by the task, __rt_mutex_adjust_prio
+would increase/boost the task's priority.  But if a higher priority task
+were for some reason to leave the mutex (timeout or signal), this same function
+would decrease/unboost the priority of the task.  That is because the pi_list
+always contains the highest priority task that is waiting on a mutex owned
+by the task, so we only need to compare the priority of that top pi waiter
+to the normal priority of the given task.
+
+
+High level overview of the PI chain walk
+----------------------------------------
+
+The PI chain walk is implemented by the function rt_mutex_adjust_prio_chain.
+
+The implementation has gone through several iterations, and has ended up
+with what we believe is the best.  It walks the PI chain by only grabbing
+at most two locks at a time, and is very efficient.
+
+The rt_mutex_adjust_prio_chain can be used either to boost or lower process
+priorities.
+
+rt_mutex_adjust_prio_chain is called with a task to be checked for PI
+(de)boosting (the owner of a mutex that a process is blocking on), a flag to
+check for deadlocking, the mutex that the task owns, and a pointer to a waiter
+that is the process's waiter struct that is blocked on the mutex (although this
+parameter may be NULL for deboosting).
+
+For this explanation, I will not mention deadlock detection. This explanation
+will try to stay at a high level.
+
+When this function is called, there are no locks held.  That also means
+that the state of the owner and lock can change when entered into this function.
+
+Before this function is called, the task has already had rt_mutex_adjust_prio
+performed on it.  This means that the task is set to the priority that it
+should be at, but the plist nodes of the task's waiter have not been updated
+with the new priorities, and that this task may not be in the proper locations
+in the pi_lists and wait_lists that the task is blocked on.  This function
+solves all that.
+
+A loop is entered, where task is the owner to be checked for PI changes that
+was passed by parameter (for the first iteration).  The pi_lock of this task is
+taken to prevent any more changes to the pi_list of the task.  This also
+prevents new tasks from completing the blocking on a mutex that is owned by this
+task.
+
+If the task is not blocked on a mutex then the loop is exited.  We are at
+the top of the PI chain.
+
+A check is now done to see if the original waiter (the process that is blocked
+on the current mutex) is the top pi waiter of the task.  That is, is this
+waiter on the top of the task's pi_list.  If it is not, it either means that
+there is another process higher in priority that is blocked on one of the
+mutexes that the task owns, or that the waiter has just woken up via a signal
+or timeout and has left the PI chain.  In either case, the loop is exited, since
+we don't need to do any more changes to the priority of the current task, or any
+task that owns a mutex that this current task is waiting on.  A priority chain
+walk is only needed when a new top pi waiter is made to a task.
+
+The next check sees if the task's waiter plist node has the priority equal to
+the priority the task is set at.  If they are equal, then we are done with
+the loop.  Remember that the function started with the priority of the
+task adjusted, but the plist nodes that hold the task in other processes
+pi_lists have not been adjusted.
+
+Next, we look at the mutex that the task is blocked on. The mutex's wait_lock
+is taken.  This is done by a spin_trylock, because the locking order of the
+pi_lock and wait_lock goes in the opposite direction. If we fail to grab the
+lock, the pi_lock is released, and we restart the loop.
+
+Now that we have both the pi_lock of the task as well as the wait_lock of
+the mutex the task is blocked on, we update the task's waiter's plist node
+that is located on the mutex's wait_list.
+
+Now we release the pi_lock of the task.
+
+Next the owner of the mutex has its pi_lock taken, so we can update the
+task's entry in the owner's pi_list.  If the task is the highest priority
+process on the mutex's wait_list, then we remove the previous top waiter
+from the owner's pi_list, and replace it with the task.
+
+Note: It is possible that the task was the current top waiter on the mutex,
+      in which case the task is not yet on the pi_list of the waiter.  This
+      is OK, since plist_del does nothing if the plist node is not on any
+      list.
+
+If the task was not the top waiter of the mutex, but it was before we
+did the priority updates, that means we are deboosting/lowering the
+task.  In this case, the task is removed from the pi_list of the owner,
+and the new top waiter is added.
+
+Lastly, we unlock both the pi_lock of the task, as well as the mutex's
+wait_lock, and continue the loop again.  On the next iteration of the
+loop, the previous owner of the mutex will be the task that will be
+processed.
+
+Note: One might think that the owner of this mutex might have changed
+      since we just grab the mutex's wait_lock. And one could be right.
+      The important thing to remember is that the owner could not have
+      become the task that is being processed in the PI chain, since
+      we have taken that task's pi_lock at the beginning of the loop.
+      So as long as there is an owner of this mutex that is not the same
+      process as the tasked being worked on, we are OK.
+
+      Looking closely at the code, one might be confused.  The check for the
+      end of the PI chain is when the task isn't blocked on anything or the
+      task's waiter structure "task" element is NULL.  This check is
+      protected only by the task's pi_lock.  But the code to unlock the mutex
+      sets the task's waiter structure "task" element to NULL with only
+      the protection of the mutex's wait_lock, which was not taken yet.
+      Isn't this a race condition if the task becomes the new owner?
+
+      The answer is No!  The trick is the spin_trylock of the mutex's
+      wait_lock.  If we fail that lock, we release the pi_lock of the
+      task and continue the loop, doing the end of PI chain check again.
+
+      In the code to release the lock, the wait_lock of the mutex is held
+      the entire time, and it is not let go when we grab the pi_lock of the
+      new owner of the mutex.  So if the switch of a new owner were to happen
+      after the check for end of the PI chain and the grabbing of the
+      wait_lock, the unlocking code would spin on the new owner's pi_lock
+      but never give up the wait_lock.  So the PI chain loop is guaranteed to
+      fail the spin_trylock on the wait_lock, release the pi_lock, and
+      try again.
+
+      If you don't quite understand the above, that's OK. You don't have to,
+      unless you really want to make a proof out of it ;)
+
+
+Pending Owners and Lock stealing
+--------------------------------
+
+One of the flags in the owner field of the mutex structure is "Pending Owner".
+What this means is that an owner was chosen by the process releasing the
+mutex, but that owner has yet to wake up and actually take the mutex.
+
+Why is this important?  Why can't we just give the mutex to another process
+and be done with it?
+
+The PI code is to help with real-time processes, and to let the highest
+priority process run as long as possible with little latencies and delays.
+If a high priority process owns a mutex that a lower priority process is
+blocked on, when the mutex is released it would be given to the lower priority
+process.  What if the higher priority process wants to take that mutex again.
+The high priority process would fail to take that mutex that it just gave up
+and it would need to boost the lower priority process to run with full
+latency of that critical section (since the low priority process just entered
+it).
+
+There's no reason a high priority process that gives up a mutex should be
+penalized if it tries to take that mutex again.  If the new owner of the
+mutex has not woken up yet, there's no reason that the higher priority process
+could not take that mutex away.
+
+To solve this, we introduced Pending Ownership and Lock Stealing.  When a
+new process is given a mutex that it was blocked on, it is only given
+pending ownership.  This means that it's the new owner, unless a higher
+priority process comes in and tries to grab that mutex.  If a higher priority
+process does come along and wants that mutex, we let the higher priority
+process "steal" the mutex from the pending owner (only if it is still pending)
+and continue with the mutex.
+
+
+Taking of a mutex (The walk through)
+------------------------------------
+
+OK, now let's take a look at the detailed walk through of what happens when
+taking a mutex.
+
+The first thing that is tried is the fast taking of the mutex.  This is
+done when we have CMPXCHG enabled (otherwise the fast taking automatically
+fails).  Only when the owner field of the mutex is NULL can the lock be
+taken with the CMPXCHG and nothing else needs to be done.
+
+If there is contention on the lock, whether it is owned or pending owner
+we go about the slow path (rt_mutex_slowlock).
+
+The slow path function is where the task's waiter structure is created on
+the stack.  This is because the waiter structure is only needed for the
+scope of this function.  The waiter structure holds the nodes to store
+the task on the wait_list of the mutex, and if need be, the pi_list of
+the owner.
+
+The wait_lock of the mutex is taken since the slow path of unlocking the
+mutex also takes this lock.
+
+We then call try_to_take_rt_mutex.  This is where the architecture that
+does not implement CMPXCHG would always grab the lock (if there's no
+contention).
+
+try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
+slow path.  The first thing that is done here is an atomic setting of
+the "Has Waiters" flag of the mutex's owner field.  Yes, this could really
+be false, because if the the mutex has no owner, there are no waiters and
+the current task also won't have any waiters.  But we don't have the lock
+yet, so we assume we are going to be a waiter.  The reason for this is to
+play nice for those architectures that do have CMPXCHG.  By setting this flag
+now, the owner of the mutex can't release the mutex without going into the
+slow unlock path, and it would then need to grab the wait_lock, which this
+code currently holds.  So setting the "Has Waiters" flag forces the owner
+to synchronize with this code.
+
+Now that we know that we can't have any races with the owner releasing the
+mutex, we check to see if we can take the ownership.  This is done if the
+mutex doesn't have a owner, or if we can steal the mutex from a pending
+owner.  Let's look at the situations we have here.
+
+  1) Has owner that is pending
+  ----------------------------
+
+  The mutex has a owner, but it hasn't woken up and the mutex flag
+  "Pending Owner" is set.  The first check is to see if the owner isn't the
+  current task.  This is because this function is also used for the pending
+  owner to grab the mutex.  When a pending owner wakes up, it checks to see
+  if it can take the mutex, and this is done if the owner is already set to
+  itself.  If so, we succeed and leave the function, clearing the "Pending
+  Owner" bit.
+
+  If the pending owner is not current, we check to see if the current priority is
+  higher than the pending owner.  If not, we fail the function and return.
+
+  There's also something special about a pending owner.  That is a pending owner
+  is never blocked on a mutex.  So there is no PI chain to worry about.  It also
+  means that if the mutex doesn't have any waiters, there's no accounting needed
+  to update the pending owner's pi_list, since we only worry about processes
+  blocked on the current mutex.
+
+  If there are waiters on this mutex, and we just stole the ownership, we need
+  to take the top waiter, remove it from the pi_list of the pending owner, and
+  add it to the current pi_list.  Note that at this moment, the pending owner
+  is no longer on the list of waiters.  This is fine, since the pending owner
+  would add itself back when it realizes that it had the ownership stolen
+  from itself.  When the pending owner tries to grab the mutex, it will fail
+  in try_to_take_rt_mutex if the owner field points to another process.
+
+  2) No owner
+  -----------
+
+  If there is no owner (or we successfully stole the lock), we set the owner
+  of the mutex to current, and set the flag of "Has Waiters" if the current
+  mutex actually has waiters, or we clear the flag if it doesn't.  See, it was
+  OK that we set that flag early, since now it is cleared.
+
+  3) Failed to grab ownership
+  ---------------------------
+
+  The most interesting case is when we fail to take ownership. This means that
+  there exists an owner, or there's a pending owner with equal or higher
+  priority than the current task.
+
+We'll continue on the failed case.
+
+If the mutex has a timeout, we set up a timer to go off to break us out
+of this mutex if we failed to get it after a specified amount of time.
+
+Now we enter a loop that will continue to try to take ownership of the mutex, or
+fail from a timeout or signal.
+
+Once again we try to take the mutex.  This will usually fail the first time
+in the loop, since it had just failed to get the mutex.  But the second time
+in the loop, this would likely succeed, since the task would likely be
+the pending owner.
+
+If the mutex is TASK_INTERRUPTIBLE a check for signals and timeout is done
+here.
+
+The waiter structure has a "task" field that points to the task that is blocked
+on the mutex.  This field can be NULL the first time it goes through the loop
+or if the task is a pending owner and had it's mutex stolen.  If the "task"
+field is NULL then we need to set up the accounting for it.
+
+Task blocks on mutex
+--------------------
+
+The accounting of a mutex and process is done with the waiter structure of
+the process.  The "task" field is set to the process, and the "lock" field
+to the mutex.  The plist nodes are initialized to the processes current
+priority.
+
+Since the wait_lock was taken at the entry of the slow lock, we can safely
+add the waiter to the wait_list.  If the current process is the highest
+priority process currently waiting on this mutex, then we remove the
+previous top waiter process (if it exists) from the pi_list of the owner,
+and add the current process to that list.  Since the pi_list of the owner
+has changed, we call rt_mutex_adjust_prio on the owner to see if the owner
+should adjust its priority accordingly.
+
+If the owner is also blocked on a lock, and had its pi_list changed
+(or deadlock checking is on), we unlock the wait_lock of the mutex and go ahead
+and run rt_mutex_adjust_prio_chain on the owner, as described earlier.
+
+Now all locks are released, and if the current process is still blocked on a
+mutex (waiter "task" field is not NULL), then we go to sleep (call schedule).
+
+Waking up in the loop
+---------------------
+
+The schedule can then wake up for a few reasons.
+  1) we were given pending ownership of the mutex.
+  2) we received a signal and was TASK_INTERRUPTIBLE
+  3) we had a timeout and was TASK_INTERRUPTIBLE
+
+In any of these cases, we continue the loop and once again try to grab the
+ownership of the mutex.  If we succeed, we exit the loop, otherwise we continue
+and on signal and timeout, will exit the loop, or if we had the mutex stolen
+we just simply add ourselves back on the lists and go back to sleep.
+
+Note: For various reasons, because of timeout and signals, the steal mutex
+      algorithm needs to be careful. This is because the current process is
+      still on the wait_list. And because of dynamic changing of priorities,
+      especially on SCHED_OTHER tasks, the current process can be the
+      highest priority task on the wait_list.
+
+Failed to get mutex on Timeout or Signal
+----------------------------------------
+
+If a timeout or signal occurred, the waiter's "task" field would not be
+NULL and the task needs to be taken off the wait_list of the mutex and perhaps
+pi_list of the owner.  If this process was a high priority process, then
+the rt_mutex_adjust_prio_chain needs to be executed again on the owner,
+but this time it will be lowering the priorities.
+
+
+Unlocking the Mutex
+-------------------
+
+The unlocking of a mutex also has a fast path for those architectures with
+CMPXCHG.  Since the taking of a mutex on contention always sets the
+"Has Waiters" flag of the mutex's owner, we use this to know if we need to
+take the slow path when unlocking the mutex.  If the mutex doesn't have any
+waiters, the owner field of the mutex would equal the current process and
+the mutex can be unlocked by just replacing the owner field with NULL.
+
+If the owner field has the "Has Waiters" bit set (or CMPXCHG is not available),
+the slow unlock path is taken.
+
+The first thing done in the slow unlock path is to take the wait_lock of the
+mutex.  This synchronizes the locking and unlocking of the mutex.
+
+A check is made to see if the mutex has waiters or not.  On architectures that
+do not have CMPXCHG, this is the location that the owner of the mutex will
+determine if a waiter needs to be awoken or not.  On architectures that
+do have CMPXCHG, that check is done in the fast path, but it is still needed
+in the slow path too.  If a waiter of a mutex woke up because of a signal
+or timeout between the time the owner failed the fast path CMPXCHG check and
+the grabbing of the wait_lock, the mutex may not have any waiters, thus the
+owner still needs to make this check. If there are no waiters than the mutex
+owner field is set to NULL, the wait_lock is released and nothing more is
+needed.
+
+If there are waiters, then we need to wake one up and give that waiter
+pending ownership.
+
+On the wake up code, the pi_lock of the current owner is taken.  The top
+waiter of the lock is found and removed from the wait_list of the mutex
+as well as the pi_list of the current owner.  The task field of the new
+pending owner's waiter structure is set to NULL, and the owner field of the
+mutex is set to the new owner with the "Pending Owner" bit set, as well
+as the "Has Waiters" bit if there still are other processes blocked on the
+mutex.
+
+The pi_lock of the previous owner is released, and the new pending owner's
+pi_lock is taken.  Remember that this is the trick to prevent the race
+condition in rt_mutex_adjust_prio_chain from adding itself as a waiter
+on the mutex.
+
+We now clear the "pi_blocked_on" field of the new pending owner, and if
+the mutex still has waiters pending, we add the new top waiter to the pi_list
+of the pending owner.
+
+Finally we unlock the pi_lock of the pending owner and wake it up.
+
+
+Contact
+-------
+
+For updates on this document, please email Steven Rostedt <rostedt@goodmis.org>
+
+
+Credits
+-------
+
+Author:  Steven Rostedt <rostedt@goodmis.org>
+
+Reviewers:  Ingo Molnar, Thomas Gleixner, Thomas Duetsch, and Randy Dunlap
+
+Updates
+-------
+
+This document was originally written for 2.6.17-rc3-mm1
diff --git a/Documentation/rt-mutex.txt b/Documentation/rt-mutex.txt
new file mode 100644 (file)
index 0000000..243393d
--- /dev/null
@@ -0,0 +1,79 @@
+RT-mutex subsystem with PI support
+----------------------------------
+
+RT-mutexes with priority inheritance are used to support PI-futexes,
+which enable pthread_mutex_t priority inheritance attributes
+(PTHREAD_PRIO_INHERIT). [See Documentation/pi-futex.txt for more details
+about PI-futexes.]
+
+This technology was developed in the -rt tree and streamlined for
+pthread_mutex support.
+
+Basic principles:
+-----------------
+
+RT-mutexes extend the semantics of simple mutexes by the priority
+inheritance protocol.
+
+A low priority owner of a rt-mutex inherits the priority of a higher
+priority waiter until the rt-mutex is released. If the temporarily
+boosted owner blocks on a rt-mutex itself it propagates the priority
+boosting to the owner of the other rt_mutex it gets blocked on. The
+priority boosting is immediately removed once the rt_mutex has been
+unlocked.
+
+This approach allows us to shorten the block of high-prio tasks on
+mutexes which protect shared resources. Priority inheritance is not a
+magic bullet for poorly designed applications, but it allows
+well-designed applications to use userspace locks in critical parts of
+an high priority thread, without losing determinism.
+
+The enqueueing of the waiters into the rtmutex waiter list is done in
+priority order. For same priorities FIFO order is chosen. For each
+rtmutex, only the top priority waiter is enqueued into the owner's
+priority waiters list. This list too queues in priority order. Whenever
+the top priority waiter of a task changes (for example it timed out or
+got a signal), the priority of the owner task is readjusted. [The
+priority enqueueing is handled by "plists", see include/linux/plist.h
+for more details.]
+
+RT-mutexes are optimized for fastpath operations and have no internal
+locking overhead when locking an uncontended mutex or unlocking a mutex
+without waiters. The optimized fastpath operations require cmpxchg
+support. [If that is not available then the rt-mutex internal spinlock
+is used]
+
+The state of the rt-mutex is tracked via the owner field of the rt-mutex
+structure:
+
+rt_mutex->owner holds the task_struct pointer of the owner. Bit 0 and 1
+are used to keep track of the "owner is pending" and "rtmutex has
+waiters" state.
+
+ owner         bit1    bit0
+ NULL          0       0       mutex is free (fast acquire possible)
+ NULL          0       1       invalid state
+ NULL          1       0       Transitional state*
+ NULL          1       1       invalid state
+ taskpointer   0       0       mutex is held (fast release possible)
+ taskpointer   0       1       task is pending owner
+ taskpointer   1       0       mutex is held and has waiters
+ taskpointer   1       1       task is pending owner and mutex has waiters
+
+Pending-ownership handling is a performance optimization:
+pending-ownership is assigned to the first (highest priority) waiter of
+the mutex, when the mutex is released. The thread is woken up and once
+it starts executing it can acquire the mutex. Until the mutex is taken
+by it (bit 0 is cleared) a competing higher priority thread can "steal"
+the mutex which puts the woken up thread back on the waiters list.
+
+The pending-ownership optimization is especially important for the
+uninterrupted workflow of high-prio tasks which repeatedly
+takes/releases locks that have lower-prio waiters. Without this
+optimization the higher-prio thread would ping-pong to the lower-prio
+task [because at unlock time we always assign a new owner].
+
+(*) The "mutex has waiters" bit gets set to take the lock. If the lock
+doesn't already have an owner, this bit is quickly cleared if there are
+no waiters.  So this is a transitional state to synchronize with looking
+at the owner field of the mutex and the mutex owner releasing the lock.
diff --git a/Documentation/video4linux/README.pvrusb2 b/Documentation/video4linux/README.pvrusb2
new file mode 100644 (file)
index 0000000..c73a32c
--- /dev/null
@@ -0,0 +1,212 @@
+
+$Id$
+Mike Isely <isely@pobox.com>
+
+                           pvrusb2 driver
+
+Background:
+
+  This driver is intended for the "Hauppauge WinTV PVR USB 2.0", which
+  is a USB 2.0 hosted TV Tuner.  This driver is a work in progress.
+  Its history started with the reverse-engineering effort by Björn
+  Danielsson <pvrusb2@dax.nu> whose web page can be found here:
+
+    http://pvrusb2.dax.nu/
+
+  From there Aurelien Alleaume <slts@free.fr> began an effort to
+  create a video4linux compatible driver.  I began with Aurelien's
+  last known snapshot and evolved the driver to the state it is in
+  here.
+
+  More information on this driver can be found at:
+
+    http://www.isely.net/pvrusb2.html
+
+
+  This driver has a strong separation of layers.  They are very
+  roughly:
+
+  1a. Low level wire-protocol implementation with the device.
+
+  1b. I2C adaptor implementation and corresponding I2C client drivers
+      implemented elsewhere in V4L.
+
+  1c. High level hardware driver implementation which coordinates all
+      activities that ensure correct operation of the device.
+
+  2.  A "context" layer which manages instancing of driver, setup,
+      tear-down, arbitration, and interaction with high level
+      interfaces appropriately as devices are hotplugged in the
+      system.
+
+  3.  High level interfaces which glue the driver to various published
+      Linux APIs (V4L, sysfs, maybe DVB in the future).
+
+  The most important shearing layer is between the top 2 layers.  A
+  lot of work went into the driver to ensure that any kind of
+  conceivable API can be laid on top of the core driver.  (Yes, the
+  driver internally leverages V4L to do its work but that really has
+  nothing to do with the API published by the driver to the outside
+  world.)  The architecture allows for different APIs to
+  simultaneously access the driver.  I have a strong sense of fairness
+  about APIs and also feel that it is a good design principle to keep
+  implementation and interface isolated from each other.  Thus while
+  right now the V4L high level interface is the most complete, the
+  sysfs high level interface will work equally well for similar
+  functions, and there's no reason I see right now why it shouldn't be
+  possible to produce a DVB high level interface that can sit right
+  alongside V4L.
+
+  NOTE: Complete documentation on the pvrusb2 driver is contained in
+  the html files within the doc directory; these are exactly the same
+  as what is on the web site at the time.  Browse those files
+  (especially the FAQ) before asking questions.
+
+
+Building
+
+  To build these modules essentially amounts to just running "Make",
+  but you need the kernel source tree nearby and you will likely also
+  want to set a few controlling environment variables first in order
+  to link things up with that source tree.  Please see the Makefile
+  here for comments that explain how to do that.
+
+
+Source file list / functional overview:
+
+  (Note: The term "module" used below generally refers to loosely
+  defined functional units within the pvrusb2 driver and bears no
+  relation to the Linux kernel's concept of a loadable module.)
+
+  pvrusb2-audio.[ch] - This is glue logic that resides between this
+    driver and the msp3400.ko I2C client driver (which is found
+    elsewhere in V4L).
+
+  pvrusb2-context.[ch] - This module implements the context for an
+    instance of the driver.  Everything else eventually ties back to
+    or is otherwise instanced within the data structures implemented
+    here.  Hotplugging is ultimately coordinated here.  All high level
+    interfaces tie into the driver through this module.  This module
+    helps arbitrate each interface's access to the actual driver core,
+    and is designed to allow concurrent access through multiple
+    instances of multiple interfaces (thus you can for example change
+    the tuner's frequency through sysfs while simultaneously streaming
+    video through V4L out to an instance of mplayer).
+
+  pvrusb2-debug.h - This header defines a printk() wrapper and a mask
+    of debugging bit definitions for the various kinds of debug
+    messages that can be enabled within the driver.
+
+  pvrusb2-debugifc.[ch] - This module implements a crude command line
+    oriented debug interface into the driver.  Aside from being part
+    of the process for implementing manual firmware extraction (see
+    the pvrusb2 web site mentioned earlier), probably I'm the only one
+    who has ever used this.  It is mainly a debugging aid.
+
+  pvrusb2-eeprom.[ch] - This is glue logic that resides between this
+    driver the tveeprom.ko module, which is itself implemented
+    elsewhere in V4L.
+
+  pvrusb2-encoder.[ch] - This module implements all protocol needed to
+    interact with the Conexant mpeg2 encoder chip within the pvrusb2
+    device.  It is a crude echo of corresponding logic in ivtv,
+    however the design goals (strict isolation) and physical layer
+    (proxy through USB instead of PCI) are enough different that this
+    implementation had to be completely different.
+
+  pvrusb2-hdw-internal.h - This header defines the core data structure
+    in the driver used to track ALL internal state related to control
+    of the hardware.  Nobody outside of the core hardware-handling
+    modules should have any business using this header.  All external
+    access to the driver should be through one of the high level
+    interfaces (e.g. V4L, sysfs, etc), and in fact even those high
+    level interfaces are restricted to the API defined in
+    pvrusb2-hdw.h and NOT this header.
+
+  pvrusb2-hdw.h - This header defines the full internal API for
+    controlling the hardware.  High level interfaces (e.g. V4L, sysfs)
+    will work through here.
+
+  pvrusb2-hdw.c - This module implements all the various bits of logic
+    that handle overall control of a specific pvrusb2 device.
+    (Policy, instantiation, and arbitration of pvrusb2 devices fall
+    within the jurisdiction of pvrusb-context not here).
+
+  pvrusb2-i2c-chips-*.c - These modules implement the glue logic to
+    tie together and configure various I2C modules as they attach to
+    the I2C bus.  There are two versions of this file.  The "v4l2"
+    version is intended to be used in-tree alongside V4L, where we
+    implement just the logic that makes sense for a pure V4L
+    environment.  The "all" version is intended for use outside of
+    V4L, where we might encounter other possibly "challenging" modules
+    from ivtv or older kernel snapshots (or even the support modules
+    in the standalone snapshot).
+
+  pvrusb2-i2c-cmd-v4l1.[ch] - This module implements generic V4L1
+    compatible commands to the I2C modules.  It is here where state
+    changes inside the pvrusb2 driver are translated into V4L1
+    commands that are in turn send to the various I2C modules.
+
+  pvrusb2-i2c-cmd-v4l2.[ch] - This module implements generic V4L2
+    compatible commands to the I2C modules.  It is here where state
+    changes inside the pvrusb2 driver are translated into V4L2
+    commands that are in turn send to the various I2C modules.
+
+  pvrusb2-i2c-core.[ch] - This module provides an implementation of a
+    kernel-friendly I2C adaptor driver, through which other external
+    I2C client drivers (e.g. msp3400, tuner, lirc) may connect and
+    operate corresponding chips within the the pvrusb2 device.  It is
+    through here that other V4L modules can reach into this driver to
+    operate specific pieces (and those modules are in turn driven by
+    glue logic which is coordinated by pvrusb2-hdw, doled out by
+    pvrusb2-context, and then ultimately made available to users
+    through one of the high level interfaces).
+
+  pvrusb2-io.[ch] - This module implements a very low level ring of
+    transfer buffers, required in order to stream data from the
+    device.  This module is *very* low level.  It only operates the
+    buffers and makes no attempt to define any policy or mechanism for
+    how such buffers might be used.
+
+  pvrusb2-ioread.[ch] - This module layers on top of pvrusb2-io.[ch]
+    to provide a streaming API usable by a read() system call style of
+    I/O.  Right now this is the only layer on top of pvrusb2-io.[ch],
+    however the underlying architecture here was intended to allow for
+    other styles of I/O to be implemented with additonal modules, like
+    mmap()'ed buffers or something even more exotic.
+
+  pvrusb2-main.c - This is the top level of the driver.  Module level
+    and USB core entry points are here.  This is our "main".
+
+  pvrusb2-sysfs.[ch] - This is the high level interface which ties the
+    pvrusb2 driver into sysfs.  Through this interface you can do
+    everything with the driver except actually stream data.
+
+  pvrusb2-tuner.[ch] - This is glue logic that resides between this
+    driver and the tuner.ko I2C client driver (which is found
+    elsewhere in V4L).
+
+  pvrusb2-util.h - This header defines some common macros used
+    throughout the driver.  These macros are not really specific to
+    the driver, but they had to go somewhere.
+
+  pvrusb2-v4l2.[ch] - This is the high level interface which ties the
+    pvrusb2 driver into video4linux.  It is through here that V4L
+    applications can open and operate the driver in the usual V4L
+    ways.  Note that **ALL** V4L functionality is published only
+    through here and nowhere else.
+
+  pvrusb2-video-*.[ch] - This is glue logic that resides between this
+    driver and the saa711x.ko I2C client driver (which is found
+    elsewhere in V4L).  Note that saa711x.ko used to be known as
+    saa7115.ko in ivtv.  There are two versions of this; one is
+    selected depending on the particular saa711[5x].ko that is found.
+
+  pvrusb2.h - This header contains compile time tunable parameters
+    (and at the moment the driver has very little that needs to be
+    tuned).
+
+
+  -Mike Isely
+  isely@pobox.com
+
index 12187a33e31021f519a09bdbd14e311e46f18451..d9ee6336c1d49e6cf262d814251741cd340a1036 100644 (file)
  to run the program with an "&" to run it in the background!)
 
  If you want to write a program to be compatible with the PC Watchdog
- driver, simply do the following:
-
--- Snippet of code --
-/*
- * Watchdog Driver Test Program
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/types.h>
-#include <linux/watchdog.h>
-
-int fd;
-
-/*
- * This function simply sends an IOCTL to the driver, which in turn ticks
- * the PC Watchdog card to reset its internal timer so it doesn't trigger
- * a computer reset.
- */
-void keep_alive(void)
-{
-    int dummy;
-
-    ioctl(fd, WDIOC_KEEPALIVE, &dummy);
-}
-
-/*
- * The main program.  Run the program with "-d" to disable the card,
- * or "-e" to enable the card.
- */
-int main(int argc, char *argv[])
-{
-    fd = open("/dev/watchdog", O_WRONLY);
-
-    if (fd == -1) {
-       fprintf(stderr, "Watchdog device not enabled.\n");
-       fflush(stderr);
-       exit(-1);
-    }
-
-    if (argc > 1) {
-       if (!strncasecmp(argv[1], "-d", 2)) {
-           ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
-           fprintf(stderr, "Watchdog card disabled.\n");
-           fflush(stderr);
-           exit(0);
-       } else if (!strncasecmp(argv[1], "-e", 2)) {
-           ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
-           fprintf(stderr, "Watchdog card enabled.\n");
-           fflush(stderr);
-           exit(0);
-       } else {
-           fprintf(stderr, "-d to disable, -e to enable.\n");
-           fprintf(stderr, "run by itself to tick the card.\n");
-           fflush(stderr);
-           exit(0);
-       }
-    } else {
-       fprintf(stderr, "Watchdog Ticking Away!\n");
-       fflush(stderr);
-    }
-
-    while(1) {
-       keep_alive();
-       sleep(1);
-    }
-}
--- End snippet --
+ driver, simply use of modify the watchdog test program:
+ Documentation/watchdog/src/watchdog-test.c
+
 
  Other IOCTL functions include:
 
diff --git a/Documentation/watchdog/src/watchdog-simple.c b/Documentation/watchdog/src/watchdog-simple.c
new file mode 100644 (file)
index 0000000..85cf17c
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <fcntl.h>
+
+int main(int argc, const char *argv[]) {
+       int fd = open("/dev/watchdog", O_WRONLY);
+       if (fd == -1) {
+               perror("watchdog");
+               exit(1);
+       }
+       while (1) {
+               write(fd, "\0", 1);
+               fsync(fd);
+               sleep(10);
+       }
+}
diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c
new file mode 100644 (file)
index 0000000..65f6c19
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Watchdog Driver Test Program
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+int fd;
+
+/*
+ * This function simply sends an IOCTL to the driver, which in turn ticks
+ * the PC Watchdog card to reset its internal timer so it doesn't trigger
+ * a computer reset.
+ */
+void keep_alive(void)
+{
+    int dummy;
+
+    ioctl(fd, WDIOC_KEEPALIVE, &dummy);
+}
+
+/*
+ * The main program.  Run the program with "-d" to disable the card,
+ * or "-e" to enable the card.
+ */
+int main(int argc, char *argv[])
+{
+    fd = open("/dev/watchdog", O_WRONLY);
+
+    if (fd == -1) {
+       fprintf(stderr, "Watchdog device not enabled.\n");
+       fflush(stderr);
+       exit(-1);
+    }
+
+    if (argc > 1) {
+       if (!strncasecmp(argv[1], "-d", 2)) {
+           ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
+           fprintf(stderr, "Watchdog card disabled.\n");
+           fflush(stderr);
+           exit(0);
+       } else if (!strncasecmp(argv[1], "-e", 2)) {
+           ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
+           fprintf(stderr, "Watchdog card enabled.\n");
+           fflush(stderr);
+           exit(0);
+       } else {
+           fprintf(stderr, "-d to disable, -e to enable.\n");
+           fprintf(stderr, "run by itself to tick the card.\n");
+           fflush(stderr);
+           exit(0);
+       }
+    } else {
+       fprintf(stderr, "Watchdog Ticking Away!\n");
+       fflush(stderr);
+    }
+
+    while(1) {
+       keep_alive();
+       sleep(1);
+    }
+}
index 21ed5117366240d2a33af5af7f5605733bd514c1..958ff3d48be3dd7288afa5e59b53cde05ccc8487 100644 (file)
@@ -34,22 +34,7 @@ activates as soon as /dev/watchdog is opened and will reboot unless
 the watchdog is pinged within a certain time, this time is called the
 timeout or margin.  The simplest way to ping the watchdog is to write
 some data to the device.  So a very simple watchdog daemon would look
-like this:
-
-#include <stdlib.h>
-#include <fcntl.h>
-
-int main(int argc, const char *argv[]) {
-       int fd=open("/dev/watchdog",O_WRONLY);
-       if (fd==-1) {
-               perror("watchdog");
-               exit(1);
-       }
-       while(1) {
-               write(fd, "\0", 1);
-               sleep(10);
-       }
-}
+like this source file:  see Documentation/watchdog/src/watchdog-simple.c
 
 A more advanced driver could for example check that a HTTP server is
 still responding before doing the write call to ping the watchdog.
@@ -110,7 +95,40 @@ current timeout using the GETTIMEOUT ioctl.
     ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
     printf("The timeout was is %d seconds\n", timeout);
 
-Envinronmental monitoring:
+Pretimeouts:
+
+Some watchdog timers can be set to have a trigger go off before the
+actual time they will reset the system.  This can be done with an NMI,
+interrupt, or other mechanism.  This allows Linux to record useful
+information (like panic information and kernel coredumps) before it
+resets.
+
+    pretimeout = 10;
+    ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout);
+
+Note that the pretimeout is the number of seconds before the time
+when the timeout will go off.  It is not the number of seconds until
+the pretimeout.  So, for instance, if you set the timeout to 60 seconds
+and the pretimeout to 10 seconds, the pretimout will go of in 50
+seconds.  Setting a pretimeout to zero disables it.
+
+There is also a get function for getting the pretimeout:
+
+    ioctl(fd, WDIOC_GETPRETIMEOUT, &timeout);
+    printf("The pretimeout was is %d seconds\n", timeout);
+
+Not all watchdog drivers will support a pretimeout.
+
+Get the number of seconds before reboot:
+
+Some watchdog drivers have the ability to report the remaining time
+before the system will reboot. The WDIOC_GETTIMELEFT is the ioctl
+that returns the number of seconds before reboot.
+
+    ioctl(fd, WDIOC_GETTIMELEFT, &timeleft);
+    printf("The timeout was is %d seconds\n", timeleft);
+
+Environmental monitoring:
 
 All watchdog drivers are required return more information about the system,
 some do temperature, fan and power level monitoring, some can tell you
@@ -169,6 +187,10 @@ The watchdog saw a keepalive ping since it was last queried.
 
        WDIOF_SETTIMEOUT        Can set/get the timeout
 
+The watchdog can do pretimeouts.
+
+       WDIOF_PRETIMEOUT        Pretimeout (in seconds), get/set
+
 
 For those drivers that return any bits set in the option field, the
 GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current
index dffda29c8799c1a2c0709a362400487fb5cc6047..4b1ff69cc19a7ea5010cecee914523b67d5dbd3c 100644 (file)
@@ -65,28 +65,7 @@ The external event interfaces on the WDT boards are not currently supported.
 Minor numbers are however allocated for it.
 
 
-Example Watchdog Driver
------------------------
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-int main(int argc, const char *argv[])
-{
-       int fd=open("/dev/watchdog",O_WRONLY);
-       if(fd==-1)
-       {
-               perror("watchdog");
-               exit(1);
-       }
-       while(1)
-       {
-               write(fd,"\0",1);
-               fsync(fd);
-               sleep(10);
-       }
-}
+Example Watchdog Driver:  see Documentation/watchdog/src/watchdog-simple.c
 
 
 Contact Information
index da677f829f7689966bf09aeda6d89fc4b6a876d1..63af36cf7f6e356fc917b1ac86f6e879be5bc0fd 100644 (file)
@@ -49,15 +49,15 @@ select_smp_affinity(unsigned int irq)
        static int last_cpu;
        int cpu = last_cpu + 1;
 
-       if (!irq_desc[irq].handler->set_affinity || irq_user_affinity[irq])
+       if (!irq_desc[irq].chip->set_affinity || irq_user_affinity[irq])
                return 1;
 
        while (!cpu_possible(cpu))
                cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
        last_cpu = cpu;
 
-       irq_affinity[irq] = cpumask_of_cpu(cpu);
-       irq_desc[irq].handler->set_affinity(irq, cpumask_of_cpu(cpu));
+       irq_desc[irq].affinity = cpumask_of_cpu(cpu);
+       irq_desc[irq].chip->set_affinity(irq, cpumask_of_cpu(cpu));
        return 0;
 }
 #endif /* CONFIG_SMP */
@@ -93,7 +93,7 @@ show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[irq]);
 #endif
-               seq_printf(p, " %14s", irq_desc[irq].handler->typename);
+               seq_printf(p, " %14s", irq_desc[irq].chip->typename);
                seq_printf(p, "  %c%s",
                        (action->flags & SA_INTERRUPT)?'+':' ',
                        action->name);
index 9d34ce26e5efc9231eb3581de7b158438818944d..f20f2dff9c438599c6e182eaf9222bf34450b45a 100644 (file)
@@ -233,7 +233,7 @@ void __init
 init_rtc_irq(void)
 {
        irq_desc[RTC_IRQ].status = IRQ_DISABLED;
-       irq_desc[RTC_IRQ].handler = &rtc_irq_type;
+       irq_desc[RTC_IRQ].chip = &rtc_irq_type;
        setup_irq(RTC_IRQ, &timer_irqaction);
 }
 
index b188683b83fd04a4ec8265e4bf1c5c06da8c1694..ac893bd48036cf6cf613d82a042eb6860b690830 100644 (file)
@@ -109,7 +109,7 @@ init_i8259a_irqs(void)
 
        for (i = 0; i < 16; i++) {
                irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].handler = &i8259a_irq_type;
+               irq_desc[i].chip = &i8259a_irq_type;
        }
 
        setup_irq(2, &cascade);
index 146a20b9e3d563208715c5033214e0e16d1d7f8e..3b581415bab0bdaa5e9607cb14faf4dc7debed10 100644 (file)
@@ -120,7 +120,7 @@ init_pyxis_irqs(unsigned long ignore_mask)
                if ((ignore_mask >> i) & 1)
                        continue;
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &pyxis_irq_type;
+               irq_desc[i].chip = &pyxis_irq_type;
        }
 
        setup_irq(16+7, &isa_cascade_irqaction);
index 0a87e466918c2e72fb59e4a5f087a1e5fa268007..8e4d121f84ccf87745aa6149e0a1a26e53649211 100644 (file)
@@ -67,7 +67,7 @@ init_srm_irqs(long max, unsigned long ignore_mask)
                if (i < 64 && ((ignore_mask >> i) & 1))
                        continue;
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &srm_irq_type;
+               irq_desc[i].chip = &srm_irq_type;
        }
 }
 
index 2a8b364c822e9f0e17c9ead5352ab84ad9f1ace6..4ea6711e55aa5263812ba401a84dbae7ff5d4dbf 100644 (file)
@@ -124,12 +124,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final);
 
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                      resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
        struct pci_controller *hose = dev->sysdata;
        unsigned long alignto;
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO) {
                /* Make sure we start at our min on all hoses */
index 558b83368559396f4d50f793d37d8e7dd83c26d1..254c507a608c076f9e09aa8acb83edfea90d2975 100644 (file)
@@ -481,7 +481,7 @@ register_cpus(void)
                struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
                if (!p)
                        return -ENOMEM;
-               register_cpu(p, i, NULL);
+               register_cpu(p, i);
        }
        return 0;
 }
index d7f0e97fe56fbeed9a93f102116de960de9c40ec..1a1a2c7a3d944190c8699339c5f38086b434ee83 100644 (file)
@@ -144,7 +144,7 @@ alcor_init_irq(void)
                if (i >= 16+20 && i <= 16+30)
                        continue;
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &alcor_irq_type;
+               irq_desc[i].chip = &alcor_irq_type;
        }
        i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq;
 
index 8e3374d34c95bf2782a34ae7ce2ca749c56b8590..8c9e443d93ad6298b312e424ee48db22fd23ebe6 100644 (file)
@@ -124,7 +124,7 @@ common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r))
 
                for (i = 16; i < 35; ++i) {
                        irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-                       irq_desc[i].handler = &cabriolet_irq_type;
+                       irq_desc[i].chip = &cabriolet_irq_type;
                }
        }
 
index d5da6b1b28eec6cd557942ff1684f371a9ccc22a..b28c8f1c6e10b078fb0b1173ce64ad538bc23dda 100644 (file)
@@ -300,7 +300,7 @@ init_tsunami_irqs(struct hw_interrupt_type * ops, int imin, int imax)
        long i;
        for (i = imin; i <= imax; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = ops;
+               irq_desc[i].chip = ops;
        }
 }
 
index 61a79c354f0bdece82ed231db04aae15706fc226..aeb8e0277905660275943dd0b0678c3ba08a19b6 100644 (file)
@@ -137,7 +137,7 @@ eb64p_init_irq(void)
 
        for (i = 16; i < 32; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &eb64p_irq_type;
+               irq_desc[i].chip = &eb64p_irq_type;
        }               
 
        common_init_isa_dma();
index bd6e5f0e43c7e443b1d23dd6935df6d26d2e2e61..64a785baf53a0f1ffac8ebfcb904a4ec4c01c0d6 100644 (file)
@@ -154,7 +154,7 @@ eiger_init_irq(void)
 
        for (i = 16; i < 128; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &eiger_irq_type;
+               irq_desc[i].chip = &eiger_irq_type;
        }
 }
 
index fcabb7c96a16588f7367eb554d7b3ad8b9ee3047..0148e095638f8c6d40183ca098f49746f2f5d9f8 100644 (file)
@@ -206,11 +206,11 @@ jensen_init_irq(void)
 {
        init_i8259a_irqs();
 
-       irq_desc[1].handler = &jensen_local_irq_type;
-       irq_desc[4].handler = &jensen_local_irq_type;
-       irq_desc[3].handler = &jensen_local_irq_type;
-       irq_desc[7].handler = &jensen_local_irq_type;
-       irq_desc[9].handler = &jensen_local_irq_type;
+       irq_desc[1].chip = &jensen_local_irq_type;
+       irq_desc[4].chip = &jensen_local_irq_type;
+       irq_desc[3].chip = &jensen_local_irq_type;
+       irq_desc[7].chip = &jensen_local_irq_type;
+       irq_desc[9].chip = &jensen_local_irq_type;
 
        common_init_isa_dma();
 }
index e32fee50522076c7cfaf685d80690e2c0846c135..36d2159543769758904fe8125b7c037b4984efcc 100644 (file)
@@ -303,7 +303,7 @@ init_io7_irqs(struct io7 *io7,
        /* Set up the lsi irqs.  */
        for (i = 0; i < 128; ++i) {
                irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[base + i].handler = lsi_ops;
+               irq_desc[base + i].chip = lsi_ops;
        }
 
        /* Disable the implemented irqs in hardware.  */
@@ -317,7 +317,7 @@ init_io7_irqs(struct io7 *io7,
        /* Set up the msi irqs.  */
        for (i = 128; i < (128 + 512); ++i) {
                irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[base + i].handler = msi_ops;
+               irq_desc[base + i].chip = msi_ops;
        }
 
        for (i = 0; i < 16; ++i)
@@ -335,7 +335,7 @@ marvel_init_irq(void)
        /* Reserve the legacy irqs.  */
        for (i = 0; i < 16; ++i) {
                irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].handler = &marvel_legacy_irq_type;
+               irq_desc[i].chip = &marvel_legacy_irq_type;
        }
 
        /* Init the io7 irqs.  */
index d78a0daa6168e3c3216b82f2f8bc514bd94ded74..b741600e3761a794450d07b278b6ffd2afe2b0ff 100644 (file)
@@ -117,7 +117,7 @@ mikasa_init_irq(void)
 
        for (i = 16; i < 32; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &mikasa_irq_type;
+               irq_desc[i].chip = &mikasa_irq_type;
        }
 
        init_i8259a_irqs();
index 65061f5d741062e01ed1487a7bb389ec770245b2..55db02d318d74172804f5ee67ae1ebd25e046b7d 100644 (file)
@@ -139,7 +139,7 @@ noritake_init_irq(void)
 
        for (i = 16; i < 48; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &noritake_irq_type;
+               irq_desc[i].chip = &noritake_irq_type;
        }
 
        init_i8259a_irqs();
index 05888a02a6049415e53b5ac0c84022eb39d5a605..949607e3d6fbe82395c641b1f94ecb3d99ef1b12 100644 (file)
@@ -180,7 +180,7 @@ rawhide_init_irq(void)
 
        for (i = 16; i < 128; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &rawhide_irq_type;
+               irq_desc[i].chip = &rawhide_irq_type;
        }
 
        init_i8259a_irqs();
index 58404243057b65711300cf786175f62597122f04..6ae50605263592061869345ecfe1856a1c33467e 100644 (file)
@@ -117,7 +117,7 @@ rx164_init_irq(void)
        rx164_update_irq_hw(0);
        for (i = 16; i < 40; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &rx164_irq_type;
+               irq_desc[i].chip = &rx164_irq_type;
        }
 
        init_i8259a_irqs();
index a7ff84474aceebc7603455ec09b8180471d09798..24dea40c9bfe823feea687efcea7677bb42bae12 100644 (file)
@@ -537,7 +537,7 @@ sable_lynx_init_irq(int nr_irqs)
 
        for (i = 0; i < nr_irqs; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &sable_lynx_irq_type;
+               irq_desc[i].chip = &sable_lynx_irq_type;
        }
 
        common_init_isa_dma();
index 7955bdfc2db0e2fabd4b44da9eed48ecc947ead2..2c75cd1fd81aab537e6b93615011baba52b98e2c 100644 (file)
@@ -154,7 +154,7 @@ takara_init_irq(void)
 
        for (i = 16; i < 128; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &takara_irq_type;
+               irq_desc[i].chip = &takara_irq_type;
        }
 
        common_init_isa_dma();
index 2551fb49ae099150561407adc726e410b8e03c9f..13f3ed8ed7ac2f1c166d6d9392a0785bccbb71fd 100644 (file)
@@ -189,7 +189,7 @@ init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax)
        long i;
        for (i = imin; i <= imax; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = ops;
+               irq_desc[i].chip = ops;
        }
 }
 
index 1553f470246e6b74eecb0ba9630982d3a0cf5c97..22c5798fe083ba03cf16e88ec6fe4088fce61ce3 100644 (file)
@@ -199,14 +199,14 @@ wildfire_init_irq_per_pca(int qbbno, int pcano)
                if (i == 2)
                        continue;
                irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i+irq_bias].handler = &wildfire_irq_type;
+               irq_desc[i+irq_bias].chip = &wildfire_irq_type;
        }
 
        irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
-       irq_desc[36+irq_bias].handler = &wildfire_irq_type;
+       irq_desc[36+irq_bias].chip = &wildfire_irq_type;
        for (i = 40; i < 64; ++i) {
                irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i+irq_bias].handler = &wildfire_irq_type;
+               irq_desc[i+irq_bias].chip = &wildfire_irq_type;
        }
 
        setup_irq(32+irq_bias, &isa_enable);    
index 3d1a3fb7d5fc17901b200f9a4e8a8097d271f066..f123c7c9fc989d507a5c834b2208fc94a5f02c54 100644 (file)
@@ -188,23 +188,27 @@ config ARCH_IMX
 
 config ARCH_IOP3XX
        bool "IOP3xx-based"
+       depends on MMU
        select PCI
        help
          Support for Intel's IOP3XX (XScale) family of processors.
 
 config ARCH_IXP4XX
        bool "IXP4xx-based"
+       depends on MMU
        help
          Support for Intel's IXP4XX (XScale) family of processors.
 
 config ARCH_IXP2000
        bool "IXP2400/2800-based"
+       depends on MMU
        select PCI
        help
          Support for Intel's IXP2400/2800 (XScale) family of processors.
 
 config ARCH_IXP23XX
        bool "IXP23XX-based"
+       depends on MMU
        select PCI
        help
          Support for Intel's IXP23xx (XScale) family of processors.
@@ -229,6 +233,7 @@ config ARCH_PNX4008
 
 config ARCH_PXA
        bool "PXA2xx-based"
+       depends on MMU
        select ARCH_MTD_XIP
        help
          Support for Intel's PXA2XX processor line.
@@ -339,6 +344,10 @@ config XSCALE_PMU
        depends on CPU_XSCALE && !XSCALE_PMU_TIMER
        default y
 
+if !MMU
+source "arch/arm/Kconfig-nommu"
+endif
+
 endmenu
 
 source "arch/arm/common/Kconfig"
index a601b8b55f3594ba1a0989956c5db5ae9da389fa..7cffbaef064ba60afcec20ca02638ebf70b89a9a 100644 (file)
@@ -22,6 +22,9 @@ obj-$(CONFIG_PCI)             += bios32.o
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_OABI_COMPAT)      += sys_oabi-compat.o
 
+obj-$(CONFIG_CRUNCH)           += crunch.o crunch-bits.o
+AFLAGS_crunch-bits.o           := -Wa,-mcpu=ep9312
+
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
 
index c49b5d4d7fca2a77217c15732c0fbeeefdf90f6f..da69e660574bf1510f8f1457d07c7368b7de12e2 100644 (file)
@@ -109,11 +109,13 @@ EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(__memzero);
 
        /* user mem (segment) */
-EXPORT_SYMBOL(__arch_copy_from_user);
-EXPORT_SYMBOL(__arch_copy_to_user);
-EXPORT_SYMBOL(__arch_clear_user);
-EXPORT_SYMBOL(__arch_strnlen_user);
-EXPORT_SYMBOL(__arch_strncpy_from_user);
+EXPORT_SYMBOL(__strnlen_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+
+#ifdef CONFIG_MMU
+EXPORT_SYMBOL(__copy_from_user);
+EXPORT_SYMBOL(__copy_to_user);
+EXPORT_SYMBOL(__clear_user);
 
 EXPORT_SYMBOL(__get_user_1);
 EXPORT_SYMBOL(__get_user_2);
@@ -123,6 +125,7 @@ EXPORT_SYMBOL(__put_user_1);
 EXPORT_SYMBOL(__put_user_2);
 EXPORT_SYMBOL(__put_user_4);
 EXPORT_SYMBOL(__put_user_8);
+#endif
 
        /* crypto hash */
 EXPORT_SYMBOL(sha_transform);
index 396efba9bacd2d6fb6351e18149576cc1d779665..447ede5143a8f7bf16f3b0ea48d0ebd500d5a3ca 100644 (file)
@@ -59,6 +59,9 @@ int main(void)
   DEFINE(TI_VFPSTATE,          offsetof(struct thread_info, vfpstate));
 #ifdef CONFIG_IWMMXT
   DEFINE(TI_IWMMXT_STATE,      offsetof(struct thread_info, fpstate.iwmmxt));
+#endif
+#ifdef CONFIG_CRUNCH
+  DEFINE(TI_CRUNCH_STATE,      offsetof(struct thread_info, crunchstate));
 #endif
   BLANK();
   DEFINE(S_R0,                 offsetof(struct pt_regs, ARM_r0));
index 302fc140154797e8d2d59045a40a940cad69092a..45da06fc1ba1a1481f66e102e0fc582aaa2096f5 100644 (file)
@@ -304,7 +304,7 @@ static inline int pdev_bad_for_parity(struct pci_dev *dev)
 static void __devinit
 pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev)
 {
-       unsigned long offset;
+       resource_size_t offset;
        int i;
 
        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
@@ -634,9 +634,9 @@ char * __init pcibios_setup(char *str)
  * which might be mirrored at 0x0100-0x03ff..
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO && start & 0x300)
                start = (start + 0x3ff) & ~0x3ff;
diff --git a/arch/arm/kernel/crunch-bits.S b/arch/arm/kernel/crunch-bits.S
new file mode 100644 (file)
index 0000000..a268867
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * arch/arm/kernel/crunch-bits.S
+ * Cirrus MaverickCrunch context switching and handling
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * Shamelessly stolen from the iWMMXt code by Nicolas Pitre, which is
+ * Copyright (c) 2003-2004, MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/arch/ep93xx-regs.h>
+
+/*
+ * We can't use hex constants here due to a bug in gas.
+ */
+#define CRUNCH_MVDX0           0
+#define CRUNCH_MVDX1           8
+#define CRUNCH_MVDX2           16
+#define CRUNCH_MVDX3           24
+#define CRUNCH_MVDX4           32
+#define CRUNCH_MVDX5           40
+#define CRUNCH_MVDX6           48
+#define CRUNCH_MVDX7           56
+#define CRUNCH_MVDX8           64
+#define CRUNCH_MVDX9           72
+#define CRUNCH_MVDX10          80
+#define CRUNCH_MVDX11          88
+#define CRUNCH_MVDX12          96
+#define CRUNCH_MVDX13          104
+#define CRUNCH_MVDX14          112
+#define CRUNCH_MVDX15          120
+#define CRUNCH_MVAX0L          128
+#define CRUNCH_MVAX0M          132
+#define CRUNCH_MVAX0H          136
+#define CRUNCH_MVAX1L          140
+#define CRUNCH_MVAX1M          144
+#define CRUNCH_MVAX1H          148
+#define CRUNCH_MVAX2L          152
+#define CRUNCH_MVAX2M          156
+#define CRUNCH_MVAX2H          160
+#define CRUNCH_MVAX3L          164
+#define CRUNCH_MVAX3M          168
+#define CRUNCH_MVAX3H          172
+#define CRUNCH_DSPSC           176
+
+#define CRUNCH_SIZE            184
+
+       .text
+
+/*
+ * Lazy switching of crunch coprocessor context
+ *
+ * r10 = struct thread_info pointer
+ * r9  = ret_from_exception
+ * lr  = undefined instr exit
+ *
+ * called from prefetch exception handler with interrupts disabled
+ */
+ENTRY(crunch_task_enable)
+       ldr     r8, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
+
+       ldr     r1, [r8, #0x80]
+       tst     r1, #0x00800000                 @ access to crunch enabled?
+       movne   pc, lr                          @ if so no business here
+       mov     r3, #0xaa                       @ unlock syscon swlock
+       str     r3, [r8, #0xc0]
+       orr     r1, r1, #0x00800000             @ enable access to crunch
+       str     r1, [r8, #0x80]
+
+       ldr     r3, =crunch_owner
+       add     r0, r10, #TI_CRUNCH_STATE       @ get task crunch save area
+       ldr     r2, [sp, #60]                   @ current task pc value
+       ldr     r1, [r3]                        @ get current crunch owner
+       str     r0, [r3]                        @ this task now owns crunch
+       sub     r2, r2, #4                      @ adjust pc back
+       str     r2, [sp, #60]
+
+       ldr     r2, [r8, #0x80]
+       mov     r2, r2                          @ flush out enable (@@@)
+
+       teq     r1, #0                          @ test for last ownership
+       mov     lr, r9                          @ normal exit from exception
+       beq     crunch_load                     @ no owner, skip save
+
+crunch_save:
+       cfstr64         mvdx0, [r1, #CRUNCH_MVDX0]      @ save 64b registers
+       cfstr64         mvdx1, [r1, #CRUNCH_MVDX1]
+       cfstr64         mvdx2, [r1, #CRUNCH_MVDX2]
+       cfstr64         mvdx3, [r1, #CRUNCH_MVDX3]
+       cfstr64         mvdx4, [r1, #CRUNCH_MVDX4]
+       cfstr64         mvdx5, [r1, #CRUNCH_MVDX5]
+       cfstr64         mvdx6, [r1, #CRUNCH_MVDX6]
+       cfstr64         mvdx7, [r1, #CRUNCH_MVDX7]
+       cfstr64         mvdx8, [r1, #CRUNCH_MVDX8]
+       cfstr64         mvdx9, [r1, #CRUNCH_MVDX9]
+       cfstr64         mvdx10, [r1, #CRUNCH_MVDX10]
+       cfstr64         mvdx11, [r1, #CRUNCH_MVDX11]
+       cfstr64         mvdx12, [r1, #CRUNCH_MVDX12]
+       cfstr64         mvdx13, [r1, #CRUNCH_MVDX13]
+       cfstr64         mvdx14, [r1, #CRUNCH_MVDX14]
+       cfstr64         mvdx15, [r1, #CRUNCH_MVDX15]
+
+#ifdef __ARMEB__
+#error fix me for ARMEB
+#endif
+
+       cfmv32al        mvfx0, mvax0                    @ save 72b accumulators
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0L]
+       cfmv32am        mvfx0, mvax0
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0M]
+       cfmv32ah        mvfx0, mvax0
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0H]
+       cfmv32al        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1L]
+       cfmv32am        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1M]
+       cfmv32ah        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1H]
+       cfmv32al        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2L]
+       cfmv32am        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2M]
+       cfmv32ah        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2H]
+       cfmv32al        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3L]
+       cfmv32am        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3M]
+       cfmv32ah        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3H]
+
+       cfmv32sc        mvdx0, dspsc                    @ save status word
+       cfstr64         mvdx0, [r1, #CRUNCH_DSPSC]
+
+       teq             r0, #0                          @ anything to load?
+       cfldr64eq       mvdx0, [r1, #CRUNCH_MVDX0]      @ mvdx0 was clobbered
+       moveq           pc, lr
+
+crunch_load:
+       cfldr64         mvdx0, [r0, #CRUNCH_DSPSC]      @ load status word
+       cfmvsc32        dspsc, mvdx0
+
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0L]     @ load 72b accumulators
+       cfmval32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0M]
+       cfmvam32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0H]
+       cfmvah32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1L]
+       cfmval32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1M]
+       cfmvam32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1H]
+       cfmvah32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2L]
+       cfmval32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2M]
+       cfmvam32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2H]
+       cfmvah32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3L]
+       cfmval32        mvax3, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3M]
+       cfmvam32        mvax3, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3H]
+       cfmvah32        mvax3, mvfx0
+
+       cfldr64         mvdx0, [r0, #CRUNCH_MVDX0]      @ load 64b registers
+       cfldr64         mvdx1, [r0, #CRUNCH_MVDX1]
+       cfldr64         mvdx2, [r0, #CRUNCH_MVDX2]
+       cfldr64         mvdx3, [r0, #CRUNCH_MVDX3]
+       cfldr64         mvdx4, [r0, #CRUNCH_MVDX4]
+       cfldr64         mvdx5, [r0, #CRUNCH_MVDX5]
+       cfldr64         mvdx6, [r0, #CRUNCH_MVDX6]
+       cfldr64         mvdx7, [r0, #CRUNCH_MVDX7]
+       cfldr64         mvdx8, [r0, #CRUNCH_MVDX8]
+       cfldr64         mvdx9, [r0, #CRUNCH_MVDX9]
+       cfldr64         mvdx10, [r0, #CRUNCH_MVDX10]
+       cfldr64         mvdx11, [r0, #CRUNCH_MVDX11]
+       cfldr64         mvdx12, [r0, #CRUNCH_MVDX12]
+       cfldr64         mvdx13, [r0, #CRUNCH_MVDX13]
+       cfldr64         mvdx14, [r0, #CRUNCH_MVDX14]
+       cfldr64         mvdx15, [r0, #CRUNCH_MVDX15]
+
+       mov     pc, lr
+
+/*
+ * Back up crunch regs to save area and disable access to them
+ * (mainly for gdb or sleep mode usage)
+ *
+ * r0 = struct thread_info pointer of target task or NULL for any
+ */
+ENTRY(crunch_task_disable)
+       stmfd   sp!, {r4, r5, lr}
+
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r4, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r1, [r3]                        @ get current crunch owner
+       teq     r1, #0                          @ any current owner?
+       beq     1f                              @ no: quit
+       teq     r0, #0                          @ any owner?
+       teqne   r1, r2                          @ or specified one?
+       bne     1f                              @ no: quit
+
+       ldr     r5, [r4, #0x80]                 @ enable access to crunch
+       mov     r2, #0xaa
+       str     r2, [r4, #0xc0]
+       orr     r5, r5, #0x00800000
+       str     r5, [r4, #0x80]
+
+       mov     r0, #0                          @ nothing to load
+       str     r0, [r3]                        @ no more current owner
+       ldr     r2, [r4, #0x80]                 @ flush out enable (@@@)
+       mov     r2, r2
+       bl      crunch_save
+
+       mov     r2, #0xaa                       @ disable access to crunch
+       str     r2, [r4, #0xc0]
+       bic     r5, r5, #0x00800000
+       str     r5, [r4, #0x80]
+       ldr     r5, [r4, #0x80]                 @ flush out enable (@@@)
+       mov     r5, r5
+
+1:     msr     cpsr_c, ip                      @ restore interrupt mode
+       ldmfd   sp!, {r4, r5, pc}
+
+/*
+ * Copy crunch state to given memory address
+ *
+ * r0 = struct thread_info pointer of target task
+ * r1 = memory address where to store crunch state
+ *
+ * this is called mainly in the creation of signal stack frames
+ */
+ENTRY(crunch_task_copy)
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r3, [r3]                        @ get current crunch owner
+       teq     r2, r3                          @ does this task own it...
+       beq     1f
+
+       @ current crunch values are in the task save area
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     r0, r1
+       mov     r1, r2
+       mov     r2, #CRUNCH_SIZE
+       b       memcpy
+
+1:     @ this task owns crunch regs -- grab a copy from there
+       mov     r0, #0                          @ nothing to load
+       mov     r3, lr                          @ preserve return address
+       bl      crunch_save
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     pc, r3
+
+/*
+ * Restore crunch state from given memory address
+ *
+ * r0 = struct thread_info pointer of target task
+ * r1 = memory address where to get crunch state from
+ *
+ * this is used to restore crunch state when unwinding a signal stack frame
+ */
+ENTRY(crunch_task_restore)
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r3, [r3]                        @ get current crunch owner
+       teq     r2, r3                          @ does this task own it...
+       beq     1f
+
+       @ this task doesn't own crunch regs -- use its save area
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     r0, r2
+       mov     r2, #CRUNCH_SIZE
+       b       memcpy
+
+1:     @ this task owns crunch regs -- load them directly
+       mov     r0, r1
+       mov     r1, #0                          @ nothing to save
+       mov     r3, lr                          @ preserve return address
+       bl      crunch_load
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     pc, r3
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
new file mode 100644 (file)
index 0000000..7481759
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * arch/arm/kernel/crunch.c
+ * Cirrus MaverickCrunch context switching and handling
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <asm/arch/ep93xx-regs.h>
+#include <asm/thread_notify.h>
+#include <asm/io.h>
+
+struct crunch_state *crunch_owner;
+
+void crunch_task_release(struct thread_info *thread)
+{
+       local_irq_disable();
+       if (crunch_owner == &thread->crunchstate)
+               crunch_owner = NULL;
+       local_irq_enable();
+}
+
+static int crunch_enabled(u32 devcfg)
+{
+       return !!(devcfg & EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE);
+}
+
+static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
+{
+       struct thread_info *thread = (struct thread_info *)t;
+       struct crunch_state *crunch_state;
+       u32 devcfg;
+
+       crunch_state = &thread->crunchstate;
+
+       switch (cmd) {
+       case THREAD_NOTIFY_FLUSH:
+               memset(crunch_state, 0, sizeof(*crunch_state));
+
+               /*
+                * FALLTHROUGH: Ensure we don't try to overwrite our newly
+                * initialised state information on the first fault.
+                */
+
+       case THREAD_NOTIFY_RELEASE:
+               crunch_task_release(thread);
+               break;
+
+       case THREAD_NOTIFY_SWITCH:
+               devcfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
+               if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
+                       devcfg ^= EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
+                       __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
+                       __raw_writel(devcfg, EP93XX_SYSCON_DEVICE_CONFIG);
+               }
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block crunch_notifier_block = {
+       .notifier_call  = crunch_do,
+};
+
+static int __init crunch_init(void)
+{
+       thread_register_notifier(&crunch_notifier_block);
+
+       return 0;
+}
+
+late_initcall(crunch_init);
index 86c92523a346704e7d94c7c1bc9660e5bc383aa6..6423a38839b8b4e86f6105399e209e00ce8f607c 100644 (file)
@@ -492,9 +492,15 @@ call_fpe:
        b       do_fpe                          @ CP#1 (FPE)
        b       do_fpe                          @ CP#2 (FPE)
        mov     pc, lr                          @ CP#3
+#ifdef CONFIG_CRUNCH
+       b       crunch_task_enable              @ CP#4 (MaverickCrunch)
+       b       crunch_task_enable              @ CP#5 (MaverickCrunch)
+       b       crunch_task_enable              @ CP#6 (MaverickCrunch)
+#else
        mov     pc, lr                          @ CP#4
        mov     pc, lr                          @ CP#5
        mov     pc, lr                          @ CP#6
+#endif
        mov     pc, lr                          @ CP#7
        mov     pc, lr                          @ CP#8
        mov     pc, lr                          @ CP#9
index a1d1b2906e8d60006090cdd62012c38f41352221..c40bdc770054c19b8a79e1f660211ec790b39274 100644 (file)
@@ -634,6 +634,32 @@ static int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp)
 
 #endif
 
+#ifdef CONFIG_CRUNCH
+/*
+ * Get the child Crunch state.
+ */
+static int ptrace_getcrunchregs(struct task_struct *tsk, void __user *ufp)
+{
+       struct thread_info *thread = task_thread_info(tsk);
+
+       crunch_task_disable(thread);  /* force it to ram */
+       return copy_to_user(ufp, &thread->crunchstate, CRUNCH_SIZE)
+               ? -EFAULT : 0;
+}
+
+/*
+ * Set the child Crunch state.
+ */
+static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp)
+{
+       struct thread_info *thread = task_thread_info(tsk);
+
+       crunch_task_release(thread);  /* force a reload */
+       return copy_from_user(&thread->crunchstate, ufp, CRUNCH_SIZE)
+               ? -EFAULT : 0;
+}
+#endif
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        unsigned long tmp;
@@ -765,6 +791,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        child->ptrace_message = data;
                        break;
 
+#ifdef CONFIG_CRUNCH
+               case PTRACE_GETCRUNCHREGS:
+                       ret = ptrace_getcrunchregs(child, (void __user *)data);
+                       break;
+
+               case PTRACE_SETCRUNCHREGS:
+                       ret = ptrace_setcrunchregs(child, (void __user *)data);
+                       break;
+#endif
+
                default:
                        ret = ptrace_request(child, request, addr, data);
                        break;
index 9fc9af88c60c72e54cad5e835c579b95027624e6..6bdf70def01f0c22390aeeba31db56cbd05be7e8 100644 (file)
@@ -119,9 +119,24 @@ DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
  * Standard memory resources
  */
 static struct resource mem_res[] = {
-       { "Video RAM",   0,     0,     IORESOURCE_MEM                   },
-       { "Kernel text", 0,     0,     IORESOURCE_MEM                   },
-       { "Kernel data", 0,     0,     IORESOURCE_MEM                   }
+       {
+               .name = "Video RAM",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .name = "Kernel text",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .name = "Kernel data",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       }
 };
 
 #define video_ram   mem_res[0]
@@ -129,9 +144,24 @@ static struct resource mem_res[] = {
 #define kernel_data mem_res[2]
 
 static struct resource io_res[] = {
-       { "reserved",    0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
-       { "reserved",    0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY },
-       { "reserved",    0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }
+       {
+               .name = "reserved",
+               .start = 0x3bc,
+               .end = 0x3be,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       },
+       {
+               .name = "reserved",
+               .start = 0x378,
+               .end = 0x37f,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       },
+       {
+               .name = "reserved",
+               .start = 0x278,
+               .end = 0x27f,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       }
 };
 
 #define lp0 io_res[0]
@@ -808,7 +838,7 @@ static int __init topology_init(void)
        int cpu;
 
        for_each_possible_cpu(cpu)
-               register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu, NULL);
+               register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu);
 
        return 0;
 }
index 1ce05ec086c6b40366a2d7aa349eef14af1b0410..83a8d3c95eb3ff458631412a96bf5ed6e4f1c742 100644 (file)
@@ -132,6 +132,37 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
        return ret;
 }
 
+#ifdef CONFIG_CRUNCH
+static int preserve_crunch_context(struct crunch_sigframe *frame)
+{
+       char kbuf[sizeof(*frame) + 8];
+       struct crunch_sigframe *kframe;
+
+       /* the crunch context must be 64 bit aligned */
+       kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
+       kframe->magic = CRUNCH_MAGIC;
+       kframe->size = CRUNCH_STORAGE_SIZE;
+       crunch_task_copy(current_thread_info(), &kframe->storage);
+       return __copy_to_user(frame, kframe, sizeof(*frame));
+}
+
+static int restore_crunch_context(struct crunch_sigframe *frame)
+{
+       char kbuf[sizeof(*frame) + 8];
+       struct crunch_sigframe *kframe;
+
+       /* the crunch context must be 64 bit aligned */
+       kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
+       if (__copy_from_user(kframe, frame, sizeof(*frame)))
+               return -1;
+       if (kframe->magic != CRUNCH_MAGIC ||
+           kframe->size != CRUNCH_STORAGE_SIZE)
+               return -1;
+       crunch_task_restore(current_thread_info(), &kframe->storage);
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_IWMMXT
 
 static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
@@ -214,6 +245,10 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
        err |= !valid_user_regs(regs);
 
        aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
+#ifdef CONFIG_CRUNCH
+       if (err == 0)
+               err |= restore_crunch_context(&aux->crunch);
+#endif
 #ifdef CONFIG_IWMMXT
        if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
                err |= restore_iwmmxt_context(&aux->iwmmxt);
@@ -333,6 +368,10 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
 
        aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
+#ifdef CONFIG_CRUNCH
+       if (err == 0)
+               err |= preserve_crunch_context(&aux->crunch);
+#endif
 #ifdef CONFIG_IWMMXT
        if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
                err |= preserve_iwmmxt_context(&aux->iwmmxt);
index 2b254e88595c76e15c233290e0f1339f04e5a621..2df9688a70282fca86ac0fb854a64da305961111 100644 (file)
@@ -80,6 +80,10 @@ SECTIONS
                *(.exit.text)
                *(.exit.data)
                *(.exitcall.exit)
+#ifndef CONFIG_MMU
+               *(.fixup)
+               *(__ex_table)
+#endif
        }
 
        .text : {                       /* Real text segment            */
@@ -87,7 +91,9 @@ SECTIONS
                        *(.text)
                        SCHED_TEXT
                        LOCK_TEXT
+#ifdef CONFIG_MMU
                        *(.fixup)
+#endif
                        *(.gnu.warning)
                        *(.rodata)
                        *(.rodata.*)
@@ -142,7 +148,9 @@ SECTIONS
                 */
                . = ALIGN(32);
                __start___ex_table = .;
+#ifdef CONFIG_MMU
                *(__ex_table)
+#endif
                __stop___ex_table = .;
 
                /*
index 7b726b627ea5ee38d85090774ab5d7f555d0c84c..30351cd4560dfcc7052a8be4eaa84620643878a3 100644 (file)
@@ -6,28 +6,31 @@
 
 lib-y          := backtrace.o changebit.o csumipv6.o csumpartial.o   \
                   csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
-                  copy_page.o delay.o findbit.o memchr.o memcpy.o    \
+                  delay.o findbit.o memchr.o memcpy.o                \
                   memmove.o memset.o memzero.o setbit.o              \
                   strncpy_from_user.o strnlen_user.o                 \
                   strchr.o strrchr.o                                 \
                   testchangebit.o testclearbit.o testsetbit.o        \
-                  getuser.o putuser.o clear_user.o                   \
                   ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
                   ucmpdi2.o lib1funcs.o div64.o sha1.o               \
                   io-readsb.o io-writesb.o io-readsl.o io-writesl.o
 
+mmu-y  := clear_user.o copy_page.o getuser.o putuser.o
+
 # the code in uaccess.S is not preemption safe and
 # probably faster on ARMv3 only
 ifeq ($(CONFIG_PREEMPT),y)
-  lib-y        += copy_from_user.o copy_to_user.o
+  mmu-y        += copy_from_user.o copy_to_user.o
 else
 ifneq ($(CONFIG_CPU_32v3),y)
-  lib-y        += copy_from_user.o copy_to_user.o
+  mmu-y        += copy_from_user.o copy_to_user.o
 else
-  lib-y        += uaccess.o
+  mmu-y        += uaccess.o
 endif
 endif
 
+lib-$(CONFIG_MMU) += $(mmu-y)
+
 ifeq ($(CONFIG_CPU_32v3),y)
   lib-y        += io-readsw-armv3.o io-writesw-armv3.o
 else
index 058b80d72aa1371a748b52cbee5b61c8653392b8..91f993f2e9dbdfd5786733dcaaec3e36ae26cf31 100644 (file)
@@ -97,16 +97,13 @@ ENTRY(c_backtrace)
                b       1007f
 
 /*
- * Fixup for LDMDB
+ * Fixup for LDMDB.  Note that this must not be in the fixup section.
  */
-               .section .fixup,"ax"
-               .align  0
 1007:          ldr     r0, =.Lbad
                mov     r1, frame
                bl      printk
                ldmfd   sp!, {r4 - r8, pc}
                .ltorg
-               .previous
                
                .section __ex_table,"a"
                .align  3
index ea435ae2e4a55738536413f48ce3b85f675576ba..ecb28dcdaf7b00704533a9241d64e3d65b9bde49 100644 (file)
 
                .text
 
-/* Prototype: int __arch_clear_user(void *addr, size_t sz)
+/* Prototype: int __clear_user(void *addr, size_t sz)
  * Purpose  : clear some user memory
  * Params   : addr - user memory address to clear
  *          : sz   - number of bytes to clear
  * Returns  : number of bytes NOT cleared
  */
-ENTRY(__arch_clear_user)
+ENTRY(__clear_user)
                stmfd   sp!, {r1, lr}
                mov     r2, #0
                cmp     r1, #4
index 7497393a0e814d588a07c3f4bcd9fe4d65b3a62f..6b7363ce749cd80a451315e3ba8b7e94e53f9eee 100644 (file)
@@ -16,7 +16,7 @@
 /*
  * Prototype:
  *
- *     size_t __arch_copy_from_user(void *to, const void *from, size_t n)
+ *     size_t __copy_from_user(void *to, const void *from, size_t n)
  *
  * Purpose:
  *
@@ -83,7 +83,7 @@
 
        .text
 
-ENTRY(__arch_copy_from_user)
+ENTRY(__copy_from_user)
 
 #include "copy_template.S"
 
index 4a6d8ea14022329444eb03535f0dd12058ccf89d..5224d94688d907caca22efec0794a9daee2a2211 100644 (file)
@@ -16,7 +16,7 @@
 /*
  * Prototype:
  *
- *     size_t __arch_copy_to_user(void *to, const void *from, size_t n)
+ *     size_t __copy_to_user(void *to, const void *from, size_t n)
  *
  * Purpose:
  *
@@ -86,7 +86,7 @@
 
        .text
 
-ENTRY(__arch_copy_to_user)
+ENTRY(__copy_to_user)
 
 #include "copy_template.S"
 
index 35649f04fcac3f6c2c0b53327a7399c3de46d7f0..36e3741a37729a59f8eb30e5d66ba3ab5e67fcbc 100644 (file)
@@ -20,7 +20,7 @@
  * returns the number of characters copied (strlen of copied string),
  *  -EFAULT on exception, or "len" if we fill the whole buffer
  */
-ENTRY(__arch_strncpy_from_user)
+ENTRY(__strncpy_from_user)
        mov     ip, r1
 1:     subs    r2, r2, #1
 USER(  ldrplbt r3, [r1], #1)
index 3668a15991efddda846e01e01aed9127c98b895b..18d8fa4f925a92c397006d7105d9fa8b7bc8c4d0 100644 (file)
        .text
        .align  5
 
-/* Prototype: unsigned long __arch_strnlen_user(const char *str, long n)
+/* Prototype: unsigned long __strnlen_user(const char *str, long n)
  * Purpose  : get length of a string in user memory
  * Params   : str - address of string in user memory
  * Returns  : length of string *including terminator*
  *           or zero on exception, or n + 1 if too long
  */
-ENTRY(__arch_strnlen_user)
+ENTRY(__strnlen_user)
        mov     r2, r0
 1:
 USER(  ldrbt   r3, [r0], #1)
index 1f1545d737be8b29ef3bccb9be3f752525f50f75..b48bd6d5fd83144ca4705becef558faadb33f725 100644 (file)
@@ -19,7 +19,7 @@
 
 #define PAGE_SHIFT 12
 
-/* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n)
+/* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
  * Purpose  : copy a block to user memory from kernel memory
  * Params   : to   - user memory
  *          : from - kernel memory
@@ -39,7 +39,7 @@ USER(         strgtbt r3, [r0], #1)                   @ May fault
                sub     r2, r2, ip
                b       .Lc2u_dest_aligned
 
-ENTRY(__arch_copy_to_user)
+ENTRY(__copy_to_user)
                stmfd   sp!, {r2, r4 - r7, lr}
                cmp     r2, #4
                blt     .Lc2u_not_enough
@@ -283,7 +283,7 @@ USER(               strgtbt r3, [r0], #1)                   @ May fault
 9001:          ldmfd   sp!, {r0, r4 - r7, pc}
                .previous
 
-/* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n);
+/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
  * Purpose  : copy a block from user memory to kernel memory
  * Params   : to   - kernel memory
  *          : from - user memory
@@ -302,7 +302,7 @@ USER(               ldrgtbt r3, [r1], #1)                   @ May fault
                sub     r2, r2, ip
                b       .Lcfu_dest_aligned
 
-ENTRY(__arch_copy_from_user)
+ENTRY(__copy_from_user)
                stmfd   sp!, {r0, r2, r4 - r7, lr}
                cmp     r2, #4
                blt     .Lcfu_not_enough
index cec5a21ca4e341593e5a6b4470a7cc903c111f70..e15e4c54a2538a53b50c238766d2ba3ac6598e44 100644 (file)
@@ -2,8 +2,19 @@ if ARCH_EP93XX
 
 menu "Cirrus EP93xx Implementation Options"
 
+config CRUNCH
+       bool "Support for MaverickCrunch"
+       help
+         Enable kernel support for MaverickCrunch.
+
 comment "EP93xx Platforms"
 
+config MACH_EDB9315
+       bool "Support Cirrus Logic EDB9315"
+       help
+         Say 'Y' here if you want your kernel to support the Cirrus
+         Logic EDB9315 Evaluation Board.
+
 config MACH_GESBC9312
        bool "Support Glomation GESBC-9312-sx"
        help
index 05a48a21038eadea89feffd7d33ab78f13544067..dfa7e2e8a18b65621d87eeab94c689d1990c14f2 100644 (file)
@@ -6,5 +6,6 @@ obj-m                   :=
 obj-n                  :=
 obj-                   :=
 
+obj-$(CONFIG_MACH_EDB9315)     += edb9315.o
 obj-$(CONFIG_MACH_GESBC9312)   += gesbc9312.o
 obj-$(CONFIG_MACH_TS72XX)      += ts72xx.o
diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c
new file mode 100644 (file)
index 0000000..ef7482f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * arch/arm/mach-ep93xx/edb9315.c
+ * Cirrus Logic EDB9315 support.
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static struct physmap_flash_data edb9315_flash_data = {
+       .width          = 4,
+};
+
+static struct resource edb9315_flash_resource = {
+       .start          = 0x60000000,
+       .end            = 0x61ffffff,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device edb9315_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &edb9315_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &edb9315_flash_resource,
+};
+
+static void __init edb9315_init_machine(void)
+{
+       ep93xx_init_devices();
+       platform_device_register(&edb9315_flash);
+}
+
+MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
+       /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb9315_init_machine,
+MACHINE_END
index 47cc6c8b7c79a1ca3e4ade460044149bbd212907..2c28d66d260ec7d1a7660278d3a77e99630ff51f 100644 (file)
@@ -30,7 +30,7 @@ static struct physmap_flash_data gesbc9312_flash_data = {
 
 static struct resource gesbc9312_flash_resource = {
        .start          = 0x60000000,
-       .end            = 0x60800000,
+       .end            = 0x607fffff,
        .flags          = IORESOURCE_MEM,
 };
 
index 6e5a56cd5ae872a9a7b69cb1d4c69debf28c73a9..0b3b875b1875221dd0695abd3150f4eacd401097 100644 (file)
@@ -118,7 +118,7 @@ static struct physmap_flash_data ts72xx_flash_data = {
 
 static struct resource ts72xx_flash_resource = {
        .start          = TS72XX_NOR_PHYS_BASE,
-       .end            = TS72XX_NOR_PHYS_BASE + 0x01000000,
+       .end            = TS72XX_NOR_PHYS_BASE + 0x00ffffff,
        .flags          = IORESOURCE_MEM,
 };
 
index dc5e489c70bc1144f60b13be9c90f214f2ea2b1f..357351fbb1e217fba6d6b833194b48a499cf3e4e 100644 (file)
@@ -59,7 +59,7 @@ static struct physmap_flash_data espresso_flash_data = {
 
 static struct resource espresso_flash_resource = {
        .start          = 0x90000000,
-       .end            = 0x92000000,
+       .end            = 0x91ffffff,
        .flags          = IORESOURCE_MEM,
 };
 
index 535b334ee045296b0df665f269a8a88ace6f7ef8..e0886871cc773d34effab66e4ca9e5be199b43cb 100644 (file)
@@ -304,7 +304,7 @@ static struct physmap_flash_data ixdp2351_flash_data = {
 
 static struct resource ixdp2351_flash_resource = {
        .start          = 0x90000000,
-       .end            = 0x94000000,
+       .end            = 0x93ffffff,
        .flags          = IORESOURCE_MEM,
 };
 
index b9f5d13fcfe126422528cf1502ed0a9f697bad01..92ad18f4125167f45e562922771c81fba3c7a168 100644 (file)
@@ -143,7 +143,7 @@ static struct physmap_flash_data roadrunner_flash_data = {
 
 static struct resource roadrunner_flash_resource = {
        .start          = 0x90000000,
-       .end            = 0x94000000,
+       .end            = 0x93ffffff,
        .flags          = IORESOURCE_MEM,
 };
 
index 539b596005fc266b2c49f8d0edfa22d7758b1b13..d9635ff4b10cb97bd979e7f8022dd346e929ae5e 100644 (file)
@@ -88,8 +88,8 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
 
        if (type == IRQT_PROBE) {
            /* Don't mess with enabled GPIOs using preconfigured edges or
-              GPIOs set to alternate function during probe */
-               if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
+              GPIOs set to alternate function or to output during probe */
+               if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx] | GPDR(gpio)) &
                    GPIO_bit(gpio))
                        return 0;
                if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
index 838bc525e83698c912c188104164d3fb6e48bbf1..9a2258270de9cb1e7e9d12b9b45b90f9092d3582 100644 (file)
@@ -69,6 +69,7 @@ void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
 
        s3c_device_i2c.name  = "s3c2440-i2c";
        s3c_device_nand.name = "s3c2440-nand";
+       s3c_device_usbgadget.name = "s3c2440-usbgadget";
 }
 
 void __init s3c244x_init_clocks(int xtal)
index ecf5e232a6fc2a3e0d6c419ca918933bdacd2fd3..c4bca753165bd2eec732ebe9515cbdc3fba1715a 100644 (file)
@@ -15,8 +15,8 @@ config CPU_ARM610
        select CPU_32v3
        select CPU_CACHE_V3
        select CPU_CACHE_VIVT
-       select CPU_COPY_V3
-       select CPU_TLB_V3
+       select CPU_COPY_V3 if MMU
+       select CPU_TLB_V3 if MMU
        help
          The ARM610 is the successor to the ARM3 processor
          and was produced by VLSI Technology Inc.
@@ -31,8 +31,8 @@ config CPU_ARM710
        select CPU_32v3
        select CPU_CACHE_V3
        select CPU_CACHE_VIVT
-       select CPU_COPY_V3
-       select CPU_TLB_V3
+       select CPU_COPY_V3 if MMU
+       select CPU_TLB_V3 if MMU
        help
          A 32-bit RISC microprocessor based on the ARM7 processor core
          designed by Advanced RISC Machines Ltd. The ARM710 is the
@@ -50,8 +50,8 @@ config CPU_ARM720T
        select CPU_ABRT_LV4T
        select CPU_CACHE_V4
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WT
-       select CPU_TLB_V4WT
+       select CPU_COPY_V4WT if MMU
+       select CPU_TLB_V4WT if MMU
        help
          A 32-bit RISC processor with 8kByte Cache, Write Buffer and
          MMU built around an ARM7TDMI core.
@@ -68,8 +68,8 @@ config CPU_ARM920T
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM920T is licensed to be produced by numerous vendors,
          and is used in the Maverick EP9312 and the Samsung S3C2410.
@@ -89,8 +89,8 @@ config CPU_ARM922T
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM922T is a version of the ARM920T, but with smaller
          instruction and data caches. It is used in Altera's
@@ -108,8 +108,8 @@ config CPU_ARM925T
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM925T is a mix between the ARM920T and ARM926T, but with
          different instruction and data caches. It is used in TI's OMAP
@@ -126,8 +126,8 @@ config CPU_ARM926T
        select CPU_32v5
        select CPU_ABRT_EV5TJ
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          This is a variant of the ARM920.  It has slightly different
          instruction sequences for cache and TLB operations.  Curiously,
@@ -144,8 +144,8 @@ config CPU_ARM1020
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM1020 is the 32K cached version of the ARM10 processor,
          with an addition of a floating-point unit.
@@ -161,8 +161,8 @@ config CPU_ARM1020E
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        depends on n
 
 # ARM1022E
@@ -172,8 +172,8 @@ config CPU_ARM1022
        select CPU_32v5
        select CPU_ABRT_EV4T
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB # can probably do better
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU # can probably do better
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM1022E is an implementation of the ARMv5TE architecture
          based upon the ARM10 integer core with a 16KiB L1 Harvard cache,
@@ -189,8 +189,8 @@ config CPU_ARM1026
        select CPU_32v5
        select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB # can probably do better
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU # can probably do better
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM1026EJ-S is an implementation of the ARMv5TEJ architecture
          based upon the ARM10 integer core.
@@ -207,8 +207,8 @@ config CPU_SA110
        select CPU_ABRT_EV4
        select CPU_CACHE_V4WB
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WB
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WB if MMU
        help
          The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and
          is available at five speeds ranging from 100 MHz to 233 MHz.
@@ -227,7 +227,7 @@ config CPU_SA1100
        select CPU_ABRT_EV4
        select CPU_CACHE_V4WB
        select CPU_CACHE_VIVT
-       select CPU_TLB_V4WB
+       select CPU_TLB_V4WB if MMU
 
 # XScale
 config CPU_XSCALE
@@ -237,7 +237,7 @@ config CPU_XSCALE
        select CPU_32v5
        select CPU_ABRT_EV5T
        select CPU_CACHE_VIVT
-       select CPU_TLB_V4WBI
+       select CPU_TLB_V4WBI if MMU
 
 # XScale Core Version 3
 config CPU_XSC3
@@ -247,7 +247,7 @@ config CPU_XSC3
        select CPU_32v5
        select CPU_ABRT_EV5T
        select CPU_CACHE_VIVT
-       select CPU_TLB_V4WBI
+       select CPU_TLB_V4WBI if MMU
        select IO_36
 
 # ARMv6
@@ -258,8 +258,8 @@ config CPU_V6
        select CPU_ABRT_EV6
        select CPU_CACHE_V6
        select CPU_CACHE_VIPT
-       select CPU_COPY_V6
-       select CPU_TLB_V6
+       select CPU_COPY_V6 if MMU
+       select CPU_TLB_V6 if MMU
 
 # ARMv6k
 config CPU_32v6K
@@ -277,17 +277,17 @@ config CPU_32v6K
 # This defines the compiler instruction set which depends on the machine type.
 config CPU_32v3
        bool
-       select TLS_REG_EMUL if SMP
+       select TLS_REG_EMUL if SMP || !MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 
 config CPU_32v4
        bool
-       select TLS_REG_EMUL if SMP
+       select TLS_REG_EMUL if SMP || !MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 
 config CPU_32v5
        bool
-       select TLS_REG_EMUL if SMP
+       select TLS_REG_EMUL if SMP || !MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 
 config CPU_32v6
@@ -334,6 +334,7 @@ config CPU_CACHE_VIVT
 config CPU_CACHE_VIPT
        bool
 
+if MMU
 # The copy-page model
 config CPU_COPY_V3
        bool
@@ -372,6 +373,8 @@ config CPU_TLB_V4WBI
 config CPU_TLB_V6
        bool
 
+endif
+
 #
 # CPU supports 36-bit I/O
 #
index 07a538505784068f949759f12e2dbec2253a1dd8..21a2770226ee418e9756d2a6663a255850352333 100644 (file)
@@ -2,10 +2,16 @@
 # Makefile for the linux arm-specific parts of the memory manager.
 #
 
-obj-y                          := consistent.o extable.o fault-armv.o \
-                                  fault.o flush.o init.o ioremap.o mmap.o \
+obj-y                          := consistent.o extable.o fault.o init.o \
+                                  iomap.o
+
+obj-$(CONFIG_MMU)              += fault-armv.o flush.o ioremap.o mmap.o \
                                   mm-armv.o
 
+ifneq ($(CONFIG_MMU),y)
+obj-y                          += nommu.o
+endif
+
 obj-$(CONFIG_MODULES)          += proc-syms.o
 
 obj-$(CONFIG_ALIGNMENT_TRAP)   += alignment.o
index 9ea1f87a7079b863ee4d061103ef46b2aa00fa9b..989fd681c822de5be93e6d66fe1676423e87b6a6 100644 (file)
@@ -26,8 +26,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#define TABLE_SIZE     (2 * PTRS_PER_PTE * sizeof(pte_t))
-
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff --git a/arch/arm/mm/iomap.c b/arch/arm/mm/iomap.c
new file mode 100644 (file)
index 0000000..62066f3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  linux/arch/arm/mm/iomap.c
+ *
+ * Map IO port and PCI memory spaces so that {read,write}[bwl] can
+ * be used to access this memory.
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+
+#ifdef __io
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+       return __io(port);
+}
+EXPORT_SYMBOL(ioport_map);
+
+void ioport_unmap(void __iomem *addr)
+{
+}
+EXPORT_SYMBOL(ioport_unmap);
+#endif
+
+#ifdef CONFIG_PCI
+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 (maxlen && len > maxlen)
+               len = maxlen;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM) {
+               if (flags & IORESOURCE_CACHEABLE)
+                       return ioremap(start, len);
+               return ioremap_nocache(start, len);
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       if ((unsigned long)addr >= VMALLOC_START &&
+           (unsigned long)addr < VMALLOC_END)
+               iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
+#endif
index c1f7180c7beda07ff35d3211880902b8a83c2a2c..7691cfdba56778d7f97768b66c243e66eb735dc2 100644 (file)
@@ -176,50 +176,3 @@ void __iounmap(void __iomem *addr)
        vunmap((void *)(PAGE_MASK & (unsigned long)addr));
 }
 EXPORT_SYMBOL(__iounmap);
-
-#ifdef __io
-void __iomem *ioport_map(unsigned long port, unsigned int nr)
-{
-       return __io(port);
-}
-EXPORT_SYMBOL(ioport_map);
-
-void ioport_unmap(void __iomem *addr)
-{
-}
-EXPORT_SYMBOL(ioport_unmap);
-#endif
-
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#include <linux/ioport.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 (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-       return NULL;
-}
-EXPORT_SYMBOL(pci_iomap);
-
-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
-{
-       if ((unsigned long)addr >= VMALLOC_START &&
-           (unsigned long)addr < VMALLOC_END)
-               iounmap(addr);
-}
-EXPORT_SYMBOL(pci_iounmap);
-#endif
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
new file mode 100644 (file)
index 0000000..1464ed8
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  linux/arch/arm/mm/nommu.c
+ *
+ * ARM uCLinux supporting functions.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/page.h>
+
+void flush_dcache_page(struct page *page)
+{
+       __cpuc_flush_dcache_page(page_address(page));
+}
+EXPORT_SYMBOL(flush_dcache_page);
+
+void __iomem *__ioremap_pfn(unsigned long pfn, unsigned long offset,
+                           size_t size, unsigned long flags)
+{
+       if (pfn >= (0x100000000ULL >> PAGE_SHIFT))
+               return NULL;
+       return (void __iomem *) (offset + (pfn << PAGE_SHIFT));
+}
+EXPORT_SYMBOL(__ioremap_pfn);
+
+void __iomem *__ioremap(unsigned long phys_addr, size_t size,
+                       unsigned long flags)
+{
+       return (void __iomem *)phys_addr;
+}
+EXPORT_SYMBOL(__ioremap);
+
+void __iounmap(void __iomem *addr)
+{
+}
+EXPORT_SYMBOL(__iounmap);
index 959588884fa5ea38afe966938120370dff0ce05f..b9abbafca81225c5c6295438d49147c89b5f7860 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -101,7 +102,9 @@ ENTRY(cpu_arm1020_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -359,6 +362,7 @@ ENTRY(cpu_arm1020_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm1020_switch_mm)
+#ifdef CONFIG_MMU
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r3, c7, c10, 4
        mov     r1, #0xF                        @ 16 segments
@@ -383,6 +387,7 @@ ENTRY(cpu_arm1020_switch_mm)
        mcr     p15, 0, r1, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+#endif /* CONFIG_MMU */
        mov     pc, lr
         
 /*
@@ -392,6 +397,7 @@ ENTRY(cpu_arm1020_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm1020_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -421,6 +427,7 @@ ENTRY(cpu_arm1020_set_pte)
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -430,7 +437,9 @@ __arm1020_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm1020_cr1_clear
        bic     r0, r0, r5
index be6d081ff2b71219d672e28b141c9cb93e32edb8..bcd5ee022e00ae36bde2c50362fdd81114ee3107 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -101,7 +102,9 @@ ENTRY(cpu_arm1020e_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -344,6 +347,7 @@ ENTRY(cpu_arm1020e_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm1020e_switch_mm)
+#ifdef CONFIG_MMU
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r3, c7, c10, 4
        mov     r1, #0xF                        @ 16 segments
@@ -367,6 +371,7 @@ ENTRY(cpu_arm1020e_switch_mm)
        mcr     p15, 0, r1, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
         
 /*
@@ -376,6 +381,7 @@ ENTRY(cpu_arm1020e_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm1020e_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -403,6 +409,7 @@ ENTRY(cpu_arm1020e_set_pte)
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -412,7 +419,9 @@ __arm1020e_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm1020e_cr1_clear
        bic     r0, r0, r5
index f778545d57a2d9825805417a8677cb8a41c5eed2..b0ccff4fadd2559912e5edf50483369726f7fd3a 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -90,7 +91,9 @@ ENTRY(cpu_arm1022_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -333,6 +336,7 @@ ENTRY(cpu_arm1022_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm1022_switch_mm)
+#ifdef CONFIG_MMU
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mov     r1, #(CACHE_DSEGMENTS - 1) << 5 @ 16 segments
 1:     orr     r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
@@ -349,6 +353,7 @@ ENTRY(cpu_arm1022_switch_mm)
        mcr     p15, 0, r1, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
         
 /*
@@ -358,6 +363,7 @@ ENTRY(cpu_arm1022_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm1022_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -385,6 +391,7 @@ ENTRY(cpu_arm1022_set_pte)
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -394,7 +401,9 @@ __arm1022_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm1022_cr1_clear
        bic     r0, r0, r5
index 148c111fde732b4b41b83bfe513949a0647cf77a..abe850c9a641ef0ef6074eaaabeb8484852a2929 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -90,7 +91,9 @@ ENTRY(cpu_arm1026_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -327,6 +330,7 @@ ENTRY(cpu_arm1026_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm1026_switch_mm)
+#ifdef CONFIG_MMU
        mov     r1, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
 1:     mrc     p15, 0, r15, c7, c14, 3         @ test, clean, invalidate
@@ -338,6 +342,7 @@ ENTRY(cpu_arm1026_switch_mm)
        mcr     p15, 0, r1, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
         
 /*
@@ -347,6 +352,7 @@ ENTRY(cpu_arm1026_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm1026_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -374,6 +380,7 @@ ENTRY(cpu_arm1026_set_pte)
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
 
@@ -384,8 +391,10 @@ __arm1026_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
        mcr     p15, 0, r4, c2, c0              @ load page table pointer
+#endif
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mov     r0, #4                          @ explicitly disable writeback
        mcr     p15, 7, r0, c15, c0, 0
index 540359b475d07d0a293467c870911885adab9e6a..7a705edfa4b22461e68106dca194c7d831d5eb70 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/proc-arm6,7.S
  *
  *  Copyright (C) 1997-2000 Russell King
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * 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
@@ -199,10 +200,12 @@ ENTRY(cpu_arm7_do_idle)
  */
 ENTRY(cpu_arm6_switch_mm)
 ENTRY(cpu_arm7_switch_mm)
+#ifdef CONFIG_MMU
                mov     r1, #0
                mcr     p15, 0, r1, c7, c0, 0           @ flush cache
                mcr     p15, 0, r0, c2, c0, 0           @ update page table ptr
                mcr     p15, 0, r1, c5, c0, 0           @ flush TLBs
+#endif
                mov     pc, lr
 
 /*
@@ -214,6 +217,7 @@ ENTRY(cpu_arm7_switch_mm)
                .align  5
 ENTRY(cpu_arm6_set_pte)
 ENTRY(cpu_arm7_set_pte)
+#ifdef CONFIG_MMU
                str     r1, [r0], #-2048                @ linux version
 
                eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -232,6 +236,7 @@ ENTRY(cpu_arm7_set_pte)
                movne   r2, #0
 
                str     r2, [r0]                        @ hardware version
+#endif /* CONFIG_MMU */
                mov     pc, lr
 
 /*
@@ -243,7 +248,9 @@ ENTRY(cpu_arm6_reset)
 ENTRY(cpu_arm7_reset)
                mov     r1, #0
                mcr     p15, 0, r1, c7, c0, 0           @ flush cache
+#ifdef CONFIG_MMU
                mcr     p15, 0, r1, c5, c0, 0           @ flush TLB
+#endif
                mov     r1, #0x30
                mcr     p15, 0, r1, c1, c0, 0           @ turn off MMU etc
                mov     pc, r0
@@ -253,19 +260,27 @@ ENTRY(cpu_arm7_reset)
                .type   __arm6_setup, #function
 __arm6_setup:  mov     r0, #0
                mcr     p15, 0, r0, c7, c0              @ flush caches on v3
+#ifdef CONFIG_MMU
                mcr     p15, 0, r0, c5, c0              @ flush TLBs on v3
                mov     r0, #0x3d                       @ . ..RS BLDP WCAM
                orr     r0, r0, #0x100                  @ . ..01 0011 1101
+#else
+               mov     r0, #0x3c                       @ . ..RS BLDP WCA.
+#endif
                mov     pc, lr
                .size   __arm6_setup, . - __arm6_setup
 
                .type   __arm7_setup, #function
 __arm7_setup:  mov     r0, #0
                mcr     p15, 0, r0, c7, c0              @ flush caches on v3
+#ifdef CONFIG_MMU
                mcr     p15, 0, r0, c5, c0              @ flush TLBs on v3
                mcr     p15, 0, r0, c3, c0              @ load domain access register
                mov     r0, #0x7d                       @ . ..RS BLDP WCAM
                orr     r0, r0, #0x100                  @ . ..01 0111 1101
+#else
+               mov     r0, #0x7c                       @ . ..RS BLDP WCA.
+#endif
                mov     pc, lr
                .size   __arm7_setup, . - __arm7_setup
 
index 26f00ee2ad9a308f79e4f00a75b177535d20a480..86102467d37f98fedf2ff9e75a83f2e3430dd795 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
  *                     Rob Scott (rscott@mtrob.fdns.net)
  *  Copyright (C) 2000 ARM Limited, Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2004.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,6 +30,7 @@
  *                     out of 'proc-arm6,7.S' per RMK discussion
  *   07-25-2000 SJH    Added idle function.
  *   08-25-2000        DBS     Updated for integration of ARM Ltd version.
+ *   04-20-2004 HSC    modified for non-paged memory management mode.
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
@@ -75,10 +77,12 @@ ENTRY(cpu_arm720_do_idle)
  *          the new.
  */
 ENTRY(cpu_arm720_switch_mm)
+#ifdef CONFIG_MMU
                mov     r1, #0
                mcr     p15, 0, r1, c7, c7, 0           @ invalidate cache
                mcr     p15, 0, r0, c2, c0, 0           @ update page table ptr
                mcr     p15, 0, r1, c8, c7, 0           @ flush TLB (v4)
+#endif
                mov     pc, lr
 
 /*
@@ -89,6 +93,7 @@ ENTRY(cpu_arm720_switch_mm)
  */
                .align  5
 ENTRY(cpu_arm720_set_pte)
+#ifdef CONFIG_MMU
                str     r1, [r0], #-2048                @ linux version
 
                eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -107,6 +112,7 @@ ENTRY(cpu_arm720_set_pte)
                movne   r2, #0
 
                str     r2, [r0]                        @ hardware version
+#endif
                mov     pc, lr
 
 /*
@@ -117,7 +123,9 @@ ENTRY(cpu_arm720_set_pte)
 ENTRY(cpu_arm720_reset)
                mov     ip, #0
                mcr     p15, 0, ip, c7, c7, 0           @ invalidate cache
+#ifdef CONFIG_MMU
                mcr     p15, 0, ip, c8, c7, 0           @ flush TLB (v4)
+#endif
                mrc     p15, 0, ip, c1, c0, 0           @ get ctrl register
                bic     ip, ip, #0x000f                 @ ............wcam
                bic     ip, ip, #0x2100                 @ ..v....s........
@@ -130,7 +138,9 @@ ENTRY(cpu_arm720_reset)
 __arm710_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7, 0           @ invalidate caches
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7, 0           @ flush TLB (v4)
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register
        ldr     r5, arm710_cr1_clear
        bic     r0, r0, r5
@@ -156,7 +166,9 @@ arm710_cr1_set:
 __arm720_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7, 0           @ invalidate caches
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7, 0           @ flush TLB (v4)
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register
        ldr     r5, arm720_cr1_clear
        bic     r0, r0, r5
index a17f79e0199c9ea0160ff2a987267e18fc26dd0b..31dc839ba07c9557ff0dae53de0827b345e870cd 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1999,2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -97,7 +98,9 @@ ENTRY(cpu_arm920_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -317,6 +320,7 @@ ENTRY(cpu_arm920_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm920_switch_mm)
+#ifdef CONFIG_MMU
        mov     ip, #0
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
@@ -337,6 +341,7 @@ ENTRY(cpu_arm920_switch_mm)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
 
 /*
@@ -346,6 +351,7 @@ ENTRY(cpu_arm920_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm920_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -372,6 +378,7 @@ ENTRY(cpu_arm920_set_pte)
        mov     r0, r0
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -381,7 +388,9 @@ __arm920_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm920_cr1_clear
        bic     r0, r0, r5
index bbde4a024a4848ca73014a7ddb01844f6481111c..9e57c34f5c098532c044aa2b1f1c02faa6aa3610 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1999,2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
  *  Copyright (C) 2001 Altera Corporation
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -99,7 +100,9 @@ ENTRY(cpu_arm922_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -321,6 +324,7 @@ ENTRY(cpu_arm922_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm922_switch_mm)
+#ifdef CONFIG_MMU
        mov     ip, #0
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
@@ -341,6 +345,7 @@ ENTRY(cpu_arm922_switch_mm)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
 
 /*
@@ -350,6 +355,7 @@ ENTRY(cpu_arm922_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm922_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -376,6 +382,7 @@ ENTRY(cpu_arm922_set_pte)
        mov     r0, r0
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -385,7 +392,9 @@ __arm922_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm922_cr1_clear
        bic     r0, r0, r5
index 224ce226a01bc24f5c561dd7b0680c5970803d34..8d47c9f3f931b1aaa1381d5ad15347899fddfeb7 100644 (file)
@@ -9,6 +9,8 @@
  *  Update for Linux-2.6 and cache flush improvements
  *  Copyright (C) 2004 Nokia Corporation by Tony Lindgren <tony@atomide.com>
  *
+ *  hacked for non-paged-MM by Hyok S. Choi, 2004.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -122,7 +124,9 @@ ENTRY(cpu_arm925_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -369,6 +373,7 @@ ENTRY(cpu_arm925_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm925_switch_mm)
+#ifdef CONFIG_MMU
        mov     ip, #0
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
@@ -383,6 +388,7 @@ ENTRY(cpu_arm925_switch_mm)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
 
 /*
@@ -392,6 +398,7 @@ ENTRY(cpu_arm925_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm925_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -420,6 +427,7 @@ ENTRY(cpu_arm925_set_pte)
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -438,7 +446,9 @@ __arm925_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
 
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mov     r0, #4                          @ disable write-back on caches explicitly
index 4e2a087cf3889599225483bb353b29931bdc4886..cb4d8f33d2a3ff4b02146e2475ab8e22e9affbf8 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1999-2001 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -85,7 +86,9 @@ ENTRY(cpu_arm926_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -329,6 +332,7 @@ ENTRY(cpu_arm926_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm926_switch_mm)
+#ifdef CONFIG_MMU
        mov     ip, #0
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
@@ -341,6 +345,7 @@ ENTRY(cpu_arm926_switch_mm)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
 
 /*
@@ -350,6 +355,7 @@ ENTRY(cpu_arm926_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm926_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -378,6 +384,7 @@ ENTRY(cpu_arm926_set_pte)
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif
        mov     pc, lr
 
        __INIT
@@ -387,7 +394,9 @@ __arm926_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
 
 
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
index a2dd5ae1077dda0c5257a768a6d69c880c0781af..5a760a2c629c11681d072e2d547e791ab1ebb7f1 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/proc-sa110.S
  *
  *  Copyright (C) 1997-2002 Russell King
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * 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
@@ -67,7 +68,9 @@ ENTRY(cpu_sa110_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -130,11 +133,15 @@ ENTRY(cpu_sa110_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_sa110_switch_mm)
+#ifdef CONFIG_MMU
        str     lr, [sp, #-4]!
        bl      v4wb_flush_kern_cache_all       @ clears IP
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
        ldr     pc, [sp], #4
+#else
+       mov     pc, lr
+#endif
 
 /*
  * cpu_sa110_set_pte(ptep, pte)
@@ -143,6 +150,7 @@ ENTRY(cpu_sa110_switch_mm)
  */
        .align  5
 ENTRY(cpu_sa110_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -164,6 +172,7 @@ ENTRY(cpu_sa110_set_pte)
        mov     r0, r0
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif
        mov     pc, lr
 
        __INIT
@@ -173,7 +182,9 @@ __sa110_setup:
        mov     r10, #0
        mcr     p15, 0, r10, c7, c7             @ invalidate I,D caches on v4
        mcr     p15, 0, r10, c7, c10, 4         @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r10, c8, c7             @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, sa110_cr1_clear
        bic     r0, r0, r5
index 777ad99c14395584690dfc32cd3c297540edca16..0a2107ad4c32f8750b52cf9424e3c69bb34f685f 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/proc-sa1100.S
  *
  *  Copyright (C) 1997-2002 Russell King
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * 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
@@ -77,7 +78,9 @@ ENTRY(cpu_sa1100_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -142,12 +145,16 @@ ENTRY(cpu_sa1100_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_sa1100_switch_mm)
+#ifdef CONFIG_MMU
        str     lr, [sp, #-4]!
        bl      v4wb_flush_kern_cache_all       @ clears IP
        mcr     p15, 0, ip, c9, c0, 0           @ invalidate RB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
        ldr     pc, [sp], #4
+#else
+       mov     pc, lr
+#endif
 
 /*
  * cpu_sa1100_set_pte(ptep, pte)
@@ -156,6 +163,7 @@ ENTRY(cpu_sa1100_switch_mm)
  */
        .align  5
 ENTRY(cpu_sa1100_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -177,6 +185,7 @@ ENTRY(cpu_sa1100_set_pte)
        mov     r0, r0
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif
        mov     pc, lr
 
        __INIT
@@ -186,7 +195,9 @@ __sa1100_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, sa1100_cr1_clear
        bic     r0, r0, r5
index 09b1a41a6de887f0afd3ebf8e9dbf520b51018c4..ca13d4d05f6551e13fae4d9148fa7c7664e3da08 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/proc-v6.S
  *
  *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *  Modified by Catalin Marinas for noMMU support
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -88,6 +89,7 @@ ENTRY(cpu_v6_dcache_clean_area)
  *     - we are not using split page tables
  */
 ENTRY(cpu_v6_switch_mm)
+#ifdef CONFIG_MMU
        mov     r2, #0
        ldr     r1, [r1, #MM_CONTEXT_ID]        @ get mm->context.id
 #ifdef CONFIG_SMP
@@ -97,6 +99,7 @@ ENTRY(cpu_v6_switch_mm)
        mcr     p15, 0, r2, c7, c10, 4          @ drain write buffer
        mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
        mcr     p15, 0, r1, c13, c0, 1          @ set context ID
+#endif
        mov     pc, lr
 
 /*
@@ -119,6 +122,7 @@ ENTRY(cpu_v6_switch_mm)
  *       1111   0   1   1      r/w     r/w
  */
 ENTRY(cpu_v6_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        bic     r2, r1, #0x000003f0
@@ -145,6 +149,7 @@ ENTRY(cpu_v6_set_pte)
 
        str     r2, [r0]
        mcr     p15, 0, r0, c7, c10, 1 @ flush_pte
+#endif
        mov     pc, lr
 
 
@@ -194,12 +199,14 @@ __v6_setup:
        mcr     p15, 0, r0, c7, c5, 0           @ invalidate I cache
        mcr     p15, 0, r0, c7, c15, 0          @ clean+invalidate cache
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7, 0           @ invalidate I + D TLBs
        mcr     p15, 0, r0, c2, c0, 2           @ TTB control register
 #ifdef CONFIG_SMP
        orr     r4, r4, #TTB_RGN_WBWA|TTB_S     @ mark PTWs shared, outer cacheable
 #endif
        mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
+#endif /* CONFIG_MMU */
 #ifdef CONFIG_VFP
        mrc     p15, 0, r0, c1, c0, 2
        orr     r0, r0, #(0xf << 20)
index 856b665020e770d8a464e40a74cd91a7f5649b7e..6a1238a29d6c4d98d46156a1863e4a342478d7db 100644 (file)
@@ -28,6 +28,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config IRQ_PER_CPU
+       bool
+       default y
+
 config CRIS
        bool
        default y
index 4b368a122015288dc1b04b9248f19ca8eefbb106..2d5be93b5197c202d37d41d0a4d6334fa0a271a0 100644 (file)
@@ -172,7 +172,7 @@ init_IRQ(void)
 
        /* Initialize IRQ handler descriptiors. */
        for(i = 2; i < NR_IRQS; i++) {
-               irq_desc[i].handler = &crisv10_irq_type;
+               irq_desc[i].chip = &crisv10_irq_type;
                set_int_vector(i, interrupt[i]);
        }
 
index 1e9d062103aec24a993c8c0e4263e4e9778df9a3..a2b9c60c2777e6cf39b94b0789fccf15307ced19 100644 (file)
@@ -43,10 +43,10 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                      resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index c78cc2685133727f32bc3e6d514b08caf79f2aca..06260874f018f4ff7d5a9d1f8d07cf8ba2e6ca11 100644 (file)
@@ -369,7 +369,7 @@ init_IRQ(void)
 
        /* Point all IRQ's to bad handlers. */
        for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
-               irq_desc[j].handler = &crisv32_irq_type;
+               irq_desc[j].chip = &crisv32_irq_type;
                set_exception_vector(i, interrupt[j]);
        }
 
index b504def3e346944cc65fad1a5b55cc391f145eb1..6547bb64636419de268dadcccea8d7b89c84c425 100644 (file)
@@ -69,7 +69,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index 0a26bf6f1cd4280ecd682d6de6a6f0c3c2ddd97c..4f165c93be424545ebcad65ee1d2b10be477f7fe 100644 (file)
@@ -64,10 +64,10 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
  */
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                      resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index 47c08bcd9b24f313e2216d88b97e7e2e58958078..0463f63359051f90bbf4b0c86a9d984ac3d36d1f 100644 (file)
@@ -233,7 +233,7 @@ config NR_CPUS
 
 config SCHED_SMT
        bool "SMT (Hyperthreading) scheduler support"
-       depends on SMP
+       depends on X86_HT
        help
          SMT scheduler support improves the CPU scheduler's decision making
          when dealing with Intel Pentium 4 chips with HyperThreading at a
@@ -242,7 +242,7 @@ config SCHED_SMT
 
 config SCHED_MC
        bool "Multi-core scheduler support"
-       depends on SMP
+       depends on X86_HT
        default y
        help
          Multi-core scheduler support improves the CPU scheduler's decision
@@ -529,6 +529,7 @@ config X86_PAE
        bool
        depends on HIGHMEM64G
        default y
+       select RESOURCES_64BIT
 
 # Common NUMA Features
 config NUMA
@@ -780,9 +781,23 @@ config HOTPLUG_CPU
          enable suspend on SMP systems. CPUs can be controlled through
          /sys/devices/system/cpu.
 
+config COMPAT_VDSO
+       bool "Compat VDSO support"
+       default y
+       help
+         Map the VDSO to the predictable old-style address too.
+       ---help---
+         Say N here if you are running a sufficiently recent glibc
+         version (2.3.3 or later), to remove the high-mapped
+         VDSO mapping and to exclusively use the randomized VDSO.
+
+         If unsure, say Y.
 
 endmenu
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
+       depends on HIGHMEM
 
 menu "Power management options (ACPI, APM)"
        depends on !X86_VOYAGER
index 1c3a809e64217292de3d4ab009b32d9953c0ee19..c80271f8f084c04014d926185cbe896a86fe8d9e 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/fixmap.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/elf.h>
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -54,6 +55,7 @@ void foo(void)
        OFFSET(TI_preempt_count, thread_info, preempt_count);
        OFFSET(TI_addr_limit, thread_info, addr_limit);
        OFFSET(TI_restart_block, thread_info, restart_block);
+       OFFSET(TI_sysenter_return, thread_info, sysenter_return);
        BLANK();
 
        OFFSET(EXEC_DOMAIN_handler, exec_domain, handler);
@@ -69,7 +71,7 @@ void foo(void)
                 sizeof(struct tss_struct));
 
        DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
-       DEFINE(VSYSCALL_BASE, __fix_to_virt(FIX_VSYSCALL));
+       DEFINE(VDSO_PRELINK, VDSO_PRELINK);
 
        OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
 }
index fd0457c9c827f406e9e7f35d490bf7c0c648fe01..e6a2d6b80cdae8a84e72566da1642bff59a7dc7a 100644 (file)
@@ -235,10 +235,10 @@ static void __init init_amd(struct cpuinfo_x86 *c)
                        while ((1 << bits) < c->x86_max_cores)
                                bits++;
                }
-               cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
-               phys_proc_id[cpu] >>= bits;
+               c->cpu_core_id = c->phys_proc_id & ((1<<bits)-1);
+               c->phys_proc_id >>= bits;
                printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
-                      cpu, c->x86_max_cores, cpu_core_id[cpu]);
+                      cpu, c->x86_max_cores, c->cpu_core_id);
        }
 #endif
 
index 44f2c5f2dda16a0b8adcb6d0170fd92951a7307e..70c87de582c7a793ab346b60c4416bcdaa3a9f2c 100644 (file)
@@ -294,7 +294,7 @@ void __cpuinit generic_identify(struct cpuinfo_x86 * c)
                        if (c->x86 >= 0x6)
                                c->x86_model += ((tfms >> 16) & 0xF) << 4;
                        c->x86_mask = tfms & 15;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
                        c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);
 #else
                        c->apicid = (ebx >> 24) & 0xFF;
@@ -319,7 +319,7 @@ void __cpuinit generic_identify(struct cpuinfo_x86 * c)
        early_intel_workaround(c);
 
 #ifdef CONFIG_X86_HT
-       phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+       c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
 #endif
 }
 
@@ -477,11 +477,9 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
 {
        u32     eax, ebx, ecx, edx;
        int     index_msb, core_bits;
-       int     cpu = smp_processor_id();
 
        cpuid(1, &eax, &ebx, &ecx, &edx);
 
-
        if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
                return;
 
@@ -492,16 +490,17 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
        } else if (smp_num_siblings > 1 ) {
 
                if (smp_num_siblings > NR_CPUS) {
-                       printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
+                       printk(KERN_WARNING "CPU: Unsupported number of the "
+                                       "siblings %d", smp_num_siblings);
                        smp_num_siblings = 1;
                        return;
                }
 
                index_msb = get_count_order(smp_num_siblings);
-               phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
+               c->phys_proc_id = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
 
                printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-                      phys_proc_id[cpu]);
+                      c->phys_proc_id);
 
                smp_num_siblings = smp_num_siblings / c->x86_max_cores;
 
@@ -509,12 +508,12 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
 
                core_bits = get_count_order(c->x86_max_cores);
 
-               cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
+               c->cpu_core_id = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
                                               ((1 << core_bits) - 1);
 
                if (c->x86_max_cores > 1)
                        printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-                              cpu_core_id[cpu]);
+                              c->cpu_core_id);
        }
 }
 #endif
@@ -613,6 +612,12 @@ void __cpuinit cpu_init(void)
                set_in_cr4(X86_CR4_TSD);
        }
 
+       /* The CPU hotplug case */
+       if (cpu_gdt_descr->address) {
+               gdt = (struct desc_struct *)cpu_gdt_descr->address;
+               memset(gdt, 0, PAGE_SIZE);
+               goto old_gdt;
+       }
        /*
         * This is a horrible hack to allocate the GDT.  The problem
         * is that cpu_init() is called really early for the boot CPU
@@ -631,7 +636,7 @@ void __cpuinit cpu_init(void)
                                local_irq_enable();
                }
        }
-
+old_gdt:
        /*
         * Initialize the per-CPU GDT with the boot GDT,
         * and set up the GDT descriptor:
index 6c37b4fd8ce285c293306788656b016e83cf3da3..e9f0b928b0a9925e534ddeadb3c868493240df58 100644 (file)
@@ -159,13 +159,13 @@ union l2_cache {
        unsigned val;
 };
 
-static unsigned short assocs[] = {
+static const unsigned short assocs[] = {
        [1] = 1, [2] = 2, [4] = 4, [6] = 8,
        [8] = 16,
        [0xf] = 0xffff // ??
        };
-static unsigned char levels[] = { 1, 1, 2 };
-static unsigned char types[] = { 1, 2, 3 };
+static const unsigned char levels[] = { 1, 1, 2 };
+static const unsigned char types[] = { 1, 2, 3 };
 
 static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
                       union _cpuid4_leaf_ebx *ebx,
@@ -261,7 +261,7 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
        unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
        unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
        unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
        unsigned int cpu = (c == &boot_cpu_data) ? 0 : (c - cpu_data);
 #endif
 
@@ -383,14 +383,14 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
 
        if (new_l2) {
                l2 = new_l2;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
                cpu_llc_id[cpu] = l2_id;
 #endif
        }
 
        if (new_l3) {
                l3 = new_l3;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
                cpu_llc_id[cpu] = l3_id;
 #endif
        }
@@ -729,7 +729,7 @@ static void __cpuexit cache_remove_dev(struct sys_device * sys_dev)
        return;
 }
 
-static int cacheinfo_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -747,7 +747,7 @@ static int cacheinfo_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cacheinfo_cpu_notifier =
+static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier =
 {
     .notifier_call = cacheinfo_cpu_callback,
 };
index a19fcb262dbb64d30120f2e974d6ed7c9a31177b..f54a15268ed730d7a24aba1668d140636fb6d88e 100644 (file)
@@ -18,7 +18,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
         * applications want to get the raw CPUID data, they should access
         * /dev/cpu/<cpu_nr>/cpuid instead.
         */
-       static char *x86_cap_flags[] = {
+       static const char * const x86_cap_flags[] = {
                /* Intel-defined */
                "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
                "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
@@ -62,7 +62,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        };
-       static char *x86_power_flags[] = {
+       static const char * const x86_power_flags[] = {
                "ts",   /* temperature sensor */
                "fid",  /* frequency id control */
                "vid",  /* voltage id control */
@@ -109,9 +109,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
 #ifdef CONFIG_X86_HT
        if (c->x86_max_cores * smp_num_siblings > 1) {
-               seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]);
+               seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
                seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[n]));
-               seq_printf(m, "core id\t\t: %d\n", cpu_core_id[n]);
+               seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
                seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
        }
 #endif
index 1d9a4abcdfc71f034c1c822853049280b32de0a2..f6dfa9fb675c1bfc5eba75ba74317ba2815b6da1 100644 (file)
@@ -183,7 +183,7 @@ static int cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long ac
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpuid_class_cpu_notifier =
+static struct notifier_block __cpuinitdata cpuid_class_cpu_notifier =
 {
        .notifier_call = cpuid_class_cpu_callback,
 };
index 9202b67c4b2e5cc925b0670d0b3e804dc719abbc..8beb0f07d99966b00206880fb3113db77333edd5 100644 (file)
@@ -601,8 +601,10 @@ efi_initialize_iomem_resources(struct resource *code_resource,
                res->end = res->start + ((md->num_pages << EFI_PAGE_SHIFT) - 1);
                res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
                if (request_resource(&iomem_resource, res) < 0)
-                       printk(KERN_ERR PFX "Failed to allocate res %s : 0x%lx-0x%lx\n",
-                               res->name, res->start, res->end);
+                       printk(KERN_ERR PFX "Failed to allocate res %s : "
+                               "0x%llx-0x%llx\n", res->name,
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                /*
                 * We don't know which region contains kernel data so we try
                 * it repeatedly and let the resource manager test it.
index e6e4506e749acbe079f9196fab1a05a6e333a753..fbdb933251b643b8e726feefe8e350205dbd7396 100644 (file)
@@ -83,6 +83,12 @@ VM_MASK              = 0x00020000
 #define resume_kernel          restore_nocheck
 #endif
 
+#ifdef CONFIG_VM86
+#define resume_userspace_sig   check_userspace
+#else
+#define resume_userspace_sig   resume_userspace
+#endif
+
 #define SAVE_ALL \
        cld; \
        pushl %es; \
@@ -211,6 +217,7 @@ ret_from_exception:
        preempt_stop
 ret_from_intr:
        GET_THREAD_INFO(%ebp)
+check_userspace:
        movl EFLAGS(%esp), %eax         # mix EFLAGS and CS
        movb CS(%esp), %al
        testl $(VM_MASK | 3), %eax
@@ -263,7 +270,12 @@ sysenter_past_esp:
        pushl $(__USER_CS)
        CFI_ADJUST_CFA_OFFSET 4
        /*CFI_REL_OFFSET cs, 0*/
-       pushl $SYSENTER_RETURN
+       /*
+        * Push current_thread_info()->sysenter_return to the stack.
+        * A tiny bit of offset fixup is necessary - 4*4 means the 4 words
+        * pushed above; +8 corresponds to copy_thread's esp0 setting.
+        */
+       pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
        CFI_ADJUST_CFA_OFFSET 4
        CFI_REL_OFFSET eip, 0
 
@@ -415,7 +427,7 @@ work_notifysig:                             # deal with pending signals and
                                        # vm86-space
        xorl %edx, %edx
        call do_notify_resume
-       jmp resume_userspace
+       jmp resume_userspace_sig
 
        ALIGN
 work_notifysig_v86:
@@ -428,7 +440,7 @@ work_notifysig_v86:
        movl %eax, %esp
        xorl %edx, %edx
        call do_notify_resume
-       jmp resume_userspace
+       jmp resume_userspace_sig
 #endif
 
        # perform syscall exit tracing
@@ -515,7 +527,7 @@ ENTRY(irq_entries_start)
  .if vector
        CFI_ADJUST_CFA_OFFSET -4
  .endif
-1:     pushl $vector-256
+1:     pushl $~(vector)
        CFI_ADJUST_CFA_OFFSET 4
        jmp common_interrupt
 .data
@@ -535,7 +547,7 @@ common_interrupt:
 #define BUILD_INTERRUPT(name, nr)      \
 ENTRY(name)                            \
        RING0_INT_FRAME;                \
-       pushl $nr-256;                  \
+       pushl $~(nr);                   \
        CFI_ADJUST_CFA_OFFSET 4;        \
        SAVE_ALL;                       \
        movl %esp,%eax;                 \
index c1a42feba28667cd8e0b7662aafe0fdb79607a23..3c6063671a9f94b4beabb137539880acdc105054 100644 (file)
@@ -132,7 +132,7 @@ void make_8259A_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
        io_apic_irqs &= ~(1<<irq);
-       irq_desc[irq].handler = &i8259A_irq_type;
+       irq_desc[irq].chip = &i8259A_irq_type;
        enable_irq(irq);
 }
 
@@ -386,12 +386,12 @@ void __init init_ISA_irqs (void)
                        /*
                         * 16 old-style INTA-cycle interrupts:
                         */
-                       irq_desc[i].handler = &i8259A_irq_type;
+                       irq_desc[i].chip = &i8259A_irq_type;
                } else {
                        /*
                         * 'high' PCI IRQs filled in on demand
                         */
-                       irq_desc[i].handler = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_type;
                }
        }
 }
index 72ae414e4d4976437fefa8a01e1b38d97fdc0395..ec9ea0269d367fb8c346b883f809ba40d7621b0d 100644 (file)
@@ -581,7 +581,7 @@ static int balanced_irq(void *unused)
        
        /* push everything to CPU 0 to give us a starting point.  */
        for (i = 0 ; i < NR_IRQS ; i++) {
-               pending_irq_cpumask[i] = cpumask_of_cpu(0);
+               irq_desc[i].pending_mask = cpumask_of_cpu(0);
                set_pending_irq(i, cpumask_of_cpu(0));
        }
 
@@ -1205,15 +1205,17 @@ static struct hw_interrupt_type ioapic_edge_type;
 #define IOAPIC_EDGE    0
 #define IOAPIC_LEVEL   1
 
-static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
+static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-       unsigned idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+       unsigned idx;
+
+       idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
                        trigger == IOAPIC_LEVEL)
-               irq_desc[idx].handler = &ioapic_level_type;
+               irq_desc[idx].chip = &ioapic_level_type;
        else
-               irq_desc[idx].handler = &ioapic_edge_type;
+               irq_desc[idx].chip = &ioapic_edge_type;
        set_intr_gate(vector, interrupt[idx]);
 }
 
@@ -1325,7 +1327,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
         * The timer IRQ doesn't have to know that behind the
         * scene we have a 8259A-master in AEOI mode ...
         */
-       irq_desc[0].handler = &ioapic_edge_type;
+       irq_desc[0].chip = &ioapic_edge_type;
 
        /*
         * Add it to the IO-APIC irq-routing table:
@@ -2069,6 +2071,13 @@ static void set_ioapic_affinity_vector (unsigned int vector,
 #endif
 #endif
 
+static int ioapic_retrigger(unsigned int irq)
+{
+       send_IPI_self(IO_APIC_VECTOR(irq));
+
+       return 1;
+}
+
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
  * so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -2088,6 +2097,7 @@ static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static struct hw_interrupt_type ioapic_level_type __read_mostly = {
@@ -2101,6 +2111,7 @@ static struct hw_interrupt_type ioapic_level_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -2135,7 +2146,7 @@ static inline void init_IO_APIC_traps(void)
                                make_8259A_irq(irq);
                        else
                                /* Strange. Oh, well.. */
-                               irq_desc[irq].handler = &no_irq_type;
+                               irq_desc[irq].chip = &no_irq_type;
                }
        }
 }
@@ -2351,7 +2362,7 @@ static inline void check_timer(void)
        printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
        disable_8259A_irq(0);
-       irq_desc[0].handler = &lapic_irq_type;
+       irq_desc[0].chip = &lapic_irq_type;
        apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);   /* Fixed mode */
        enable_8259A_irq(0);
 
index 061533e0cb5e8efa284258c3619665a287a786e5..16b4917039672bb3200e82c0325ef2f85134fbd9 100644 (file)
@@ -53,13 +53,19 @@ static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
  */
 fastcall unsigned int do_IRQ(struct pt_regs *regs)
 {      
-       /* high bits used in ret_from_ code */
-       int irq = regs->orig_eax & 0xff;
+       /* high bit used in ret_from_ code */
+       int irq = ~regs->orig_eax;
 #ifdef CONFIG_4KSTACKS
        union irq_ctx *curctx, *irqctx;
        u32 *isp;
 #endif
 
+       if (unlikely((unsigned)irq >= NR_IRQS)) {
+               printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+                                       __FUNCTION__, irq);
+               BUG();
+       }
+
        irq_enter();
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
        /* Debugging check for stack overflow: is there less than 1KB free? */
@@ -76,6 +82,10 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
        }
 #endif
 
+       if (!irq_desc[irq].handle_irq) {
+               __do_IRQ(irq, regs);
+               goto out_exit;
+       }
 #ifdef CONFIG_4KSTACKS
 
        curctx = (union irq_ctx *) current_thread_info();
@@ -100,8 +110,8 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
                 * softirq checks work in the hardirq context.
                 */
                irqctx->tinfo.preempt_count =
-                       irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK |
-                       curctx->tinfo.preempt_count & SOFTIRQ_MASK;
+                       (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
+                       (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
 
                asm volatile(
                        "       xchgl   %%ebx,%%esp      \n"
@@ -115,6 +125,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
 #endif
                __do_IRQ(irq, regs);
 
+out_exit:
        irq_exit();
 
        return 1;
@@ -243,7 +254,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -285,13 +296,13 @@ void fixup_irqs(cpumask_t map)
                if (irq == 2)
                        continue;
 
-               cpus_and(mask, irq_affinity[irq], map);
+               cpus_and(mask, irq_desc[irq].affinity, map);
                if (any_online_cpu(mask) == NR_CPUS) {
                        printk("Breaking affinity for irq %i\n", irq);
                        mask = map;
                }
-               if (irq_desc[irq].handler->set_affinity)
-                       irq_desc[irq].handler->set_affinity(irq, mask);
+               if (irq_desc[irq].chip->set_affinity)
+                       irq_desc[irq].chip->set_affinity(irq, mask);
                else if (irq_desc[irq].action && !(warned++))
                        printk("Cannot set affinity for irq %i\n", irq);
        }
index 7a328230e540f8b073e5d0306f457a1a9bffbc28..d022cb8fd7251ccc79e3eeb89a8210e5f92b85d1 100644 (file)
@@ -266,7 +266,7 @@ static int msr_class_cpu_callback(struct notifier_block *nfb, unsigned long acti
        return NOTIFY_OK;
 }
 
-static struct notifier_block msr_class_cpu_notifier =
+static struct notifier_block __cpuinitdata msr_class_cpu_notifier =
 {
        .notifier_call = msr_class_cpu_callback,
 };
index 321f5fd26e75062ef2119710e9ce1b7047ac662c..9bf590cefc7d4d55d89fde0561ec6a5fb70d5192 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 
 #include <linux/scx200.h>
@@ -45,11 +46,19 @@ static struct pci_driver scx200_pci_driver = {
        .probe = scx200_probe,
 };
 
-static DEFINE_SPINLOCK(scx200_gpio_config_lock);
+static DEFINE_MUTEX(scx200_gpio_config_lock);
 
-static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void __devinit scx200_init_shadow(void)
 {
        int bank;
+
+       /* read the current values driven on the GPIO signals */
+       for (bank = 0; bank < 2; ++bank)
+               scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+}
+
+static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
        unsigned base;
 
        if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE ||
@@ -63,10 +72,7 @@ static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_
                }
 
                scx200_gpio_base = base;
-
-               /* read the current values driven on the GPIO signals */
-               for (bank = 0; bank < 2; ++bank)
-                       scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+               scx200_init_shadow();
 
        } else {
                /* find the base of the Configuration Block */
@@ -87,12 +93,11 @@ static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_
        return 0;
 }
 
-u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
+u32 scx200_gpio_configure(unsigned index, u32 mask, u32 bits)
 {
        u32 config, new_config;
-       unsigned long flags;
 
-       spin_lock_irqsave(&scx200_gpio_config_lock, flags);
+       mutex_lock(&scx200_gpio_config_lock);
 
        outl(index, scx200_gpio_base + 0x20);
        config = inl(scx200_gpio_base + 0x24);
@@ -100,45 +105,11 @@ u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
        new_config = (config & mask) | bits;
        outl(new_config, scx200_gpio_base + 0x24);
 
-       spin_unlock_irqrestore(&scx200_gpio_config_lock, flags);
+       mutex_unlock(&scx200_gpio_config_lock);
 
        return config;
 }
 
-#if 0
-void scx200_gpio_dump(unsigned index)
-{
-       u32 config = scx200_gpio_configure(index, ~0, 0);
-       printk(KERN_DEBUG "GPIO%02u: 0x%08lx", index, (unsigned long)config);
-       
-       if (config & 1) 
-               printk(" OE"); /* output enabled */
-       else
-               printk(" TS"); /* tristate */
-       if (config & 2) 
-               printk(" PP"); /* push pull */
-       else
-               printk(" OD"); /* open drain */
-       if (config & 4) 
-               printk(" PUE"); /* pull up enabled */
-       else
-               printk(" PUD"); /* pull up disabled */
-       if (config & 8) 
-               printk(" LOCKED"); /* locked */
-       if (config & 16) 
-               printk(" LEVEL"); /* level input */
-       else
-               printk(" EDGE"); /* edge input */
-       if (config & 32) 
-               printk(" HI"); /* trigger on rising edge */
-       else
-               printk(" LO"); /* trigger on falling edge */
-       if (config & 64) 
-               printk(" DEBOUNCE"); /* debounce */
-       printk("\n");
-}
-#endif  /*  0  */
-
 static int __init scx200_init(void)
 {
        printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
@@ -159,10 +130,3 @@ EXPORT_SYMBOL(scx200_gpio_base);
 EXPORT_SYMBOL(scx200_gpio_shadow);
 EXPORT_SYMBOL(scx200_gpio_configure);
 EXPORT_SYMBOL(scx200_cb_base);
-
-/*
-    Local variables:
-        compile-command: "make -k -C ../../.. SUBDIRS=arch/i386/kernel modules"
-        c-basic-offset: 8
-    End:
-*/
index 4a65040cc624b06bf1de3ca678f66cd9527b36a9..6712f0d2eb37372aa040ce352ef68a9ebd8c09d7 100644 (file)
@@ -1314,8 +1314,10 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat
        probe_roms();
        for (i = 0; i < e820.nr_map; i++) {
                struct resource *res;
+#ifndef CONFIG_RESOURCES_64BIT
                if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
                        continue;
+#endif
                res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
                switch (e820.map[i].type) {
                case E820_RAM:  res->name = "System RAM"; break;
index 5c352c3a9e7fa00492da1ff1c33a28ad0b5217c7..43002cfb40c4e2811bf5006c9126fa2ff1cfdd46 100644 (file)
@@ -351,7 +351,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
                        goto give_sigsegv;
        }
 
-       restorer = &__kernel_sigreturn;
+       restorer = (void *)VDSO_SYM(&__kernel_sigreturn);
        if (ka->sa.sa_flags & SA_RESTORER)
                restorer = ka->sa.sa_restorer;
 
@@ -447,7 +447,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                goto give_sigsegv;
 
        /* Set up to return from userspace.  */
-       restorer = &__kernel_rt_sigreturn;
+       restorer = (void *)VDSO_SYM(&__kernel_rt_sigreturn);
        if (ka->sa.sa_flags & SA_RESTORER)
                restorer = ka->sa.sa_restorer;
        err |= __put_user(restorer, &frame->pretcode);
index bce5470ecb42e6e91ac47510366676fe13637a57..89e7315e539c49a5f8f19a3479ae21774075a374 100644 (file)
@@ -67,12 +67,6 @@ int smp_num_siblings = 1;
 EXPORT_SYMBOL(smp_num_siblings);
 #endif
 
-/* Package ID of each logical CPU */
-int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
-
-/* Core ID of each logical CPU */
-int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
-
 /* Last level cache ID of each logical CPU */
 int cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID};
 
@@ -454,10 +448,12 @@ cpumask_t cpu_coregroup_map(int cpu)
        struct cpuinfo_x86 *c = cpu_data + cpu;
        /*
         * For perf, we return last level cache shared map.
-        * TBD: when power saving sched policy is added, we will return
-        *      cpu_core_map when power saving policy is enabled
+        * And for power savings, we return cpu_core_map
         */
-       return c->llc_shared_map;
+       if (sched_mc_power_savings || sched_smt_power_savings)
+               return cpu_core_map[cpu];
+       else
+               return c->llc_shared_map;
 }
 
 /* representing cpus for which sibling maps can be computed */
@@ -473,8 +469,8 @@ set_cpu_sibling_map(int cpu)
 
        if (smp_num_siblings > 1) {
                for_each_cpu_mask(i, cpu_sibling_setup_map) {
-                       if (phys_proc_id[cpu] == phys_proc_id[i] &&
-                           cpu_core_id[cpu] == cpu_core_id[i]) {
+                       if (c[cpu].phys_proc_id == c[i].phys_proc_id &&
+                           c[cpu].cpu_core_id == c[i].cpu_core_id) {
                                cpu_set(i, cpu_sibling_map[cpu]);
                                cpu_set(cpu, cpu_sibling_map[i]);
                                cpu_set(i, cpu_core_map[cpu]);
@@ -501,7 +497,7 @@ set_cpu_sibling_map(int cpu)
                        cpu_set(i, c[cpu].llc_shared_map);
                        cpu_set(cpu, c[i].llc_shared_map);
                }
-               if (phys_proc_id[cpu] == phys_proc_id[i]) {
+               if (c[cpu].phys_proc_id == c[i].phys_proc_id) {
                        cpu_set(i, cpu_core_map[cpu]);
                        cpu_set(cpu, cpu_core_map[i]);
                        /*
@@ -1056,6 +1052,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
        struct warm_boot_cpu_info info;
        struct work_struct task;
        int     apicid, ret;
+       struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
 
        apicid = x86_cpu_to_apicid[cpu];
        if (apicid == BAD_APICID) {
@@ -1063,6 +1060,18 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
                goto exit;
        }
 
+       /*
+        * the CPU isn't initialized at boot time, allocate gdt table here.
+        * cpu_init will initialize it
+        */
+       if (!cpu_gdt_descr->address) {
+               cpu_gdt_descr->address = get_zeroed_page(GFP_KERNEL);
+               if (!cpu_gdt_descr->address)
+                       printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
+                       ret = -ENOMEM;
+                       goto exit;
+       }
+
        info.complete = &done;
        info.apicid = apicid;
        info.cpu = cpu;
@@ -1340,8 +1349,8 @@ remove_siblinginfo(int cpu)
                cpu_clear(cpu, cpu_sibling_map[sibling]);
        cpus_clear(cpu_sibling_map[cpu]);
        cpus_clear(cpu_core_map[cpu]);
-       phys_proc_id[cpu] = BAD_APICID;
-       cpu_core_id[cpu] = BAD_APICID;
+       c[cpu].phys_proc_id = 0;
+       c[cpu].cpu_core_id = 0;
        cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
index 0bada1870bdf5691631e10558bf43cbb350691a1..713ba39d32c66db0e2ad4ca0580088ffccef785f 100644 (file)
@@ -2,6 +2,8 @@
  * linux/arch/i386/kernel/sysenter.c
  *
  * (C) Copyright 2002 Linus Torvalds
+ * Portions based on the vdso-randomization code from exec-shield:
+ * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
  *
  * This file contains the needed initializations to support sysenter.
  */
 #include <linux/gfp.h>
 #include <linux/string.h>
 #include <linux/elf.h>
+#include <linux/mm.h>
+#include <linux/module.h>
 
 #include <asm/cpufeature.h>
 #include <asm/msr.h>
 #include <asm/pgtable.h>
 #include <asm/unistd.h>
 
+/*
+ * Should the kernel map a VDSO page into processes and pass its
+ * address down to glibc upon exec()?
+ */
+unsigned int __read_mostly vdso_enabled = 1;
+
+EXPORT_SYMBOL_GPL(vdso_enabled);
+
+static int __init vdso_setup(char *s)
+{
+       vdso_enabled = simple_strtoul(s, NULL, 0);
+
+       return 1;
+}
+
+__setup("vdso=", vdso_setup);
+
 extern asmlinkage void sysenter_entry(void);
 
 void enable_sep_cpu(void)
@@ -45,23 +66,120 @@ void enable_sep_cpu(void)
  */
 extern const char vsyscall_int80_start, vsyscall_int80_end;
 extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
+static void *syscall_page;
 
 int __init sysenter_setup(void)
 {
-       void *page = (void *)get_zeroed_page(GFP_ATOMIC);
+       syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
 
-       __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC);
+#ifdef CONFIG_COMPAT_VDSO
+       __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);
+       printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
+#else
+       /*
+        * In the non-compat case the ELF coredumping code needs the fixmap:
+        */
+       __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_KERNEL_RO);
+#endif
 
        if (!boot_cpu_has(X86_FEATURE_SEP)) {
-               memcpy(page,
+               memcpy(syscall_page,
                       &vsyscall_int80_start,
                       &vsyscall_int80_end - &vsyscall_int80_start);
                return 0;
        }
 
-       memcpy(page,
+       memcpy(syscall_page,
               &vsyscall_sysenter_start,
               &vsyscall_sysenter_end - &vsyscall_sysenter_start);
 
        return 0;
 }
+
+static struct page *syscall_nopage(struct vm_area_struct *vma,
+                               unsigned long adr, int *type)
+{
+       struct page *p = virt_to_page(adr - vma->vm_start + syscall_page);
+       get_page(p);
+       return p;
+}
+
+/* Prevent VMA merging */
+static void syscall_vma_close(struct vm_area_struct *vma)
+{
+}
+
+static struct vm_operations_struct syscall_vm_ops = {
+       .close = syscall_vma_close,
+       .nopage = syscall_nopage,
+};
+
+/* Defined in vsyscall-sysenter.S */
+extern void SYSENTER_RETURN;
+
+/* Setup a VMA at program startup for the vsyscall page */
+int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = current->mm;
+       unsigned long addr;
+       int ret;
+
+       down_write(&mm->mmap_sem);
+       addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+       if (IS_ERR_VALUE(addr)) {
+               ret = addr;
+               goto up_fail;
+       }
+
+       vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL);
+       if (!vma) {
+               ret = -ENOMEM;
+               goto up_fail;
+       }
+
+       vma->vm_start = addr;
+       vma->vm_end = addr + PAGE_SIZE;
+       /* MAYWRITE to allow gdb to COW and set breakpoints */
+       vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
+       vma->vm_flags |= mm->def_flags;
+       vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+       vma->vm_ops = &syscall_vm_ops;
+       vma->vm_mm = mm;
+
+       ret = insert_vm_struct(mm, vma);
+       if (unlikely(ret)) {
+               kmem_cache_free(vm_area_cachep, vma);
+               goto up_fail;
+       }
+
+       current->mm->context.vdso = (void *)addr;
+       current_thread_info()->sysenter_return =
+                                   (void *)VDSO_SYM(&SYSENTER_RETURN);
+       mm->total_vm++;
+up_fail:
+       up_write(&mm->mmap_sem);
+       return ret;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+       if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
+               return "[vdso]";
+       return NULL;
+}
+
+struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+{
+       return NULL;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long addr)
+{
+       return 0;
+}
+
+int in_gate_area_no_task(unsigned long addr)
+{
+       return 0;
+}
index 296355292c7c56433df1c849e93851985a7798d3..e2e281d4bcc80ee7bc3b090e75914606231e6224 100644 (file)
 
 static struct i386_cpu cpu_devices[NR_CPUS];
 
-int arch_register_cpu(int num){
-       struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
-       int node = cpu_to_node(num);
-       if (node_online(node))
-               parent = &node_devices[node].node;
-#endif /* CONFIG_NUMA */
-
+int arch_register_cpu(int num)
+{
        /*
         * CPU0 cannot be offlined due to several
         * restrictions and assumptions in kernel. This basically
@@ -50,21 +43,13 @@ int arch_register_cpu(int num){
        if (!num)
                cpu_devices[num].cpu.no_control = 1;
 
-       return register_cpu(&cpu_devices[num].cpu, num, parent);
+       return register_cpu(&cpu_devices[num].cpu, num);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
 
 void arch_unregister_cpu(int num) {
-       struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
-       int node = cpu_to_node(num);
-       if (node_online(node))
-               parent = &node_devices[node].node;
-#endif /* CONFIG_NUMA */
-
-       return unregister_cpu(&cpu_devices[num].cpu, parent);
+       return unregister_cpu(&cpu_devices[num].cpu);
 }
 EXPORT_SYMBOL(arch_register_cpu);
 EXPORT_SYMBOL(arch_unregister_cpu);
@@ -74,16 +59,13 @@ EXPORT_SYMBOL(arch_unregister_cpu);
 
 #ifdef CONFIG_NUMA
 #include <linux/mmzone.h>
-#include <asm/node.h>
-
-struct i386_node node_devices[MAX_NUMNODES];
 
 static int __init topology_init(void)
 {
        int i;
 
        for_each_online_node(i)
-               arch_register_node(i);
+               register_one_node(i);
 
        for_each_present_cpu(i)
                arch_register_cpu(i);
index 3b62baa6a371def2c0ae3e426fbf2410f3fc83a2..1a36d26e15eb0c6d370832ee166dd0fba3700f59 100644 (file)
@@ -42,10 +42,10 @@ __kernel_vsyscall:
        /* 7: align return point with nop's to make disassembly easier */
        .space 7,0x90
 
-       /* 14: System call restart point is here! (SYSENTER_RETURN - 2) */
+       /* 14: System call restart point is here! (SYSENTER_RETURN-2) */
        jmp .Lenter_kernel
        /* 16: System call normal return point is here! */
-       .globl SYSENTER_RETURN  /* Symbol used by entry.S.  */
+       .globl SYSENTER_RETURN  /* Symbol used by sysenter.c  */
 SYSENTER_RETURN:
        pop %ebp
 .Lpop_ebp:
index 98699ca6e52d7b2febba30a086741a4f663da426..e26975fc68b650105cbff7b0568ba7b856770085 100644 (file)
@@ -7,7 +7,7 @@
 
 SECTIONS
 {
-  . = VSYSCALL_BASE + SIZEOF_HEADERS;
+  . = VDSO_PRELINK + SIZEOF_HEADERS;
 
   .hash           : { *(.hash) }               :text
   .dynsym         : { *(.dynsym) }
@@ -20,7 +20,7 @@ SECTIONS
      For the layouts to match, we need to skip more than enough
      space for the dynamic symbol table et al.  If this amount
      is insufficient, ld -shared will barf.  Just increase it here.  */
-  . = VSYSCALL_BASE + 0x400;
+  . = VDSO_PRELINK + 0x400;
 
   .text           : { *(.text) }               :text =0x90909090
   .note                  : { *(.note.*) }              :text :note
index 8a9e1a6f745de17f9d28e9acfaf2e3f3d205994a..1f84cdb24779179b77da4b80d711ae6f276f5d5f 100644 (file)
@@ -140,8 +140,8 @@ void __init time_init_hook(void)
 
 #define MB (1024 * 1024)
 
-static unsigned long sgivwfb_mem_phys;
-static unsigned long sgivwfb_mem_size;
+unsigned long sgivwfb_mem_phys;
+unsigned long sgivwfb_mem_size;
 
 long long mem_size __initdata = 0;
 
@@ -177,8 +177,4 @@ char * __init machine_specific_memory_setup(void)
        add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
 
        return "PROM";
-
-       /* Remove gcc warnings */
-       (void) sanitize_e820_map(NULL, NULL);
-       (void) copy_e820_map(NULL, 0);
 }
index 3e64fb7212911bc4db9fe8db9f67ab75a40ecd36..c418521dd5547073cf78bfbf0e9bb710366cb3b0 100644 (file)
@@ -278,22 +278,22 @@ void init_VISWS_APIC_irqs(void)
                irq_desc[i].depth = 1;
 
                if (i == 0) {
-                       irq_desc[i].handler = &cobalt_irq_type;
+                       irq_desc[i].chip = &cobalt_irq_type;
                }
                else if (i == CO_IRQ_IDE0) {
-                       irq_desc[i].handler = &cobalt_irq_type;
+                       irq_desc[i].chip = &cobalt_irq_type;
                }
                else if (i == CO_IRQ_IDE1) {
-                       irq_desc[i].handler = &cobalt_irq_type;
+                       irq_desc[i].chip = &cobalt_irq_type;
                }
                else if (i == CO_IRQ_8259) {
-                       irq_desc[i].handler = &piix4_master_irq_type;
+                       irq_desc[i].chip = &piix4_master_irq_type;
                }
                else if (i < CO_IRQ_APIC0) {
-                       irq_desc[i].handler = &piix4_virtual_irq_type;
+                       irq_desc[i].chip = &piix4_virtual_irq_type;
                }
                else if (IS_CO_APIC(i)) {
-                       irq_desc[i].handler = &cobalt_irq_type;
+                       irq_desc[i].chip = &cobalt_irq_type;
                }
        }
 
index 0e225054e2229cf9543f70ede0b5794e45ddb73d..defc6ebbd56517ac054deeeafbf17239de36cc5d 100644 (file)
@@ -5,10 +5,10 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/acpi.h>
 #include <asm/arch_hooks.h>
 #include <asm/voyager.h>
 #include <asm/e820.h>
+#include <asm/io.h>
 #include <asm/setup.h>
 
 void __init pre_intr_init_hook(void)
@@ -27,8 +27,7 @@ void __init intr_init_hook(void)
        smp_intr_init();
 #endif
 
-       if (!acpi_ioapic)
-               setup_irq(2, &irq2);
+       setup_irq(2, &irq2);
 }
 
 void __init pre_setup_arch_hook(void)
index 70e560a1b79ad1c457d0ac9777d3931d2c8ba87a..5b8b579a079fa8a7afdc52e4871aef91b3a94665 100644 (file)
@@ -661,6 +661,7 @@ do_boot_cpu(__u8 cpu)
                print_cpu_info(&cpu_data[cpu]);
                wmb();
                cpu_set(cpu, cpu_callout_map);
+               cpu_set(cpu, cpu_present_map);
        }
        else {
                printk("CPU%d FAILED TO BOOT: ", cpu);
@@ -1418,7 +1419,7 @@ smp_intr_init(void)
         * This is for later: first 16 correspond to PC IRQs; next 16
         * are Primary MC IRQs and final 16 are Secondary MC IRQs */
        for(i = 0; i < 48; i++)
-               irq_desc[i].handler = &vic_irq_type;
+               irq_desc[i].chip = &vic_irq_type;
 }
 
 /* send a CPI at level cpi to a set of cpus in cpuset (set 1 bit per
@@ -1912,6 +1913,7 @@ void __devinit smp_prepare_boot_cpu(void)
        cpu_set(smp_processor_id(), cpu_online_map);
        cpu_set(smp_processor_id(), cpu_callout_map);
        cpu_set(smp_processor_id(), cpu_possible_map);
+       cpu_set(smp_processor_id(), cpu_present_map);
 }
 
 int __devinit
index bf19513f0cea227126407b0e22cbb0bf614fa7b3..f84b16e007ff86fb73185482efcbca7be8eb4ebd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
+#include <linux/poison.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
@@ -654,7 +655,7 @@ void __init mem_init(void)
  */
 #ifdef CONFIG_MEMORY_HOTPLUG
 #ifndef CONFIG_NEED_MULTIPLE_NODES
-int add_memory(u64 start, u64 size)
+int arch_add_memory(int nid, u64 start, u64 size)
 {
        struct pglist_data *pgdata = &contig_page_data;
        struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1;
@@ -753,7 +754,7 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
        for (addr = begin; addr < end; addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
                init_page_count(virt_to_page(addr));
-               memset((void *)addr, 0xcc, PAGE_SIZE);
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                free_page(addr);
                totalram_pages++;
        }
index 0887b34bc59b987543c10b92ae53d73b83c361ef..353a836ed63c03f363acbcba49e4c54d9258f855 100644 (file)
@@ -229,8 +229,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
        if (PageHighMem(page))
                return;
        if (!enable)
-               mutex_debug_check_no_locks_freed(page_address(page),
-                                                numpages * PAGE_SIZE);
+               debug_check_no_locks_freed(page_address(page),
+                                          numpages * PAGE_SIZE);
 
        /* the return value is ignored - the calls cannot fail,
         * large pages are disabled at boot time.
index a151f7a99f5e8010a7f9875cede3f9aceb81ed61..10154a2cac6895d6073973f3e12ef95d18bee247 100644 (file)
  */
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                       resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index 18318749884b012f1f2e3d879a633a7ed21802bd..b487e227a1f7a3e6b17dd48d57a81d1319e0e376 100644 (file)
@@ -271,6 +271,9 @@ config HOTPLUG_CPU
          can be controlled through /sys/devices/system/cpu/cpu#.
          Say N if you want to disable CPU hotplug.
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
+
 config SCHED_SMT
        bool "SMT scheduler support"
        depends on SMP
@@ -374,6 +377,10 @@ config HAVE_ARCH_EARLY_PFN_TO_NID
        def_bool y
        depends on NEED_MULTIPLE_NODES
 
+config HAVE_ARCH_NODEDATA_EXTENSION
+       def_bool y
+       depends on NUMA
+
 config IA32_SUPPORT
        bool "Support for Linux/x86 binaries"
        help
@@ -485,6 +492,10 @@ config GENERIC_PENDING_IRQ
        depends on GENERIC_HARDIRQS && SMP
        default y
 
+config IRQ_PER_CPU
+       bool
+       default y
+
 source "arch/ia64/hp/sim/Kconfig"
 
 menu "Instrumentation Support"
index 766bf495543249e44bfd69d92a31ebd3a69b47cc..9d1cffb57cde20c3f143a529b8bd5a2d6cf114a5 100644 (file)
@@ -114,7 +114,7 @@ CONFIG_IA64_CYCLONE=y
 CONFIG_IOSAPIC=y
 CONFIG_FORCE_MAX_ZONEORDER=17
 CONFIG_SMP=y
-CONFIG_NR_CPUS=4
+CONFIG_NR_CPUS=16
 CONFIG_HOTPLUG_CPU=y
 CONFIG_PERMIT_BSP_REMOVE=y
 CONFIG_FORCE_CPEI_RETARGET=y
index c0d25a2a3e9caf1ddbf7eb396b23027347024856..8145547bb52daf891199affd969a5dd9cb8cee9a 100644 (file)
@@ -44,8 +44,8 @@ hpsim_irq_init (void)
        int i;
 
        for (i = 0; i < NR_IRQS; ++i) {
-               idesc = irq_descp(i);
-               if (idesc->handler == &no_irq_type)
-                       idesc->handler = &irq_type_hp_sim;
+               idesc = irq_desc + i;
+               if (idesc->chip == &no_irq_type)
+                       idesc->chip = &irq_type_hp_sim;
        }
 }
index d58c1c5c903a9cfdae0981411ae53604fce020f1..efc7df4b0fd251a126b29a263546bb4ef2181f07 100644 (file)
@@ -456,7 +456,7 @@ iosapic_startup_edge_irq (unsigned int irq)
 static void
 iosapic_ack_edge_irq (unsigned int irq)
 {
-       irq_desc_t *idesc = irq_descp(irq);
+       irq_desc_t *idesc = irq_desc + irq;
 
        move_native_irq(irq);
        /*
@@ -659,14 +659,14 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
        else
                irq_type = &irq_type_iosapic_level;
 
-       idesc = irq_descp(vector);
-       if (idesc->handler != irq_type) {
-               if (idesc->handler != &no_irq_type)
+       idesc = irq_desc + vector;
+       if (idesc->chip != irq_type) {
+               if (idesc->chip != &no_irq_type)
                        printk(KERN_WARNING
                               "%s: changing vector %d from %s to %s\n",
                               __FUNCTION__, vector,
-                              idesc->handler->typename, irq_type->typename);
-               idesc->handler = irq_type;
+                              idesc->chip->typename, irq_type->typename);
+               idesc->chip = irq_type;
        }
        return 0;
 }
@@ -793,14 +793,14 @@ again:
                        return -ENOSPC;
        }
 
-       spin_lock_irqsave(&irq_descp(vector)->lock, flags);
+       spin_lock_irqsave(&irq_desc[vector].lock, flags);
        spin_lock(&iosapic_lock);
        {
                if (gsi_to_vector(gsi) > 0) {
                        if (list_empty(&iosapic_intr_info[vector].rtes))
                                free_irq_vector(vector);
                        spin_unlock(&iosapic_lock);
-                       spin_unlock_irqrestore(&irq_descp(vector)->lock,
+                       spin_unlock_irqrestore(&irq_desc[vector].lock,
                                               flags);
                        goto again;
                }
@@ -810,7 +810,7 @@ again:
                              polarity, trigger);
                if (err < 0) {
                        spin_unlock(&iosapic_lock);
-                       spin_unlock_irqrestore(&irq_descp(vector)->lock,
+                       spin_unlock_irqrestore(&irq_desc[vector].lock,
                                               flags);
                        return err;
                }
@@ -825,7 +825,7 @@ again:
                set_rte(gsi, vector, dest, mask);
        }
        spin_unlock(&iosapic_lock);
-       spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+       spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
 
        printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
               gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
@@ -860,7 +860,7 @@ iosapic_unregister_intr (unsigned int gsi)
        }
        vector = irq_to_vector(irq);
 
-       idesc = irq_descp(irq);
+       idesc = irq_desc + irq;
        spin_lock_irqsave(&idesc->lock, flags);
        spin_lock(&iosapic_lock);
        {
@@ -903,7 +903,7 @@ iosapic_unregister_intr (unsigned int gsi)
                        BUG_ON(iosapic_intr_info[vector].count);
 
                        /* Clear the interrupt controller descriptor */
-                       idesc->handler = &no_irq_type;
+                       idesc->chip = &no_irq_type;
 
                        /* Clear the interrupt information */
                        memset(&iosapic_intr_info[vector], 0,
index 9c72ea3f6432d115ca32090d0c8bd9c8365d5c07..7852382de2fa6666a67383086f0014c93ddce43a 100644 (file)
@@ -76,7 +76,7 @@ int show_interrupts(struct seq_file *p, void *v)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
                }
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -100,7 +100,7 @@ void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
        cpu_set(cpu_logical_id(hwid), mask);
 
        if (irq < NR_IRQS) {
-               irq_affinity[irq] = mask;
+               irq_desc[irq].affinity = mask;
                irq_redir[irq] = (char) (redir & 0xff);
        }
 }
@@ -120,7 +120,7 @@ static void migrate_irqs(void)
        int             irq, new_cpu;
 
        for (irq=0; irq < NR_IRQS; irq++) {
-               desc = irq_descp(irq);
+               desc = irq_desc + irq;
 
                /*
                 * No handling for now.
@@ -131,7 +131,7 @@ static void migrate_irqs(void)
                if (desc->status == IRQ_PER_CPU)
                        continue;
 
-               cpus_and(mask, irq_affinity[irq], cpu_online_map);
+               cpus_and(mask, irq_desc[irq].affinity, cpu_online_map);
                if (any_online_cpu(mask) == NR_CPUS) {
                        /*
                         * Save it for phase 2 processing
@@ -144,15 +144,15 @@ static void migrate_irqs(void)
                        /*
                         * Al three are essential, currently WARN_ON.. maybe panic?
                         */
-                       if (desc->handler && desc->handler->disable &&
-                               desc->handler->enable && desc->handler->set_affinity) {
-                               desc->handler->disable(irq);
-                               desc->handler->set_affinity(irq, mask);
-                               desc->handler->enable(irq);
+                       if (desc->chip && desc->chip->disable &&
+                               desc->chip->enable && desc->chip->set_affinity) {
+                               desc->chip->disable(irq);
+                               desc->chip->set_affinity(irq, mask);
+                               desc->chip->enable(irq);
                        } else {
-                               WARN_ON((!(desc->handler) || !(desc->handler->disable) ||
-                                               !(desc->handler->enable) ||
-                                               !(desc->handler->set_affinity)));
+                               WARN_ON((!(desc->chip) || !(desc->chip->disable) ||
+                                               !(desc->chip->enable) ||
+                                               !(desc->chip->set_affinity)));
                        }
                }
        }
index ef9a2b49307ae756ac58a8fb7f8c360aa2aca53a..f5035304594e5af977d6b432a3f82e45b9320d93 100644 (file)
@@ -249,9 +249,9 @@ register_percpu_irq (ia64_vector vec, struct irqaction *action)
 
        for (irq = 0; irq < NR_IRQS; ++irq)
                if (irq_to_vector(irq) == vec) {
-                       desc = irq_descp(irq);
+                       desc = irq_desc + irq;
                        desc->status |= IRQ_PER_CPU;
-                       desc->handler = &irq_type_ia64_lsapic;
+                       desc->chip = &irq_type_ia64_lsapic;
                        if (action)
                                setup_irq(irq, action);
                }
index ea14e6a04409636c62813048504cf77e3ef57949..1ab58b09f3d7163df640f5765efd7d8d3a020c02 100644 (file)
@@ -26,6 +26,13 @@ lsapic_noop (unsigned int irq)
        /* nuthing to do... */
 }
 
+static int lsapic_retrigger(unsigned int irq)
+{
+       ia64_resend_irq(irq);
+
+       return 1;
+}
+
 struct hw_interrupt_type irq_type_ia64_lsapic = {
        .typename =     "LSAPIC",
        .startup =      lsapic_noop_startup,
@@ -33,5 +40,6 @@ struct hw_interrupt_type irq_type_ia64_lsapic = {
        .enable =       lsapic_noop,
        .disable =      lsapic_noop,
        .ack =          lsapic_noop,
-       .end =          lsapic_noop
+       .end =          lsapic_noop,
+       .retrigger =    lsapic_retrigger,
 };
index 6a0880639bc9396208c30a9f9ccd4b3ae93aa835..d7dc5e63de63c2bc29b9a1fc19b98c663517de5f 100644 (file)
@@ -1788,7 +1788,7 @@ ia64_mca_late_init(void)
                        cpe_poll_enabled = 0;
                        for (irq = 0; irq < NR_IRQS; ++irq)
                                if (irq_to_vector(irq) == cpe_vector) {
-                                       desc = irq_descp(irq);
+                                       desc = irq_desc + irq;
                                        desc->status |= IRQ_PER_CPU;
                                        setup_irq(irq, &mca_cpe_irqaction);
                                        ia64_cpe_irq = irq;
index 859fb37ff49b682799b65b1384b9d05cbc576b88..8a12084191384ee55f02ed5848a95ef708206732 100644 (file)
@@ -959,7 +959,7 @@ remove_palinfo_proc_entries(unsigned int hcpu)
        }
 }
 
-static int palinfo_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
                                                                unsigned long action,
                                                                void *hcpu)
 {
@@ -978,7 +978,7 @@ static int palinfo_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block palinfo_cpu_notifier =
+static struct notifier_block __cpuinitdata palinfo_cpu_notifier =
 {
        .notifier_call = palinfo_cpu_callback,
        .priority = 0,
@@ -998,7 +998,7 @@ palinfo_init(void)
        }
 
        /* Register for future delivery via notify registration */
-       register_cpu_notifier(&palinfo_cpu_notifier);
+       register_hotcpu_notifier(&palinfo_cpu_notifier);
 
        return 0;
 }
index 6d7bc8ff7b3afff19b3781cdaa91a18d27268772..a0055d3d695c81d2ba042dcbe54d831ffd82a42b 100644 (file)
@@ -6165,7 +6165,7 @@ pfm_load_regs (struct task_struct *task)
                /*
                 * will replay the PMU interrupt
                 */
-               if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR);
+               if (need_irq_resend) ia64_resend_irq(IA64_PERFMON_VECTOR);
 
                pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
        }
@@ -6305,7 +6305,7 @@ pfm_load_regs (struct task_struct *task)
                /*
                 * will replay the PMU interrupt
                 */
-               if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR);
+               if (need_irq_resend) ia64_resend_irq(IA64_PERFMON_VECTOR);
 
                pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
        }
index 663a186ad194a1abfaa7b00b72a7b93afbcbe107..9065f0f01ba3e7f70b48abf36af96cf46b205514 100644 (file)
@@ -572,7 +572,7 @@ static struct file_operations salinfo_data_fops = {
 };
 
 #ifdef CONFIG_HOTPLUG_CPU
-static int
+static int __devinit
 salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
 {
        unsigned int i, cpu = (unsigned long)hcpu;
@@ -673,9 +673,7 @@ salinfo_init(void)
        salinfo_timer.function = &salinfo_timeout;
        add_timer(&salinfo_timer);
 
-#ifdef CONFIG_HOTPLUG_CPU
-       register_cpu_notifier(&salinfo_cpu_notifier);
-#endif
+       register_hotcpu_notifier(&salinfo_cpu_notifier);
 
        return 0;
 }
index 44e9547878ac7310b6f11502d1a709fd5805bd66..5203df78f150cd1d9cf35c5b888a958f4dd10cdd 100644 (file)
@@ -677,16 +677,16 @@ int migrate_platform_irqs(unsigned int cpu)
                        new_cpei_cpu = any_online_cpu(cpu_online_map);
                        mask = cpumask_of_cpu(new_cpei_cpu);
                        set_cpei_target_cpu(new_cpei_cpu);
-                       desc = irq_descp(ia64_cpe_irq);
+                       desc = irq_desc + ia64_cpe_irq;
                        /*
                         * Switch for now, immediatly, we need to do fake intr
                         * as other interrupts, but need to study CPEI behaviour with
                         * polling before making changes.
                         */
                        if (desc) {
-                               desc->handler->disable(ia64_cpe_irq);
-                               desc->handler->set_affinity(ia64_cpe_irq, mask);
-                               desc->handler->enable(ia64_cpe_irq);
+                               desc->chip->disable(ia64_cpe_irq);
+                               desc->chip->set_affinity(ia64_cpe_irq, mask);
+                               desc->chip->enable(ia64_cpe_irq);
                                printk ("Re-targetting CPEI to cpu %d\n", new_cpei_cpu);
                        }
                }
index 879edb51d1e0e1b2c29698815127dc8b215f7067..5511d9c6c70152fe67b1025c1fe8ea8044926760 100644 (file)
 #include <asm/numa.h>
 #include <asm/cpu.h>
 
-#ifdef CONFIG_NUMA
-static struct node *sysfs_nodes;
-#endif
 static struct ia64_cpu *sysfs_cpus;
 
 int arch_register_cpu(int num)
 {
-       struct node *parent = NULL;
-       
-#ifdef CONFIG_NUMA
-       parent = &sysfs_nodes[cpu_to_node(num)];
-#endif /* CONFIG_NUMA */
-
 #if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU)
        /*
         * If CPEI cannot be re-targetted, and this is
@@ -48,21 +39,14 @@ int arch_register_cpu(int num)
                sysfs_cpus[num].cpu.no_control = 1;
 #endif
 
-       return register_cpu(&sysfs_cpus[num].cpu, num, parent);
+       return register_cpu(&sysfs_cpus[num].cpu, num);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
 
 void arch_unregister_cpu(int num)
 {
-       struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
-       int node = cpu_to_node(num);
-       parent = &sysfs_nodes[node];
-#endif /* CONFIG_NUMA */
-
-       return unregister_cpu(&sysfs_cpus[num].cpu, parent);
+       return unregister_cpu(&sysfs_cpus[num].cpu);
 }
 EXPORT_SYMBOL(arch_register_cpu);
 EXPORT_SYMBOL(arch_unregister_cpu);
@@ -74,17 +58,11 @@ static int __init topology_init(void)
        int i, err = 0;
 
 #ifdef CONFIG_NUMA
-       sysfs_nodes = kzalloc(sizeof(struct node) * MAX_NUMNODES, GFP_KERNEL);
-       if (!sysfs_nodes) {
-               err = -ENOMEM;
-               goto out;
-       }
-
        /*
         * MCD - Do we want to register all ONLINE nodes, or all POSSIBLE nodes?
         */
        for_each_online_node(i) {
-               if ((err = register_node(&sysfs_nodes[i], i, 0)))
+               if ((err = register_one_node(i)))
                        goto out;
        }
 #endif
@@ -426,7 +404,7 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev)
  * When a cpu is hot-plugged, do a check and initiate
  * cache kobject if necessary
  */
-static int cache_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
                unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -444,7 +422,7 @@ static int cache_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cache_cpu_notifier =
+static struct notifier_block __cpuinitdata cache_cpu_notifier =
 {
        .notifier_call = cache_cpu_callback
 };
index b6bcc9fa36030690b073440781e48398847ae547..525b082eb6619821fed5224fccadabaf79002cf4 100644 (file)
@@ -33,7 +33,6 @@
  */
 struct early_node_data {
        struct ia64_node_data *node_data;
-       pg_data_t *pgdat;
        unsigned long pernode_addr;
        unsigned long pernode_size;
        struct bootmem_data bootmem_data;
@@ -46,6 +45,8 @@ struct early_node_data {
 static struct early_node_data mem_data[MAX_NUMNODES] __initdata;
 static nodemask_t memory_less_mask __initdata;
 
+static pg_data_t *pgdat_list[MAX_NUMNODES];
+
 /*
  * To prevent cache aliasing effects, align per-node structures so that they
  * start at addresses that are strided by node number.
@@ -99,7 +100,7 @@ static int __init build_node_maps(unsigned long start, unsigned long len,
  * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
  * called yet.  Note that node 0 will also count all non-existent cpus.
  */
-static int __init early_nr_cpus_node(int node)
+static int __meminit early_nr_cpus_node(int node)
 {
        int cpu, n = 0;
 
@@ -114,7 +115,7 @@ static int __init early_nr_cpus_node(int node)
  * compute_pernodesize - compute size of pernode data
  * @node: the node id.
  */
-static unsigned long __init compute_pernodesize(int node)
+static unsigned long __meminit compute_pernodesize(int node)
 {
        unsigned long pernodesize = 0, cpus;
 
@@ -175,13 +176,13 @@ static void __init fill_pernode(int node, unsigned long pernode,
        pernode += PERCPU_PAGE_SIZE * cpus;
        pernode += node * L1_CACHE_BYTES;
 
-       mem_data[node].pgdat = __va(pernode);
+       pgdat_list[node] = __va(pernode);
        pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
 
        mem_data[node].node_data = __va(pernode);
        pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
 
-       mem_data[node].pgdat->bdata = bdp;
+       pgdat_list[node]->bdata = bdp;
        pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
 
        cpu_data = per_cpu_node_setup(cpu_data, node);
@@ -268,7 +269,7 @@ static int __init find_pernode_space(unsigned long start, unsigned long len,
 static int __init free_node_bootmem(unsigned long start, unsigned long len,
                                    int node)
 {
-       free_bootmem_node(mem_data[node].pgdat, start, len);
+       free_bootmem_node(pgdat_list[node], start, len);
 
        return 0;
 }
@@ -287,7 +288,7 @@ static void __init reserve_pernode_space(void)
        int node;
 
        for_each_online_node(node) {
-               pg_data_t *pdp = mem_data[node].pgdat;
+               pg_data_t *pdp = pgdat_list[node];
 
                if (node_isset(node, memory_less_mask))
                        continue;
@@ -307,6 +308,17 @@ static void __init reserve_pernode_space(void)
        }
 }
 
+static void __meminit scatter_node_data(void)
+{
+       pg_data_t **dst;
+       int node;
+
+       for_each_online_node(node) {
+               dst = LOCAL_DATA_ADDR(pgdat_list[node])->pg_data_ptrs;
+               memcpy(dst, pgdat_list, sizeof(pgdat_list));
+       }
+}
+
 /**
  * initialize_pernode_data - fixup per-cpu & per-node pointers
  *
@@ -317,17 +329,10 @@ static void __init reserve_pernode_space(void)
  */
 static void __init initialize_pernode_data(void)
 {
-       pg_data_t *pgdat_list[MAX_NUMNODES];
        int cpu, node;
 
-       for_each_online_node(node)
-               pgdat_list[node] = mem_data[node].pgdat;
+       scatter_node_data();
 
-       /* Copy the pg_data_t list to each node and init the node field */
-       for_each_online_node(node) {
-               memcpy(mem_data[node].node_data->pg_data_ptrs, pgdat_list,
-                      sizeof(pgdat_list));
-       }
 #ifdef CONFIG_SMP
        /* Set the node_data pointer for each per-cpu struct */
        for (cpu = 0; cpu < NR_CPUS; cpu++) {
@@ -372,7 +377,7 @@ static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize)
        if (bestnode == -1)
                bestnode = anynode;
 
-       ptr = __alloc_bootmem_node(mem_data[bestnode].pgdat, pernodesize,
+       ptr = __alloc_bootmem_node(pgdat_list[bestnode], pernodesize,
                PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
 
        return ptr;
@@ -476,7 +481,7 @@ void __init find_memory(void)
                pernodesize = mem_data[node].pernode_size;
                map = pernode + pernodesize;
 
-               init_bootmem_node(mem_data[node].pgdat,
+               init_bootmem_node(pgdat_list[node],
                                  map>>PAGE_SHIFT,
                                  bdp->node_boot_start>>PAGE_SHIFT,
                                  bdp->node_low_pfn);
@@ -786,3 +791,21 @@ void __init paging_init(void)
 
        zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
 }
+
+pg_data_t *arch_alloc_nodedata(int nid)
+{
+       unsigned long size = compute_pernodesize(nid);
+
+       return kzalloc(size, GFP_KERNEL);
+}
+
+void arch_free_nodedata(pg_data_t *pgdat)
+{
+       kfree(pgdat);
+}
+
+void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat)
+{
+       pgdat_list[update_node] = update_pgdat;
+       scatter_node_data();
+}
index 11f08001f8c26e9aaa820b37d379d78eedac0bbd..38306e98f04b2877a076ae7ac4912dee3cebfbab 100644 (file)
@@ -652,7 +652,7 @@ void online_page(struct page *page)
        num_physpages++;
 }
 
-int add_memory(u64 start, u64 size)
+int arch_add_memory(int nid, u64 start, u64 size)
 {
        pg_data_t *pgdat;
        struct zone *zone;
@@ -660,7 +660,7 @@ int add_memory(u64 start, u64 size)
        unsigned long nr_pages = size >> PAGE_SHIFT;
        int ret;
 
-       pgdat = NODE_DATA(0);
+       pgdat = NODE_DATA(nid);
 
        zone = pgdat->node_zones + ZONE_NORMAL;
        ret = __add_pages(zone, start_pfn, nr_pages);
@@ -671,7 +671,6 @@ int add_memory(u64 start, u64 size)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(add_memory);
 
 int remove_memory(u64 start, u64 size)
 {
index 77375a55da312fd7b4ac5ddcb68933aadc381e83..5bef0e3603f2a44e19169a5957bb6a0bf201150a 100644 (file)
@@ -568,7 +568,7 @@ pcibios_disable_device (struct pci_dev *dev)
 
 void
 pcibios_align_resource (void *data, struct resource *res,
-                       unsigned long size, unsigned long align)
+                       resource_size_t size, resource_size_t align)
 {
 }
 
index dc8e2b6967135f7d92f7236b9601c09cc349cc14..7bb6ad188ba39855f1516465e4fee89f5b4ef145 100644 (file)
@@ -27,7 +27,7 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info);
 int sn_force_interrupt_flag = 1;
 extern int sn_ioif_inited;
 struct list_head **sn_irq_lh;
-static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
+static DEFINE_SPINLOCK(sn_irq_info_lock); /* non-IRQ lock */
 
 u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
                                     struct sn_irq_info *sn_irq_info,
@@ -225,8 +225,8 @@ void sn_irq_init(void)
        ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;
 
        for (i = 0; i < NR_IRQS; i++) {
-               if (base_desc[i].handler == &no_irq_type) {
-                       base_desc[i].handler = &irq_type_sn;
+               if (base_desc[i].chip == &no_irq_type) {
+                       base_desc[i].chip = &irq_type_sn;
                }
        }
 }
index 93577abae36da488e4e7bbe87accbf4436a26f80..3bfccf354343740e3fd811b3ff13d5c1a43a2376 100644 (file)
@@ -458,7 +458,7 @@ void __init sn_setup(char **cmdline_p)
         * support here so we don't have to listen to failed keyboard probe
         * messages.
         */
-       if (version <= 0x0209 && acpi_kbd_controller_present) {
+       if (is_shub1() && version <= 0x0209 && acpi_kbd_controller_present) {
                printk(KERN_INFO "Disabling legacy keyboard support as prom "
                       "is too old and doesn't provide FADT\n");
                acpi_kbd_controller_present = 0;
@@ -577,7 +577,8 @@ void __init sn_cpu_init(void)
        int i;
        static int wars_have_been_checked;
 
-       if (smp_processor_id() == 0 && IS_MEDUSA()) {
+       cpuid = smp_processor_id();
+       if (cpuid == 0 && IS_MEDUSA()) {
                if (ia64_sn_is_fake_prom())
                        sn_prom_type = 2;
                else
@@ -596,6 +597,12 @@ void __init sn_cpu_init(void)
                BUG();
        sn_hub_info->as_shift = sn_hub_info->nasid_shift - 2;
 
+       /*
+        * Don't check status. The SAL call is not supported on all PROMs
+        * but a failure is harmless.
+        */
+       (void) ia64_sn_set_cpu_number(cpuid);
+
        /*
         * The boot cpu makes this call again after platform initialization is
         * complete.
@@ -607,7 +614,6 @@ void __init sn_cpu_init(void)
                if (ia64_sn_get_prom_feature_set(i, &sn_prom_features[i]) != 0)
                        break;
 
-       cpuid = smp_processor_id();
        cpuphyid = get_sapicid();
 
        if (ia64_sn_get_sapic_info(cpuphyid, &nasid, &subnode, &slice))
index 20de72791b979d64791fe119f86153b9d2a93a23..e4aa839d0189f57eaa99d673793b0de1ca3a621e 100644 (file)
@@ -595,7 +595,7 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
 
        /* sanity check prom rev */
 
-       if (sn_sal_rev() < 0x0406) {
+       if (is_shub1() && sn_sal_rev() < 0x0406) {
                printk
                    (KERN_ERR "%s:  SGI prom rev 4.06 or greater required "
                     "for tioca support\n", __FUNCTION__);
index a4634b06f67554ffeb3f9c84f33bb213ca493b7b..3841861df6a2a0565fc19aad6b59e8a5fa0490ee 100644 (file)
@@ -54,7 +54,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index 3cd3c2988a4875f6da0c8e2fb8af921264beba42..1ff483c8a4c9749c99d8f70b052ee9d805cc3aa6 100644 (file)
@@ -275,7 +275,7 @@ static int __init topology_init(void)
        int i;
 
        for_each_present_cpu(i)
-               register_cpu(&cpu_devices[i], i, NULL);
+               register_cpu(&cpu_devices[i], i);
 
        return 0;
 }
index 6328e1357a80637c324421ffed54af28e223f804..f9f56c2701951c10f0c44883c57a8f89fa3ddf2b 100644 (file)
@@ -87,7 +87,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on M32104UT-LAN (SMC91C111)*/
        irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].handler = &m32104ut_irq_type;
+       irq_desc[M32R_IRQ_INT0].chip = &m32104ut_irq_type;
        irq_desc[M32R_IRQ_INT0].action = 0;
        irq_desc[M32R_IRQ_INT0].depth = 1;
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11; /* "H" level sense */
@@ -96,7 +96,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &m32104ut_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &m32104ut_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -105,7 +105,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &m32104ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &m32104ut_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = M32R_ICUCR_IEN;
@@ -113,7 +113,7 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &m32104ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &m32104ut_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = M32R_ICUCR_IEN;
index fad1fc99bb272d8b4d485bc9346de58f027c2468..b6ab00eff58057db820edf51c06cfdc08a4b5017 100644 (file)
@@ -301,7 +301,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/
        irq_desc[M32700UT_LAN_IRQ_LAN].status = IRQ_DISABLED;
-       irq_desc[M32700UT_LAN_IRQ_LAN].handler = &m32700ut_lanpld_irq_type;
+       irq_desc[M32700UT_LAN_IRQ_LAN].chip = &m32700ut_lanpld_irq_type;
        irq_desc[M32700UT_LAN_IRQ_LAN].action = 0;
        irq_desc[M32700UT_LAN_IRQ_LAN].depth = 1;       /* disable nested irq */
        lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;   /* "H" edge sense */
@@ -310,7 +310,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -318,7 +318,7 @@ void __init init_IRQ(void)
 
        /* SIO0 : receive */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -326,7 +326,7 @@ void __init init_IRQ(void)
 
        /* SIO0 : send */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -334,7 +334,7 @@ void __init init_IRQ(void)
 
        /* SIO1 : receive */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -342,7 +342,7 @@ void __init init_IRQ(void)
 
        /* SIO1 : send */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -350,7 +350,7 @@ void __init init_IRQ(void)
 
        /* DMA1 : */
        irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_DMA1].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_DMA1].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_DMA1].action = 0;
        irq_desc[M32R_IRQ_DMA1].depth = 1;
        icu_data[M32R_IRQ_DMA1].icucr = 0;
@@ -359,7 +359,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        /* INT#1: SIO0 Receive on PLD */
        irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_RCV].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_RCV].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
        irq_desc[PLD_IRQ_SIO0_RCV].depth = 1;   /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
@@ -367,7 +367,7 @@ void __init init_IRQ(void)
 
        /* INT#1: SIO0 Send on PLD */
        irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_SND].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_SND].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_SIO0_SND].action = 0;
        irq_desc[PLD_IRQ_SIO0_SND].depth = 1;   /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
@@ -376,7 +376,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC IREQ on PLD */
        irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_CFIREQ].action = 0;
        irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
@@ -384,7 +384,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC Insert on PLD */
        irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
        irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
@@ -392,7 +392,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC Eject on PLD */
        irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
        irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
@@ -416,7 +416,7 @@ void __init init_IRQ(void)
        outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
 
     irq_desc[M32700UT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
-    irq_desc[M32700UT_LCD_IRQ_USB_INT1].handler = &m32700ut_lcdpld_irq_type;
+    irq_desc[M32700UT_LCD_IRQ_USB_INT1].chip = &m32700ut_lcdpld_irq_type;
     irq_desc[M32700UT_LCD_IRQ_USB_INT1].action = 0;
     irq_desc[M32700UT_LCD_IRQ_USB_INT1].depth = 1;
     lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */
@@ -434,7 +434,7 @@ void __init init_IRQ(void)
         * INT3# is used for AR
         */
        irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_INT3].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_INT3].action = 0;
        irq_desc[M32R_IRQ_INT3].depth = 1;
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
index 00f253209cb36a0fd8db56407ed88c9d75a5cde0..c268044185f543ed4ffd936996fb29e01c6f1e29 100644 (file)
@@ -86,7 +86,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_NE2000
        /* INT0 : LAN controller (RTL8019AS) */
        irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_INT0].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_INT0].action = 0;
        irq_desc[M32R_IRQ_INT0].depth = 1;
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
@@ -95,7 +95,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -104,7 +104,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -112,7 +112,7 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -120,7 +120,7 @@ void __init init_IRQ(void)
 
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -128,7 +128,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -138,7 +138,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_M32R_PCC)
        /* INT1 : pccard0 interrupt */
        irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_INT1].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_INT1].action = 0;
        irq_desc[M32R_IRQ_INT1].depth = 1;
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
@@ -146,7 +146,7 @@ void __init init_IRQ(void)
 
        /* INT2 : pccard1 interrupt */
        irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_INT2].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_INT2].action = 0;
        irq_desc[M32R_IRQ_INT2].depth = 1;
        icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
index eebc9d8b4e72be56fc49df85fe84fca54def62ec..bd2327d5cca28a1528a8f0ae1fec9b83231a7fec 100644 (file)
@@ -87,7 +87,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT0 : LAN controller (SMC91111) */
        irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_INT0].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_INT0].action = 0;
        irq_desc[M32R_IRQ_INT0].depth = 1;
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
@@ -96,7 +96,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -105,7 +105,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -113,14 +113,14 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO0_S);
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -128,7 +128,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -138,7 +138,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_USB)
        /* INT1 : USB Host controller interrupt */
        irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT1].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_INT1].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_INT1].action = 0;
        irq_desc[M32R_IRQ_INT1].depth = 1;
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
@@ -147,7 +147,7 @@ void __init init_IRQ(void)
 
        /* ICUCR40: CFC IREQ */
        irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].handler = &mappi2_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].chip = &mappi2_irq_type;
        irq_desc[PLD_IRQ_CFIREQ].action = 0;
        irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
@@ -156,7 +156,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_M32R_CFC)
        /* ICUCR41: CFC Insert */
        irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi2_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].chip = &mappi2_irq_type;
        irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
        irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
        icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
@@ -164,7 +164,7 @@ void __init init_IRQ(void)
 
        /* ICUCR42: CFC Eject */
        irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].handler = &mappi2_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].chip = &mappi2_irq_type;
        irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
        irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
        icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
index d2ff021e2d3dc7d1acf2c7f2be0b77601210b1a4..014b51d17505a3e9fd047f79b82f20508d813d9d 100644 (file)
@@ -87,7 +87,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT0 : LAN controller (SMC91111) */
        irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_INT0].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_INT0].action = 0;
        irq_desc[M32R_IRQ_INT0].depth = 1;
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
@@ -96,7 +96,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -105,7 +105,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -113,14 +113,14 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO0_S);
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -128,7 +128,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -138,7 +138,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_USB)
        /* INT1 : USB Host controller interrupt */
        irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT1].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_INT1].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_INT1].action = 0;
        irq_desc[M32R_IRQ_INT1].depth = 1;
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
@@ -147,7 +147,7 @@ void __init init_IRQ(void)
 
        /* CFC IREQ */
        irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].handler = &mappi3_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].chip = &mappi3_irq_type;
        irq_desc[PLD_IRQ_CFIREQ].action = 0;
        irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
@@ -156,7 +156,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_M32R_CFC)
        /* ICUCR41: CFC Insert & eject */
        irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi3_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].chip = &mappi3_irq_type;
        irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
        irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
        icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
@@ -166,7 +166,7 @@ void __init init_IRQ(void)
 
        /* IDE IREQ */
        irq_desc[PLD_IRQ_IDEIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_IDEIREQ].handler = &mappi3_irq_type;
+       irq_desc[PLD_IRQ_IDEIREQ].chip = &mappi3_irq_type;
        irq_desc[PLD_IRQ_IDEIREQ].action = 0;
        irq_desc[PLD_IRQ_IDEIREQ].depth = 1;    /* disable nested irq */
        icu_data[PLD_IRQ_IDEIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
index 0e9e63538c0f051cd95cedf7659c9e845d5c2cb3..ea64831aef7ad536869cfdd9dccb63c6ca47b3f6 100644 (file)
@@ -85,7 +85,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_NE2000
        /* INT3 : LAN controller (RTL8019AS) */
        irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_INT3].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_INT3].action = 0;
        irq_desc[M32R_IRQ_INT3].depth = 1;
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
@@ -94,7 +94,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -103,7 +103,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -111,7 +111,7 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -119,7 +119,7 @@ void __init init_IRQ(void)
 
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -127,7 +127,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
index 548e8fc7949b113a39a697f1cce1407b03c938f5..55e8972d455aedd27a132766a3c89ad42f388474 100644 (file)
@@ -302,7 +302,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/
        irq_desc[OPSPUT_LAN_IRQ_LAN].status = IRQ_DISABLED;
-       irq_desc[OPSPUT_LAN_IRQ_LAN].handler = &opsput_lanpld_irq_type;
+       irq_desc[OPSPUT_LAN_IRQ_LAN].chip = &opsput_lanpld_irq_type;
        irq_desc[OPSPUT_LAN_IRQ_LAN].action = 0;
        irq_desc[OPSPUT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */
        lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;     /* "H" edge sense */
@@ -311,7 +311,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -319,7 +319,7 @@ void __init init_IRQ(void)
 
        /* SIO0 : receive */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -327,7 +327,7 @@ void __init init_IRQ(void)
 
        /* SIO0 : send */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -335,7 +335,7 @@ void __init init_IRQ(void)
 
        /* SIO1 : receive */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -343,7 +343,7 @@ void __init init_IRQ(void)
 
        /* SIO1 : send */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -351,7 +351,7 @@ void __init init_IRQ(void)
 
        /* DMA1 : */
        irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_DMA1].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_DMA1].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_DMA1].action = 0;
        irq_desc[M32R_IRQ_DMA1].depth = 1;
        icu_data[M32R_IRQ_DMA1].icucr = 0;
@@ -360,7 +360,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        /* INT#1: SIO0 Receive on PLD */
        irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_RCV].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_RCV].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
        irq_desc[PLD_IRQ_SIO0_RCV].depth = 1;   /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
@@ -368,7 +368,7 @@ void __init init_IRQ(void)
 
        /* INT#1: SIO0 Send on PLD */
        irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_SND].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_SND].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_SIO0_SND].action = 0;
        irq_desc[PLD_IRQ_SIO0_SND].depth = 1;   /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
@@ -378,7 +378,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_M32R_CFC)
        /* INT#1: CFC IREQ on PLD */
        irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_CFIREQ].action = 0;
        irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
@@ -386,7 +386,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC Insert on PLD */
        irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
        irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
@@ -394,7 +394,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC Eject on PLD */
        irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
        irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
@@ -420,7 +420,7 @@ void __init init_IRQ(void)
        outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
 
     irq_desc[OPSPUT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
-    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].handler = &opsput_lcdpld_irq_type;
+    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].chip = &opsput_lcdpld_irq_type;
     irq_desc[OPSPUT_LCD_IRQ_USB_INT1].action = 0;
     irq_desc[OPSPUT_LCD_IRQ_USB_INT1].depth = 1;
     lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;   /* "L" level sense */
@@ -438,7 +438,7 @@ void __init init_IRQ(void)
         * INT3# is used for AR
         */
        irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_INT3].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_INT3].action = 0;
        irq_desc[M32R_IRQ_INT3].depth = 1;
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
index 64be659a23e7efca76532e72e84c952ec6bd76a3..7fa12d8f66b47d63d8695422d429cc515a7a1f10 100644 (file)
@@ -158,7 +158,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -167,7 +167,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SERIAL_M32R_SIO)
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -175,7 +175,7 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -183,7 +183,7 @@ void __init init_IRQ(void)
 
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -191,7 +191,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -201,7 +201,7 @@ void __init init_IRQ(void)
        /* INT#67-#71: CFC#0 IREQ on PLD */
        for (i = 0 ; i < CONFIG_CFC_NUM ; i++ ) {
                irq_desc[PLD_IRQ_CF0 + i].status = IRQ_DISABLED;
-               irq_desc[PLD_IRQ_CF0 + i].handler = &m32700ut_pld_irq_type;
+               irq_desc[PLD_IRQ_CF0 + i].chip = &m32700ut_pld_irq_type;
                irq_desc[PLD_IRQ_CF0 + i].action = 0;
                irq_desc[PLD_IRQ_CF0 + i].depth = 1;    /* disable nested irq */
                pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr
@@ -212,7 +212,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
        /* INT#76: 16552D#0 IREQ on PLD */
        irq_desc[PLD_IRQ_UART0].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_UART0].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_UART0].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_UART0].action = 0;
        irq_desc[PLD_IRQ_UART0].depth = 1;      /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr
@@ -221,7 +221,7 @@ void __init init_IRQ(void)
 
        /* INT#77: 16552D#1 IREQ on PLD */
        irq_desc[PLD_IRQ_UART1].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_UART1].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_UART1].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_UART1].action = 0;
        irq_desc[PLD_IRQ_UART1].depth = 1;      /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr
@@ -232,7 +232,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE)
        /* INT#80: AK4524 IREQ on PLD */
        irq_desc[PLD_IRQ_SNDINT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SNDINT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SNDINT].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_SNDINT].action = 0;
        irq_desc[PLD_IRQ_SNDINT].depth = 1;     /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr
index 8b6e723eb82bb30371a02aed5508490a74caa9b1..e767f2ddae72a0ca59dabb0e6e16bbfcc8ea11e7 100644 (file)
@@ -540,6 +540,59 @@ config RAM32BIT
 
 endchoice
 
+comment "ROM configuration"
+
+config ROM
+       bool "Specify ROM linker regions"
+       default n
+       help
+         Define a ROM region for the linker script. This creates a kernel
+         that can be stored in flash, with possibly the text, and data
+         regions being copied out to RAM at startup.
+
+config ROMBASE
+       hex "Address of the base of ROM device"
+       default "0"
+       depends on ROM
+       help
+         Define the address that the ROM region starts at. Some platforms
+         use this to set their chip select region accordingly for the boot
+         device.
+
+config ROMVEC
+       hex "Address of the base of the ROM vectors"
+       default "0"
+       depends on ROM
+       help
+         This is almost always the same as the base of the ROM. Since on all
+         68000 type varients the vectors are at the base of the boot device
+         on system startup.
+
+config ROMVECSIZE
+       hex "Size of ROM vector region (in bytes)"
+       default "0x400"
+       depends on ROM
+       help
+         Define the size of the vector region in ROM. For most 68000
+         varients this would be 0x400 bytes in size. Set to 0 if you do
+         not want a vector region at the start of the ROM.
+
+config ROMSTART
+       hex "Address of the base of system image in ROM"
+       default "0x400"
+       depends on ROM
+       help
+         Define the start address of the system image in ROM. Commonly this
+         is strait after the ROM vectors.
+
+config ROMSIZE
+       hex "Size of the ROM device"
+       default "0x100000"
+       depends on ROM
+       help
+         Size of the ROM device. On some platforms this is used to setup
+         the chip select that controls the boot ROM device.
+
 choice
        prompt "Kernel executes from"
        ---help---
index 6f880cbff1c88d00c13723491456027a7e913140..8951793fd8d4aa3446bb60169e23ac807fb40aa0 100644 (file)
@@ -21,6 +21,7 @@ platform-$(CONFIG_M527x)      := 527x
 platform-$(CONFIG_M5272)       := 5272
 platform-$(CONFIG_M528x)       := 528x
 platform-$(CONFIG_M5307)       := 5307
+platform-$(CONFIG_M532x)       := 532x
 platform-$(CONFIG_M5407)       := 5407
 PLATFORM := $(platform-y)
 
@@ -44,6 +45,7 @@ board-$(CONFIG_senTec)                := senTec
 board-$(CONFIG_SNEHA)          := SNEHA
 board-$(CONFIG_M5208EVB)       := M5208EVB
 board-$(CONFIG_MOD5272)                := MOD5272
+board-$(CONFIG_AVNET)           := AVNET
 BOARD := $(board-y)
 
 model-$(CONFIG_RAMKERNEL)      := ram
@@ -65,6 +67,7 @@ cpuclass-$(CONFIG_M527x)      := 5307
 cpuclass-$(CONFIG_M5272)       := 5307
 cpuclass-$(CONFIG_M528x)       := 5307
 cpuclass-$(CONFIG_M5307)       := 5307
+cpuclass-$(CONFIG_M532x)       := 5307
 cpuclass-$(CONFIG_M5407)       := 5307
 cpuclass-$(CONFIG_M68328)      := 68328
 cpuclass-$(CONFIG_M68EZ328)    := 68328
@@ -81,16 +84,17 @@ export PLATFORM BOARD MODEL CPUCLASS
 #
 # Some CFLAG additions based on specific CPU type.
 #
-cflags-$(CONFIG_M5206)         := -m5200 -Wa,-S -Wa,-m5200
-cflags-$(CONFIG_M5206e)                := -m5200 -Wa,-S -Wa,-m5200
-cflags-$(CONFIG_M520x)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M523x)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M5249)         := -m5200 -Wa,-S -Wa,-m5200
-cflags-$(CONFIG_M527x)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M5272)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M528x)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M5307)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M5407)         := -m5200 -Wa,-S -Wa,-m5200
+cflags-$(CONFIG_M5206)         := -m5200
+cflags-$(CONFIG_M5206e)                := -m5200
+cflags-$(CONFIG_M520x)         := -m5307
+cflags-$(CONFIG_M523x)         := -m5307
+cflags-$(CONFIG_M5249)         := -m5200
+cflags-$(CONFIG_M527x)         := -m5307
+cflags-$(CONFIG_M5272)         := -m5307
+cflags-$(CONFIG_M528x)         := -m5307
+cflags-$(CONFIG_M5307)         := -m5307
+cflags-$(CONFIG_M532x)         := -m5307
+cflags-$(CONFIG_M5407)         := -m5200
 cflags-$(CONFIG_M68328)                := -m68000
 cflags-$(CONFIG_M68EZ328)      := -m68000
 cflags-$(CONFIG_M68VZ328)      := -m68000
index 2d59ba1a79ba4e984b6a3d1bc3d6d18e648c4c94..3891de09ac2372e1fcd51a11e8ea44a12cfe3262 100644 (file)
@@ -1,21 +1,22 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13-uc0
-# Wed Aug 31 15:03:26 2005
+# Linux kernel version: 2.6.17
+# Tue Jun 27 12:57:06 2006
 #
-CONFIG_M68KNOMMU=y
+CONFIG_M68K=y
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
-CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_TIME_LOW_RES=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -23,32 +24,54 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
 # General setup
 #
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SYSVIPC is not set
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_KOBJECT_UEVENT is not set
 # CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
 #
 # CONFIG_MODULES is not set
 
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
 #
 # Processor type and features
 #
@@ -58,6 +81,7 @@ CONFIG_BASE_SMALL=0
 # CONFIG_M68360 is not set
 # CONFIG_M5206 is not set
 # CONFIG_M5206e is not set
+# CONFIG_M520x is not set
 # CONFIG_M523x is not set
 # CONFIG_M5249 is not set
 # CONFIG_M5271 is not set
@@ -65,29 +89,12 @@ CONFIG_M5272=y
 # CONFIG_M5275 is not set
 # CONFIG_M528x is not set
 # CONFIG_M5307 is not set
+# CONFIG_M532x is not set
 # CONFIG_M5407 is not set
 CONFIG_COLDFIRE=y
-# CONFIG_CLOCK_AUTO is not set
-# CONFIG_CLOCK_11MHz is not set
-# CONFIG_CLOCK_16MHz is not set
-# CONFIG_CLOCK_20MHz is not set
-# CONFIG_CLOCK_24MHz is not set
-# CONFIG_CLOCK_25MHz is not set
-# CONFIG_CLOCK_33MHz is not set
-# CONFIG_CLOCK_40MHz is not set
-# CONFIG_CLOCK_45MHz is not set
-# CONFIG_CLOCK_48MHz is not set
-# CONFIG_CLOCK_50MHz is not set
-# CONFIG_CLOCK_54MHz is not set
-# CONFIG_CLOCK_60MHz is not set
-# CONFIG_CLOCK_62_5MHz is not set
-# CONFIG_CLOCK_64MHz is not set
-CONFIG_CLOCK_66MHz=y
-# CONFIG_CLOCK_70MHz is not set
-# CONFIG_CLOCK_100MHz is not set
-# CONFIG_CLOCK_140MHz is not set
-# CONFIG_CLOCK_150MHz is not set
-# CONFIG_CLOCK_166MHz is not set
+CONFIG_CLOCK_SET=y
+CONFIG_CLOCK_FREQ=66666666
+CONFIG_CLOCK_DIV=1
 
 #
 # Platform
@@ -102,11 +109,14 @@ CONFIG_M5272C3=y
 CONFIG_FREESCALE=y
 # CONFIG_LARGE_ALLOCS is not set
 CONFIG_4KSTACKS=y
-CONFIG_RAMAUTO=y
-# CONFIG_RAM4MB is not set
-# CONFIG_RAM8MB is not set
-# CONFIG_RAM16MB is not set
-# CONFIG_RAM32MB is not set
+
+#
+# RAM configuration
+#
+CONFIG_RAMBASE=0x0
+CONFIG_RAMSIZE=0x800000
+CONFIG_VECTORBASE=0x0
+CONFIG_KERNELBASE=0x20000
 CONFIG_RAMAUTOBIT=y
 # CONFIG_RAM8BIT is not set
 # CONFIG_RAM16BIT is not set
@@ -119,6 +129,8 @@ CONFIG_FLATMEM_MANUAL=y
 # 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
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -140,6 +152,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_BINFMT_FLAT=y
 # CONFIG_BINFMT_ZFLAT is not set
 # CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
@@ -155,6 +168,7 @@ CONFIG_NET=y
 #
 # Networking options
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -171,18 +185,30 @@ CONFIG_IP_FIB_HASH=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
 # CONFIG_INET_TUNNEL is not set
-# CONFIG_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_INET_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
 # CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETFILTER is not set
 
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
@@ -195,8 +221,11 @@ CONFIG_TCP_CONG_BIC=y
 # 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
-# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -205,6 +234,7 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
 
 #
 # Device Drivers
@@ -217,6 +247,11 @@ 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)
 #
@@ -235,6 +270,7 @@ 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
@@ -254,13 +290,13 @@ CONFIG_MTD_CFI_I2=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_UCLINUX=y
-# CONFIG_MTD_SNAPGEARuC is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -269,7 +305,6 @@ CONFIG_MTD_UCLINUX=y
 # 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
 
 #
@@ -284,6 +319,11 @@ CONFIG_MTD_UCLINUX=y
 #
 # CONFIG_MTD_NAND is not set
 
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
 #
 # Parallel port support
 #
@@ -296,7 +336,6 @@ CONFIG_MTD_UCLINUX=y
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -304,16 +343,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
-CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_ATA_OVER_ETH is not set
 
 #
@@ -324,6 +354,7 @@ CONFIG_IOSCHED_NOOP=y
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
 
 #
@@ -353,14 +384,16 @@ CONFIG_NETDEVICES=y
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NE2000 is not set
-# CONFIG_NET_PCI is not set
 CONFIG_FEC=y
 # CONFIG_FEC2 is not set
 
@@ -392,6 +425,7 @@ CONFIG_PPP=y
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
@@ -425,8 +459,6 @@ CONFIG_PPP=y
 #
 # CONFIG_VT is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_LEDMAN is not set
-# CONFIG_RESETSWITCH is not set
 
 #
 # Serial drivers
@@ -450,8 +482,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_MCFWATCHDOG is not set
-# CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
@@ -464,14 +494,19 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # TPM devices
 #
-# CONFIG_MCF_QSPI is not set
-# CONFIG_M41T11M6 is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
 #
 # CONFIG_I2C is not set
-# CONFIG_I2C_SENSOR is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
 
 #
 # Dallas's 1-wire bus
@@ -482,6 +517,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Hardware Monitoring support
 #
 # CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
 
 #
 # Misc devices
@@ -491,6 +527,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
 
 #
 # Digital Video Broadcasting Devices
@@ -502,11 +539,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # CONFIG_FB is not set
 
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-
 #
 # Sound
 #
@@ -517,6 +549,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
 
 #
 # USB Gadget Support
@@ -528,14 +565,32 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # CONFIG_MMC is not set
 
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
 #
 # InfiniBand support
 #
 
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
 #
 # File systems
 #
@@ -543,15 +598,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-
-#
-# XFS support
-#
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_INOTIFY is not set
@@ -559,6 +610,7 @@ CONFIG_ROMFS_FS=y
 # CONFIG_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -581,6 +633,7 @@ CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -611,6 +664,7 @@ CONFIG_RAMFS=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -627,8 +681,12 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
 # CONFIG_FULLDEBUG is not set
 # CONFIG_HIGHPROFILE is not set
 # CONFIG_BOOTPARAM is not set
@@ -655,5 +713,6 @@ CONFIG_LOG_BUF_SHIFT=14
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 # CONFIG_CRC32 is not set
 # CONFIG_LIBCRC32C is not set
index 8670938f1107a5f9c6a03d2e9bce29ca2d53f19e..db7a0c1cebae8dfe88ad393fa47eefc711790fdc 100644 (file)
@@ -357,7 +357,8 @@ void pcibios_fixup_bus(struct pci_bus *b)
 
 /*****************************************************************************/
 
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align)
+void pcibios_align_resource(void *data, struct resource *res,
+                               resource_size_t size, resource_size_t align)
 {
 }
 
index 6a2f0c6932547079639ebf10ff11955660ad5a3e..59ced831b79214358ef5a5bec9d6bb9def55df4d 100644 (file)
@@ -3,63 +3,13 @@
  *
  *     (C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com>
  *
- *     This ends up looking compilcated, because of the number of
- *     address variations for ram and rom/flash layouts. The real
- *     work of the linker script is all at the end, and reasonably
- *     strait forward.
+ *     This linker script is equiped to build either ROM loaded or RAM
+ *     run kernels.
  */
 
 #include <linux/config.h>
 #include <asm-generic/vmlinux.lds.h>
 
-/*
- *     Original Palm pilot (same for Xcopilot).
- *     There is really only a rom target for this.
- */
-#ifdef CONFIG_PILOT3
-#define        ROMVEC_START    0x10c00000
-#define        ROMVEC_LENGTH   0x10400
-#define        ROM_START       0x10c10400
-#define        ROM_LENGTH      0xfec00
-#define        ROM_END         0x10d00000
-#define        DATA_ADDR       CONFIG_KERNELBASE
-#endif
-
-/*
- *     Same setup on both the uCsimm and uCdimm.
- */
-#if defined(CONFIG_UCSIMM) || defined(CONFIG_UCDIMM)
-#ifdef CONFIG_RAMKERNEL
-#define        ROMVEC_START    0x10c10000
-#define        ROMVEC_LENGTH   0x400
-#define        ROM_START       0x10c10400
-#define        ROM_LENGTH      0x1efc00
-#define        ROM_END         0x10e00000
-#endif
-#ifdef CONFIG_ROMKERNEL
-#define        ROMVEC_START    0x10c10000
-#define        ROMVEC_LENGTH   0x400
-#define        ROM_START       0x10c10400
-#define        ROM_LENGTH      0x1efc00
-#define        ROM_END         0x10e00000
-#endif
-#ifdef CONFIG_HIMEMKERNEL
-#define        ROMVEC_START    0x00600000
-#define        ROMVEC_LENGTH   0x400
-#define        ROM_START       0x00600400
-#define        ROM_LENGTH      0x1efc00
-#define        ROM_END         0x007f0000
-#endif
-#endif
-
-#ifdef CONFIG_UCQUICC
-#define        ROMVEC_START    0x00000000
-#define        ROMVEC_LENGTH   0x404
-#define        ROM_START       0x00000404
-#define        ROM_LENGTH      0x1ff6fc
-#define        ROM_END         0x00200000
-#endif
-
 #if defined(CONFIG_RAMKERNEL)
 #define        RAM_START       CONFIG_KERNELBASE
 #define        RAM_LENGTH      (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
 #if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
 #define        RAM_START       CONFIG_RAMBASE
 #define        RAM_LENGTH      CONFIG_RAMSIZE
+#define        ROMVEC_START    CONFIG_ROMVEC
+#define        ROMVEC_LENGTH   CONFIG_ROMVECSIZE
+#define        ROM_START       CONFIG_ROMSTART
+#define        ROM_LENGTH      CONFIG_ROMSIZE
 #define        TEXT            rom
 #define        DATA            ram
 #define        INIT            ram
@@ -90,7 +44,6 @@ MEMORY {
 #ifdef ROM_START
        romvec  : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
        rom     : ORIGIN = ROM_START, LENGTH = ROM_LENGTH
-       erom    : ORIGIN = ROM_END, LENGTH = 0
 #endif
 }
 
@@ -167,13 +120,6 @@ SECTIONS {
                _etext = . ;
        } > TEXT
 
-#ifdef ROM_END
-       . = ROM_END ;
-       .erom : {
-               __rom_end = . ;
-       } > erom
-#endif
-
        .data DATA_ADDR : {
                . = ALIGN(4);
                _sdata = . ;
index 1b3b719e4479d0458b81e55807ff6d47b0d14bc4..5e5435552d5652da8b4e1b0fa6f81c24a9a028b4 100644 (file)
@@ -8,6 +8,7 @@ head-$(CONFIG_DRAGEN2)  = head-de2.o
 
 obj-y                  += entry.o ints.o timers.o
 obj-$(CONFIG_M68328)   += config.o
+obj-$(CONFIG_ROM)      += romvec.o
 
 extra-y                        := head.o
 extra-$(CONFIG_M68328) += bootlogo.rh head.o
index 2b448a297011f43ed1a26924fe22e6ef0eecb9b9..234430b9551c96fef3e32ff370b69a1500c0fda2 100644 (file)
@@ -28,6 +28,8 @@ _ramstart:
 _ramend:
 .long   0
 
+#define        RAMEND  (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
 #ifdef CONFIG_INIT_LCD
 splash_bits:
 #include "bootlogo.rh"
@@ -48,7 +50,7 @@ _stext:       movew   #0x2700,%sr
        moveb   #0x81,   0xfffffA27     /* LCKCON */
        movew   #0xff00, 0xfffff412     /* LCD pins */
 #endif
-       moveal  #__ramend-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
+       moveal  #RAMEND-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
        movew   #32767, %d0  /* PLL settle wait loop */
 1:     subq    #1, %d0
        bne     1b
@@ -73,13 +75,13 @@ _stext:     movew   #0x2700,%sr
        bhi     1b
 
         movel   #_sdata, %d0    
-        movel   %d0,    _rambase        
-        movel   #_ebss,  %d0
-        movel   %d0,    _ramstart
-       movel   #__ramend-CONFIG_MEMORY_RESERVE*0x100000, %d0
-       movel   %d0,    _ramend
-       movel   #__ramvec,      %d0
-       movel   %d0,    _ramvec
+        movel   %d0, _rambase        
+        movel   #_ebss, %d0
+        movel   %d0, _ramstart
+       movel   #RAMEND-CONFIG_MEMORY_RESERVE*0x100000, %d0
+       movel   %d0, _ramend
+       movel   #CONFIG_VECTORBASE,     %d0
+       movel   %d0, _ramvec
        
 /*
  * load the current task pointer and stack
index 7437217813d2cd6099227f78dfe24fbc79b0bff8..2dda7339aae5cf00136df28f0896926144d0674f 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/system.h>
 #include <asm/irq.h>
+#include <asm/irqnode.h>
 #include <asm/traps.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
@@ -82,25 +83,6 @@ unsigned int local_irq_count[NR_CPUS];
 /* irq node variables for the 32 (potential) on chip sources */
 static irq_node_t int_irq_list[NR_IRQS];
 
-#if !defined(CONFIG_DRAGEN2)
-asm (".global _start, __ramend/n/t"
-     ".section .romvec/n"
-     "e_vectors:\n\t"
-     ".long __ramend-4, _start, buserr, trap, trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap, trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap, trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap\n\t"
-       /*.long inthandler, inthandler, inthandler, inthandler
-       .long inthandler4, inthandler, inthandler, inthandler   */
-       /* TRAP #0-15 */
-     ".long system_call, trap, trap, trap, trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap, trap, trap, trap, trap\n\t"
-     ".long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n\t"
-     ".text\n"
-     "ignore: rte");
-#endif
-
 /*
  * This function should be called during kernel startup to initialize
  * the IRQ handling routines.
diff --git a/arch/m68knommu/platform/68328/romvec.S b/arch/m68knommu/platform/68328/romvec.S
new file mode 100644 (file)
index 0000000..3e7fe1e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * linux/arch/m68knommu/platform/68328/romvec.S
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Copyright 1996 Roman Zippel
+ * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
+ * Copyright 2006 Greg Ungerer <gerg@snapgear.com>
+ */
+
+#include <linux/config.h>
+
+.global _start
+.global _buserr
+.global trap
+.global system_call
+
+.section .romvec
+
+e_vectors:
+.long CONFIG_RAMBASE+CONFIG_RAMSIZE-4, _start, buserr, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+/* TRAP #0-15 */
+.long system_call, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+
index 3db244625f0fc2c59b2d3f931b18a8f49147f34e..69c670dfd62bb99b77c607b85fb2e0ce61a8f024 100644 (file)
@@ -141,13 +141,13 @@ int BSP_set_clock_mmss (unsigned long nowtime)
 void BSP_reset (void)
 {
   local_irq_disable();
-  asm volatile ("
-    moveal #_start, %a0;
-    moveb #0, 0xFFFFF300;
-    moveal 0(%a0), %sp;
-    moveal 4(%a0), %a0;
-    jmp (%a0);
-    ");
+  asm volatile (
+    "moveal #_start, %a0;\n"
+    "moveb #0, 0xFFFFF300;\n"
+    "moveal 0(%a0), %sp;\n"
+    "moveal 4(%a0), %a0;\n"
+    "jmp (%a0);\n"
+    );
 }
 
 unsigned char *scc1_hwaddr;
index a5c639a51eefd2a5a11ae0b13cc6f040e8d836e8..f497713a4ec7ea72dfbc2a1fc4736c66000d233a 100644 (file)
@@ -18,7 +18,6 @@
 .global _start
 
 .global _rambase
-.global __ramvec
 .global _ramvec
 .global _ramstart
 .global _ramend
@@ -26,6 +25,8 @@
 .global _quicc_base
 .global _periph_base
 
+#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
 #define REGB                        0x1000
 #define PEPAR                       (_dprbase + REGB + 0x0016)
 #define GMR                         (_dprbase + REGB + 0x0040)
@@ -103,7 +104,7 @@ _stext:
        nop
        ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
        /* We should not need to setup the boot stack the reset should do it. */
-       movea.l #__ramend, %sp                  /*set up stack at the end of DRAM:*/
+       movea.l #RAMEND, %sp                    /*set up stack at the end of DRAM:*/
 
 set_mbar_register:
        moveq.l #0x07, %d1                      /* Setup MBAR */
@@ -163,7 +164,7 @@ configure_memory_controller:
        move.l  %d0, GMR
 
 configure_chip_select_0:
-       move.l  #__ramend, %d0
+       move.l  #RAMEND, %d0
        subi.l  #__ramstart, %d0
        subq.l  #0x01, %d0
        eori.l  #SIM_OR_MASK, %d0
@@ -234,16 +235,10 @@ store_ram_size:
        /* Set ram size information */
        move.l  #_sdata, _rambase
        move.l  #_ebss, _ramstart
-       move.l  #__ramend, %d0
+       move.l  #RAMEND, %d0
        sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
-       move.l  %d0, _ramend                    /* Different from __ramend.*/
+       move.l  %d0, _ramend                    /* Different from RAMEND.*/
 
-store_flash_size:
-       /* Set rom size information */
-       move.l  #__rom_end, %d0
-       sub.l   #__rom_start, %d0
-       move.l  %d0, rom_length
-    
        pea     0
        pea     env
        pea     %sp@(4)
@@ -286,7 +281,7 @@ _dprbase:
      */
  
 .section ".data.initvect","awx"
-    .long   __ramend   /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
     .long   _start      /* Reset: Initial Program Counter               - 1.  */
     .long   buserr      /* Bus Error                                    - 2.  */
     .long   trap        /* Address Error                                - 3.  */
index 0da357a4cfee407d141321af4837bbdb5e77f67f..2d28c3e19a881894d2f2389f0691db2364b06f29 100644 (file)
@@ -18,7 +18,6 @@
 .global _start
 
 .global _rambase
-.global __ramvec
 .global _ramvec
 .global _ramstart
 .global _ramend
@@ -26,6 +25,8 @@
 .global _quicc_base
 .global _periph_base
 
+#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
 #define REGB                        0x1000
 #define PEPAR                       (_dprbase + REGB + 0x0016)
 #define GMR                         (_dprbase + REGB + 0x0040)
@@ -115,7 +116,7 @@ _stext:
        nop
        ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
        /* We should not need to setup the boot stack the reset should do it. */
-       movea.l #__ramend, %sp          /* set up stack at the end of DRAM:*/
+       movea.l #RAMEND, %sp            /* set up stack at the end of DRAM:*/
 
 
 set_mbar_register:
@@ -245,16 +246,10 @@ store_ram_size:
        /* Set ram size information */
        move.l  #_sdata, _rambase
        move.l  #_ebss, _ramstart
-       move.l  #__ramend, %d0
+       move.l  #RAMEND, %d0
        sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
-       move.l  %d0, _ramend                    /* Different from __ramend.*/
+       move.l  %d0, _ramend                    /* Different from RAMEND.*/
 
-store_flash_size:
-       /* Set rom size information */
-       move.l  #__rom_end, %d0
-       sub.l   #__rom_start, %d0
-       move.l  %d0, rom_length
-    
        pea     0
        pea     env
        pea     %sp@(4)
@@ -298,7 +293,7 @@ _dprbase:
      */
  
 .section ".data.initvect","awx"
-    .long   __ramend   /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
     .long   _start      /* Reset: Initial Program Counter               - 1.  */
     .long   buserr      /* Bus Error                                    - 2.  */
     .long   trap        /* Address Error                                - 3.  */
index ba184db1651b60daba705d4aaf56315ace42d145..0245fc4a478127223578387c346ff05970e42571 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <asm/system.h>
 #include <asm/irq.h>
+#include <asm/irqnode.h>
 #include <asm/traps.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
index d8d56e5de31073b38e73a5477097d0c20567631d..15a14a67c2bf016ffe2569a9a6505a8b37580d82 100644 (file)
@@ -42,13 +42,13 @@ void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int
 void m68ez328_reset(void)
 {
   local_irq_disable();
-  asm volatile ("
-    moveal #0x10c00000, %a0;
-    moveb #0, 0xFFFFF300;
-    moveal 0(%a0), %sp;
-    moveal 4(%a0), %a0;
-    jmp (%a0);
-    ");
+  asm volatile (
+    "moveal #0x10c00000, %a0;\n"
+    "moveb #0, 0xFFFFF300;\n"
+    "moveal 0(%a0), %sp;\n"
+    "moveal 4(%a0), %a0;\n"
+    "jmp (%a0);\n"
+    );
 }
 
 /***************************************************************************/
index d926524cdf82632e9b456996a61406694fbf3fea..4058de5c8fa2f665cdcd658fcf452c29a98216a4 100644 (file)
@@ -141,13 +141,13 @@ static void init_hardware(char *command, int size)
 static void m68vz328_reset(void)
 {
        local_irq_disable();
-       asm volatile ("
-               moveal #0x10c00000, %a0;
-               moveb #0, 0xFFFFF300;
-               moveal 0(%a0), %sp;
-               moveal 4(%a0), %a0;
-               jmp (%a0);
-       ");
+       asm volatile (
+               "moveal #0x10c00000, %a0;\n\t"
+               "moveb #0, 0xFFFFF300;\n\t"
+               "moveal 0(%a0), %sp;\n\t"
+               "moveal 4(%a0), %a0;\n\t"
+               "jmp (%a0);\n"
+       );
 }
 
 unsigned char *cs8900a_hwaddr;
index 35e038a974c6227940cc4ebe7c5ead85d52e4a65..08c2ece4ae405387d51269b80eec228dbee18dd7 100644 (file)
@@ -1618,6 +1618,11 @@ config GENERIC_IRQ_PROBE
        bool
        default y
 
+config IRQ_PER_CPU
+       depends on SMP
+       bool
+       default y
+
 #
 # - Highmem only makes sense for the 32-bit kernel.
 # - The current highmem code will only work properly on physically indexed
index afe05ec12c27d31326d73937081eb7e0631d1c33..da74ac21954bb573408c7936b471092cb03a50d9 100644 (file)
@@ -333,31 +333,31 @@ static void setup_local_irq(unsigned int irq_nr, int type, int int_req)
                                au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG0SET);
-                               irq_desc[irq_nr].handler = &rise_edge_irq_type;
+                               irq_desc[irq_nr].chip = &rise_edge_irq_type;
                                break;
                        case INTC_INT_FALL_EDGE: /* 0:1:0 */
                                au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG1SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
-                               irq_desc[irq_nr].handler = &fall_edge_irq_type;
+                               irq_desc[irq_nr].chip = &fall_edge_irq_type;
                                break;
                        case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */
                                au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG1SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG0SET);
-                               irq_desc[irq_nr].handler = &either_edge_irq_type;
+                               irq_desc[irq_nr].chip = &either_edge_irq_type;
                                break;
                        case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
                                au_writel(1<<(irq_nr-32), IC1_CFG2SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG0SET);
-                               irq_desc[irq_nr].handler = &level_irq_type;
+                               irq_desc[irq_nr].chip = &level_irq_type;
                                break;
                        case INTC_INT_LOW_LEVEL: /* 1:1:0 */
                                au_writel(1<<(irq_nr-32), IC1_CFG2SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG1SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
-                               irq_desc[irq_nr].handler = &level_irq_type;
+                               irq_desc[irq_nr].chip = &level_irq_type;
                                break;
                        case INTC_INT_DISABLED: /* 0:0:0 */
                                au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
@@ -385,31 +385,31 @@ static void setup_local_irq(unsigned int irq_nr, int type, int int_req)
                                au_writel(1<<irq_nr, IC0_CFG2CLR);
                                au_writel(1<<irq_nr, IC0_CFG1CLR);
                                au_writel(1<<irq_nr, IC0_CFG0SET);
-                               irq_desc[irq_nr].handler = &rise_edge_irq_type;
+                               irq_desc[irq_nr].chip = &rise_edge_irq_type;
                                break;
                        case INTC_INT_FALL_EDGE: /* 0:1:0 */
                                au_writel(1<<irq_nr, IC0_CFG2CLR);
                                au_writel(1<<irq_nr, IC0_CFG1SET);
                                au_writel(1<<irq_nr, IC0_CFG0CLR);
-                               irq_desc[irq_nr].handler = &fall_edge_irq_type;
+                               irq_desc[irq_nr].chip = &fall_edge_irq_type;
                                break;
                        case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */
                                au_writel(1<<irq_nr, IC0_CFG2CLR);
                                au_writel(1<<irq_nr, IC0_CFG1SET);
                                au_writel(1<<irq_nr, IC0_CFG0SET);
-                               irq_desc[irq_nr].handler = &either_edge_irq_type;
+                               irq_desc[irq_nr].chip = &either_edge_irq_type;
                                break;
                        case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
                                au_writel(1<<irq_nr, IC0_CFG2SET);
                                au_writel(1<<irq_nr, IC0_CFG1CLR);
                                au_writel(1<<irq_nr, IC0_CFG0SET);
-                               irq_desc[irq_nr].handler = &level_irq_type;
+                               irq_desc[irq_nr].chip = &level_irq_type;
                                break;
                        case INTC_INT_LOW_LEVEL: /* 1:1:0 */
                                au_writel(1<<irq_nr, IC0_CFG2SET);
                                au_writel(1<<irq_nr, IC0_CFG1SET);
                                au_writel(1<<irq_nr, IC0_CFG0CLR);
-                               irq_desc[irq_nr].handler = &level_irq_type;
+                               irq_desc[irq_nr].chip = &level_irq_type;
                                break;
                        case INTC_INT_DISABLED: /* 0:0:0 */
                                au_writel(1<<irq_nr, IC0_CFG0CLR);
index bacc0c6bfe675e5f3570371ea4f98a9004664ee7..5dd164fc1889290e243d0855ba1978aecf932dc7 100644 (file)
@@ -172,7 +172,7 @@ void _board_init_irq(void)
 
        for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++)
        {
-               irq_desc[irq_nr].handler = &external_irq_type;
+               irq_desc[irq_nr].chip = &external_irq_type;
                pb1200_disable_irq(irq_nr);
        }
 
index 5fcd5f070cdcf6a52cdf5a9ed52185be36932fbb..63c3d6534b3a108bd8d87d11838d585fea80e790 100644 (file)
@@ -107,7 +107,7 @@ void __init vrc5477_irq_init(u32 irq_base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &vrc5477_irq_controller;
+               irq_desc[i].chip = &vrc5477_irq_controller;
        }
 
        vrc5477_irq_base = irq_base;
index d5bca5d233b6e6b67d32546d7789b9be1052926f..da2dbb42f913fc21bfd7dd0177d5ec393ae5a82c 100644 (file)
@@ -144,13 +144,13 @@ void __init init_ioasic_irqs(int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &ioasic_irq_type;
+               irq_desc[i].chip = &ioasic_irq_type;
        }
        for (; i < base + IO_IRQ_LINES; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &ioasic_dma_irq_type;
+               irq_desc[i].chip = &ioasic_dma_irq_type;
        }
 
        ioasic_irq_base = base;
index 898bed502a348fb3a7572e8bd65d550a20d0f46c..d44c00d9e80fa973f32100d4e8c192d4d53b741c 100644 (file)
@@ -123,7 +123,7 @@ void __init init_kn02_irqs(int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &kn02_irq_type;
+               irq_desc[i].chip = &kn02_irq_type;
        }
 
        kn02_irq_base = base;
index 46c468b26b30879c72b82e01e52a271b32e61d2a..f489a8067a93fa46570378fd85a5345beb78226c 100644 (file)
@@ -138,7 +138,7 @@ void __init arch_init_irq(void)
        /*  Let's initialize our IRQ descriptors  */
        for (i = 0; i < NR_IRQS; i++) {
                irq_desc[i].status = 0;
-               irq_desc[i].handler = &no_irq_type;
+               irq_desc[i].chip = &no_irq_type;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 0;
                spin_lock_init(&irq_desc[i].lock);
index 77be7216bdd091430735ccb89c1e356144a779fd..a6749c56fe38d620ea29ca4546fc6a79baf31470 100644 (file)
@@ -208,10 +208,10 @@ void __init arch_init_irq(void)
 #endif
 
        for (i = 0; i <= IT8172_LAST_IRQ; i++) {
-               irq_desc[i].handler = &it8172_irq_type;
+               irq_desc[i].chip = &it8172_irq_type;
                spin_lock_init(&irq_desc[i].lock);
        }
-       irq_desc[MIPS_CPU_TIMER_IRQ].handler = &cp0_irq_type;
+       irq_desc[MIPS_CPU_TIMER_IRQ].chip = &cp0_irq_type;
        set_c0_status(ALLINTS_NOTIMER);
 }
 
index becc9accd49573e5d24e052a8e3d8e2e40699339..478be9858a1e04117eb3456e2200119a083b9f04 100644 (file)
@@ -73,7 +73,7 @@ void __init init_r4030_ints(void)
                irq_desc[i].status     = IRQ_DISABLED;
                irq_desc[i].action     = 0;
                irq_desc[i].depth      = 1;
-               irq_desc[i].handler    = &r4030_irq_type;
+               irq_desc[i].chip    = &r4030_irq_type;
        }
 
        r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0);
index 11304d1354f45b0d47afc511e9a7811fa9383ca6..380046ea1db55103f5ddbcc2c23e459b951c04ac 100644 (file)
@@ -435,7 +435,7 @@ void jmr3927_irq_init(u32 irq_base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &jmr3927_irq_controller;
+               irq_desc[i].chip = &jmr3927_irq_controller;
        }
 
        jmr3927_irq_base = irq_base;
index 0cb8ed5662f3d2cbaa1f0ac6cde7cbfa6f5ff8bb..91ffb1233cad92cda4ce6ad163bc880798f7533a 100644 (file)
@@ -120,7 +120,7 @@ int i8259A_irq_pending(unsigned int irq)
 void make_8259A_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &i8259A_irq_type;
+       irq_desc[irq].chip = &i8259A_irq_type;
        enable_irq(irq);
 }
 
@@ -327,7 +327,7 @@ void __init init_i8259_irqs (void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &i8259A_irq_type;
+               irq_desc[i].chip = &i8259A_irq_type;
        }
 
        setup_irq(2, &irq2);
index 97ebdc754b9e6e8a59a1edf02611819872e606fb..f8cd1ac64d88314785849eec94f3d801b49943d7 100644 (file)
@@ -174,14 +174,14 @@ void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq)
 
                switch (imp->im_type) {
                case MSC01_IRQ_EDGE:
-                       irq_desc[base+n].handler = &msc_edgeirq_type;
+                       irq_desc[base+n].chip = &msc_edgeirq_type;
                        if (cpu_has_veic)
                                MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT);
                        else
                                MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl);
                        break;
                case MSC01_IRQ_LEVEL:
-                       irq_desc[base+n].handler = &msc_levelirq_type;
+                       irq_desc[base+n].chip = &msc_levelirq_type;
                        if (cpu_has_veic)
                                MSCIC_WRITE(MSC01_IC_SUP+n*8, 0);
                        else
index 0613f1f36b1bb0f9dabb0adfcbfbf98b5d378e3c..f9c763a65547f0cc8760aaa8eaf61d8bdbe7d1b4 100644 (file)
@@ -155,7 +155,7 @@ void __init mv64340_irq_init(unsigned int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 2;
-               irq_desc[i].handler = &mv64340_irq_type;
+               irq_desc[i].chip = &mv64340_irq_type;
        }
 
        irq_base = base;
index 0b130c5ac5d915d6eee4df811cd4b7a5543b2c50..121da385a94d05216488abe15a20b398521e5ff4 100644 (file)
@@ -91,7 +91,7 @@ void __init rm7k_cpu_irq_init(int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &rm7k_irq_controller;
+               irq_desc[i].chip = &rm7k_irq_controller;
        }
 
        irq_base = base;
index 9b5f20c32acb97177b946fdb1c1a863c1a03cd1b..25109c103e44dff4ed3216ce45f7f27a39bc1732 100644 (file)
@@ -139,11 +139,11 @@ void __init rm9k_cpu_irq_init(int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &rm9k_irq_controller;
+               irq_desc[i].chip = &rm9k_irq_controller;
        }
 
        rm9000_perfcount_irq = base + 1;
-       irq_desc[rm9000_perfcount_irq].handler = &rm9k_perfcounter_irq;
+       irq_desc[rm9000_perfcount_irq].chip = &rm9k_perfcounter_irq;
 
        irq_base = base;
 }
index 3dce742e716fd3df1b36920dc3606d2e91fb056b..5c9dcd5eed59e7cf3459381990e873346d329d5a 100644 (file)
@@ -95,7 +95,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -137,7 +137,7 @@ void __init init_IRQ(void)
                irq_desc[i].status  = IRQ_DISABLED;
                irq_desc[i].action  = NULL;
                irq_desc[i].depth   = 1;
-               irq_desc[i].handler = &no_irq_type;
+               irq_desc[i].chip = &no_irq_type;
                spin_lock_init(&irq_desc[i].lock);
 #ifdef CONFIG_MIPS_MT_SMTC
                irq_hwmask[i] = 0;
index 5db67e31ec1accf28c0150ed43a8d91176a3609a..0e455a8ad860d612fa282a775d962275cc5f589e 100644 (file)
@@ -167,14 +167,14 @@ void __init mips_cpu_irq_init(int irq_base)
                        irq_desc[i].status = IRQ_DISABLED;
                        irq_desc[i].action = NULL;
                        irq_desc[i].depth = 1;
-                       irq_desc[i].handler = &mips_mt_cpu_irq_controller;
+                       irq_desc[i].chip = &mips_mt_cpu_irq_controller;
                }
 
        for (i = irq_base + 2; i < irq_base + 8; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &mips_cpu_irq_controller;
+               irq_desc[i].chip = &mips_cpu_irq_controller;
        }
 
        mips_cpu_irq_base = irq_base;
index 298f82fe8440a43d1a8140ed8a256d44595ed6d8..9096a5ea42298d4f409ce249f7f5e4ec3d9195c8 100644 (file)
@@ -446,7 +446,7 @@ static int __init topology_init(void)
        int ret;
 
        for_each_present_cpu(cpu) {
-               ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL);
+               ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu);
                if (ret)
                        printk(KERN_WARNING "topology_init: register_cpu %d "
                               "failed (%d)\n", cpu, ret);
index 2e8e52c135e6edc17613f24b4e79f29563ef8519..70cf09afdf565c573d5750f70723deed249d98bd 100644 (file)
@@ -367,7 +367,7 @@ void mipsmt_prepare_cpus(void)
        dvpe();
        dmt();
 
-       freeIPIq.lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&freeIPIq.lock);
 
        /*
         * We probably don't have as many VPEs as we do SMP "CPUs",
@@ -375,7 +375,7 @@ void mipsmt_prepare_cpus(void)
         */
        for (i=0; i<NR_CPUS; i++) {
                IPIQ[i].head = IPIQ[i].tail = NULL;
-               IPIQ[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&IPIQ[i].lock);
                IPIQ[i].depth = 0;
                ipi_timer_latch[i] = 0;
        }
index 2d3472b21ebbe3ad62b98ff3046380b0039107a3..9316a024a8188ed8d2e92d5db266263b08e2b47a 100644 (file)
@@ -156,6 +156,6 @@ void __init arch_init_irq(void)
                irq_desc[i].status      = IRQ_DISABLED;
                irq_desc[i].action      = 0;
                irq_desc[i].depth       = 1;
-               irq_desc[i].handler     = &lasat_irq_type;
+               irq_desc[i].chip        = &lasat_irq_type;
        }
 }
index db53950b7cfbae7bd9e8936ede6fd6f6f5c64882..9dd6b89255818ddbf22fbcc86e4f294b834c1499 100644 (file)
@@ -215,7 +215,7 @@ void __init arch_init_irq(void)
                irq_desc[i].status      = IRQ_DISABLED;
                irq_desc[i].action      = 0;
                irq_desc[i].depth       = 1;
-               irq_desc[i].handler     = &atlas_irq_type;
+               irq_desc[i].chip        = &atlas_irq_type;
                spin_lock_init(&irq_desc[i].lock);
        }
 }
index bd885785e2f992f6dd2d80295e5afa427c67551e..31d179c4673fe55cf9c812bcd813963b547a8fa1 100644 (file)
@@ -147,6 +147,6 @@ void cpci_irq_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 2;
-               irq_desc[i].handler = &cpci_irq_type;
+               irq_desc[i].chip = &cpci_irq_type;
        }
 }
index 755bde5146be1d5d0b77bb319e91be12ecb8923d..852265026fd1f5b830e3e172268c1b7a7425ab35 100644 (file)
@@ -137,10 +137,10 @@ void uart_irq_init(void)
        irq_desc[80].status = IRQ_DISABLED;
        irq_desc[80].action = 0;
        irq_desc[80].depth = 2;
-       irq_desc[80].handler = &uart_irq_type;
+       irq_desc[80].chip = &uart_irq_type;
 
        irq_desc[81].status = IRQ_DISABLED;
        irq_desc[81].action = 0;
        irq_desc[81].depth = 2;
-       irq_desc[81].handler = &uart_irq_type;
+       irq_desc[81].chip = &uart_irq_type;
 }
index 4dfce154d4af1cb33e7b35410f3a747d34c47555..ba66f8c9bd4eec824b21882d8129d284289cf6dc 100644 (file)
@@ -51,11 +51,11 @@ unsigned long PCIBIOS_MIN_MEM       = 0;
  */
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                      resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
        struct pci_controller *hose = dev->sysdata;
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO) {
                /* Make sure we start at our min on all hoses */
index 39ee6314f62757279e12118448a04b70713fb2a7..8f18764a235956c6dbb14825b8cabba6daf8dd91 100644 (file)
@@ -236,7 +236,7 @@ void __init arch_init_irq(void)
        int configPR;
 
        for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) {
-               irq_desc[i].handler = &level_irq_type;
+               irq_desc[i].chip = &level_irq_type;
                pnx8550_ack(i); /* mask the irq just in case  */
        }
 
@@ -273,7 +273,7 @@ void __init arch_init_irq(void)
                /* mask/priority is still 0 so we will not get any
                 * interrupts until it is unmasked */
 
-               irq_desc[i].handler = &level_irq_type;
+               irq_desc[i].chip = &level_irq_type;
        }
 
        /* Priority level 0 */
@@ -282,12 +282,12 @@ void __init arch_init_irq(void)
        /* Set int vector table address */
        PNX8550_GIC_VECTOR_0 = PNX8550_GIC_VECTOR_1 = 0;
 
-       irq_desc[MIPS_CPU_GIC_IRQ].handler = &level_irq_type;
+       irq_desc[MIPS_CPU_GIC_IRQ].chip = &level_irq_type;
        setup_irq(MIPS_CPU_GIC_IRQ, &gic_action);
 
        /* init of Timer interrupts */
        for (i = PNX8550_INT_TIMER_MIN; i <= PNX8550_INT_TIMER_MAX; i++) {
-               irq_desc[i].handler = &level_irq_type;
+               irq_desc[i].chip = &level_irq_type;
        }
 
        /* Stop Timer 1-3 */
@@ -295,7 +295,7 @@ void __init arch_init_irq(void)
        configPR |= 0x00000038;
        write_c0_config7(configPR);
 
-       irq_desc[MIPS_CPU_TIMER_IRQ].handler = &level_irq_type;
+       irq_desc[MIPS_CPU_TIMER_IRQ].chip = &level_irq_type;
        setup_irq(MIPS_CPU_TIMER_IRQ, &timer_action);
 }
 
index 54b65a80abf587d30a54d613b1a268f780f38a3c..fb523ebcafa8e8a5e6c8ee753cdbaa8c6a347e57 100644 (file)
@@ -383,12 +383,12 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 
 
 void pcibios_align_resource(void *data, struct resource *res,
-                            unsigned long size, unsigned long align)
+                            resource_size_t size, resource_size_t align)
 {
         struct pci_dev *dev = data;
 
         if (res->flags & IORESOURCE_IO) {
-                unsigned long start = res->start;
+                resource_size_t start = res->start;
 
                 /* We need to avoid collisions with `mirrored' VGA ports
                    and other strange ISA hardware, so we always want the
index b19820110aa3a91c52c9bf1f0157b3979001a315..989167b49ce92e70611940937a10c3a7efff5e28 100644 (file)
@@ -279,9 +279,9 @@ int __init ip22_eisa_init(void)
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
                if (i < (SGINT_EISA + 8))
-                       irq_desc[i].handler = &ip22_eisa1_irq_type;
+                       irq_desc[i].chip = &ip22_eisa1_irq_type;
                else
-                       irq_desc[i].handler = &ip22_eisa2_irq_type;
+                       irq_desc[i].chip = &ip22_eisa2_irq_type;
        }
 
        /* Cannot use request_irq because of kmalloc not being ready at such
index fc6a7e2b189ccd90224c54dbf6ac4ae62ba99b68..18906af6969100e7c51f9b0c9a62a60ad1c3ad3e 100644 (file)
@@ -436,7 +436,7 @@ void __init arch_init_irq(void)
                irq_desc[i].status      = IRQ_DISABLED;
                irq_desc[i].action      = 0;
                irq_desc[i].depth       = 1;
-               irq_desc[i].handler     = handler;
+               irq_desc[i].chip        = handler;
        }
 
        /* vector handler. this register the IRQ as non-sharable */
index 0b61a39ce2bb1f116f991b94d481aa6cd2825096..869566c360ae9b5fe5a4e7b2d848498d39dda975 100644 (file)
@@ -386,7 +386,7 @@ void __devinit register_bridge_irq(unsigned int irq)
        irq_desc[irq].status    = IRQ_DISABLED;
        irq_desc[irq].action    = 0;
        irq_desc[irq].depth     = 1;
-       irq_desc[irq].handler   = &bridge_irq_type;
+       irq_desc[irq].chip      = &bridge_irq_type;
 }
 
 int __devinit request_bridge_irq(struct bridge_controller *bc)
index 8ba08047d164222b31bf6315b66fb51603d3a93a..00b94aaf6371834134736b909979397c9c7c52f9 100644 (file)
@@ -591,7 +591,7 @@ void __init arch_init_irq(void)
                irq_desc[irq].status = IRQ_DISABLED;
                irq_desc[irq].action = 0;
                irq_desc[irq].depth = 0;
-               irq_desc[irq].handler = controller;
+               irq_desc[irq].chip = controller;
        }
        setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
        setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
index e61760b14d99ec208d741e85f121f99cfb189838..610df40cb82088241ed6fdcb52e98ed30cef455d 100644 (file)
@@ -276,10 +276,10 @@ void __init init_bcm1480_irqs(void)
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
                if (i < BCM1480_NR_IRQS) {
-                       irq_desc[i].handler = &bcm1480_irq_type;
+                       irq_desc[i].chip = &bcm1480_irq_type;
                        bcm1480_irq_owner[i] = 0;
                } else {
-                       irq_desc[i].handler = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_type;
                }
        }
 }
index f853c32f60a0f7e1b847f289a469b8e2b0932ada..fcc61940f1ff6444e8e03fed4cdf105a9cac555e 100644 (file)
@@ -246,10 +246,10 @@ void __init init_sb1250_irqs(void)
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
                if (i < SB1250_NR_IRQS) {
-                       irq_desc[i].handler = &sb1250_irq_type;
+                       irq_desc[i].chip = &sb1250_irq_type;
                        sb1250_irq_owner[i] = 0;
                } else {
-                       irq_desc[i].handler = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_type;
                }
        }
 }
index 7365b4853ddb212a0d6073d49d60460838819f1f..c19e158ec402ad22dc2b6f60a7677f7102e7b72f 100644 (file)
@@ -203,7 +203,7 @@ void __init arch_init_irq(void)
                irq_desc[i].status     = IRQ_DISABLED;
                irq_desc[i].action     = 0;
                irq_desc[i].depth      = 1;
-               irq_desc[i].handler    = &pciasic_irq_type;
+               irq_desc[i].chip    = &pciasic_irq_type;
        }
 
        change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4);
index 8ca68015cf40ffd9456a17febfa107187eb8b18d..a42be00483e6d57f07bcdbe10b1267570939a974 100644 (file)
@@ -227,7 +227,7 @@ static void __init tx4927_irq_cp0_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &tx4927_irq_cp0_type;
+               irq_desc[i].chip = &tx4927_irq_cp0_type;
        }
 
        return;
@@ -435,7 +435,7 @@ static void __init tx4927_irq_pic_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 2;
-               irq_desc[i].handler = &tx4927_irq_pic_type;
+               irq_desc[i].chip = &tx4927_irq_pic_type;
        }
 
        setup_irq(TX4927_IRQ_NEST_PIC_ON_CP0, &tx4927_irq_pic_action);
index aee07ff2212a37bb1348a6a48d783dea94a8146e..c67978b6dae494b5ec08f6b175f759be3c941faf 100644 (file)
@@ -368,7 +368,7 @@ static void __init toshiba_rbtx4927_irq_ioc_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 3;
-               irq_desc[i].handler = &toshiba_rbtx4927_irq_ioc_type;
+               irq_desc[i].chip = &toshiba_rbtx4927_irq_ioc_type;
        }
 
        setup_irq(TOSHIBA_RBTX4927_IRQ_NEST_IOC_ON_PIC,
@@ -526,7 +526,7 @@ static void __init toshiba_rbtx4927_irq_isa_init(void)
                irq_desc[i].action = 0;
                irq_desc[i].depth =
                    ((i < TOSHIBA_RBTX4927_IRQ_ISA_MID) ? (4) : (5));
-               irq_desc[i].handler = &toshiba_rbtx4927_irq_isa_type;
+               irq_desc[i].chip = &toshiba_rbtx4927_irq_isa_type;
        }
 
        setup_irq(TOSHIBA_RBTX4927_IRQ_NEST_ISA_ON_IOC,
@@ -692,13 +692,13 @@ void toshiba_rbtx4927_irq_dump(char *key)
        {
                u32 i, j = 0;
                for (i = 0; i < NR_IRQS; i++) {
-                       if (strcmp(irq_desc[i].handler->typename, "none")
+                       if (strcmp(irq_desc[i].chip->typename, "none")
                            == 0)
                                continue;
 
                        if ((i >= 1)
-                           && (irq_desc[i - 1].handler->typename ==
-                               irq_desc[i].handler->typename)) {
+                           && (irq_desc[i - 1].chip->typename ==
+                               irq_desc[i].chip->typename)) {
                                j++;
                        } else {
                                j = 0;
@@ -707,12 +707,12 @@ void toshiba_rbtx4927_irq_dump(char *key)
                            (TOSHIBA_RBTX4927_IRQ_INFO,
                             "%s irq=0x%02x/%3d s=0x%08x h=0x%08x a=0x%08x ah=0x%08x d=%1d n=%s/%02d\n",
                             key, i, i, irq_desc[i].status,
-                            (u32) irq_desc[i].handler,
+                            (u32) irq_desc[i].chip,
                             (u32) irq_desc[i].action,
                             (u32) (irq_desc[i].action ? irq_desc[i].
                                    action->handler : 0),
                             irq_desc[i].depth,
-                            irq_desc[i].handler->typename, j);
+                            irq_desc[i].chip->typename, j);
                }
        }
 #endif
index 873805178d8e993b09402aad77ce8a9524f9bf83..0b2f8c8492181e4724b5675fdffed196ba207877 100644 (file)
@@ -102,7 +102,7 @@ tx4938_irq_cp0_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &tx4938_irq_cp0_type;
+               irq_desc[i].chip = &tx4938_irq_cp0_type;
        }
 
        return;
@@ -306,7 +306,7 @@ tx4938_irq_pic_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 2;
-               irq_desc[i].handler = &tx4938_irq_pic_type;
+               irq_desc[i].chip = &tx4938_irq_pic_type;
        }
 
        setup_irq(TX4938_IRQ_NEST_PIC_ON_CP0, &tx4938_irq_pic_action);
index 9cd9c0fe22658c9bcbcd6fbdb6e62a73f3ca609b..3b8245dc5bd38e9b074a4e12902bae0efb1082a9 100644 (file)
@@ -146,7 +146,7 @@ toshiba_rbtx4938_irq_ioc_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 3;
-               irq_desc[i].handler = &toshiba_rbtx4938_irq_ioc_type;
+               irq_desc[i].chip = &toshiba_rbtx4938_irq_ioc_type;
        }
 
        setup_irq(RBTX4938_IRQ_IOCINT,
index 07ae19cf0c296d93422abe4db50f5d5c30c4f683..b9323302cc4e6fbf4b6312dab00b0617656ba4e3 100644 (file)
@@ -722,10 +722,10 @@ static int __init vr41xx_icu_init(void)
        icu2_write(MGIUINTHREG, 0xffff);
 
        for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++)
-               irq_desc[i].handler = &sysint1_irq_type;
+               irq_desc[i].chip = &sysint1_irq_type;
 
        for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++)
-               irq_desc[i].handler = &sysint2_irq_type;
+               irq_desc[i].chip = &sysint2_irq_type;
 
        cascade_irq(INT0_IRQ, icu_get_irq);
        cascade_irq(INT1_IRQ, icu_get_irq);
index 86796bb63c3c7e3d6b3aaa41626a52a43b8eca35..66aa50802deb6fcc06dd399a90b9c86a2a4a5d5a 100644 (file)
@@ -73,13 +73,13 @@ static void irq_dispatch(unsigned int irq, struct pt_regs *regs)
        if (cascade->get_irq != NULL) {
                unsigned int source_irq = irq;
                desc = irq_desc + source_irq;
-               desc->handler->ack(source_irq);
+               desc->chip->ack(source_irq);
                irq = cascade->get_irq(irq, regs);
                if (irq < 0)
                        atomic_inc(&irq_err_count);
                else
                        irq_dispatch(irq, regs);
-               desc->handler->end(source_irq);
+               desc->chip->end(source_irq);
        } else
                do_IRQ(irq, regs);
 }
index 3e31f8193d2115ef100674e6cddc015bd5acfa62..2d287b8893d90f4081c7742191e8ff2f24000af3 100644 (file)
@@ -483,7 +483,7 @@ static inline int vrc4173_icu_init(int cascade_irq)
        vr41xx_set_irq_level(GIU_IRQ_TO_PIN(cascade_irq), LEVEL_LOW);
 
        for (i = VRC4173_IRQ_BASE; i <= VRC4173_IRQ_LAST; i++)
-                irq_desc[i].handler = &vrc4173_irq_type;
+                irq_desc[i].chip = &vrc4173_irq_type;
 
        return 0;
 }
index 31db6b61a39e9627ad7c5da13e2e4de555880325..7b2511ca0a616a0c4729ba244d392fcbea0361ff 100644 (file)
@@ -104,7 +104,7 @@ void __init rockhopper_init_irq(void)
        }
 
        for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++)
-               irq_desc[i].handler = &i8259_irq_type;
+               irq_desc[i].chip = &i8259_irq_type;
 
        setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade);
 
index 910fb3afc0b5c91e40c24a030a7b1b8241af5d60..6dd0ea8f88e0a49c273e3f04734efc3e42abb0d5 100644 (file)
@@ -51,6 +51,10 @@ config GENERIC_HARDIRQS
 config GENERIC_IRQ_PROBE
        def_bool y
 
+config IRQ_PER_CPU
+       bool
+       default y
+
 # unless you want to implement ACPI on PA-RISC ... ;-)
 config PM
        bool
index c057ad7605bab4e8e3d4d1ac1e987bced680f780..bc7c4a4e26a1e24f53b62b735bf820baac104635 100644 (file)
@@ -97,15 +97,17 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 void
 show_cache_info(struct seq_file *m)
 {
+       char buf[32];
+
        seq_printf(m, "I-cache\t\t: %ld KB\n", 
                cache_info.ic_size/1024 );
-       seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %d-way associative)\n", 
+       if (cache_info.dc_loop == 1)
+               snprintf(buf, 32, "%lu-way associative", cache_info.dc_loop);
+       seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %s)\n",
                cache_info.dc_size/1024,
                (cache_info.dc_conf.cc_wt ? "WT":"WB"),
                (cache_info.dc_conf.cc_sh ? ", shared I/D":""),
-               (cache_info.dc_conf.cc_assoc)
-       );
-
+               ((cache_info.dc_loop == 1) ? "direct mapped" : buf));
        seq_printf(m, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
                cache_info.it_size,
                cache_info.dt_size,
@@ -158,11 +160,11 @@ parisc_cache_init(void)
                cache_info.dc_conf.cc_block,
                cache_info.dc_conf.cc_line,
                cache_info.dc_conf.cc_shift);
-       printk("        wt %d sh %d cst %d assoc %d\n",
+       printk("        wt %d sh %d cst %d hv %d\n",
                cache_info.dc_conf.cc_wt,
                cache_info.dc_conf.cc_sh,
                cache_info.dc_conf.cc_cst,
-               cache_info.dc_conf.cc_assoc);
+               cache_info.dc_conf.cc_hv);
 
        printk("IC  base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx\n",
                cache_info.ic_base,
@@ -176,11 +178,11 @@ parisc_cache_init(void)
                cache_info.ic_conf.cc_block,
                cache_info.ic_conf.cc_line,
                cache_info.ic_conf.cc_shift);
-       printk("        wt %d sh %d cst %d assoc %d\n",
+       printk("        wt %d sh %d cst %d hv %d\n",
                cache_info.ic_conf.cc_wt,
                cache_info.ic_conf.cc_sh,
                cache_info.ic_conf.cc_cst,
-               cache_info.ic_conf.cc_assoc);
+               cache_info.ic_conf.cc_hv);
 
        printk("D-TLB conf: sh %d page %d cst %d aid %d pad1 %d \n",
                cache_info.dt_conf.tc_sh,
@@ -234,7 +236,8 @@ parisc_cache_init(void)
 
 void disable_sr_hashing(void)
 {
-       int srhash_type;
+       int srhash_type, retval;
+       unsigned long space_bits;
 
        switch (boot_cpu_data.cpu_type) {
        case pcx: /* We shouldn't get this far.  setup.c should prevent it. */
@@ -260,6 +263,13 @@ void disable_sr_hashing(void)
        }
 
        disable_sr_hashing_asm(srhash_type);
+
+       retval = pdc_spaceid_bits(&space_bits);
+       /* If this procedure isn't implemented, don't panic. */
+       if (retval < 0 && retval != PDC_BAD_OPTION)
+               panic("pdc_spaceid_bits call failed.\n");
+       if (space_bits != 0)
+               panic("SpaceID hashing is still on!\n");
 }
 
 void flush_dcache_page(struct page *page)
index d9e53cf0372b313a368b886cc062fc33b419e5ab..630730c32a5a1e9d794f82ac5c9c7c15c3ab4831 100644 (file)
@@ -1638,7 +1638,7 @@ dbit_trap_20w:
        load32          PA(pa_dbit_lock),t0
 
 dbit_spin_20w:
-       ldcw            0(t0),t1
+       LDCW            0(t0),t1
        cmpib,=         0,t1,dbit_spin_20w
        nop
 
@@ -1674,7 +1674,7 @@ dbit_trap_11:
        load32          PA(pa_dbit_lock),t0
 
 dbit_spin_11:
-       ldcw            0(t0),t1
+       LDCW            0(t0),t1
        cmpib,=         0,t1,dbit_spin_11
        nop
 
@@ -1714,7 +1714,7 @@ dbit_trap_20:
        load32          PA(pa_dbit_lock),t0
 
 dbit_spin_20:
-       ldcw            0(t0),t1
+       LDCW            0(t0),t1
        cmpib,=         0,t1,dbit_spin_20
        nop
 
index 2dc06b8e18171f0e485d750d85f56be4ac197802..4398d2a95789b247c2676ae4f798631e45f77af0 100644 (file)
@@ -11,7 +11,7 @@
  * Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
  * Copyright 2003 Grant Grundler <grundler parisc-linux org>
  * Copyright 2003,2004 Ryan Bradetich <rbrad@parisc-linux.org>
- * Copyright 2004 Thibaut VARENE <varenet@parisc-linux.org>
+ * Copyright 2004,2006 Thibaut VARENE <varenet@parisc-linux.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
@@ -252,10 +252,8 @@ int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
 #endif
 
 /**
- * pdc_chassis_disp - Updates display
+ * pdc_chassis_disp - Updates chassis code
  * @retval: -1 on error, 0 on success
- *
- * Works on old PDC only (E class, others?)
  */
 int pdc_chassis_disp(unsigned long disp)
 {
@@ -268,6 +266,22 @@ int pdc_chassis_disp(unsigned long disp)
        return retval;
 }
 
+/**
+ * pdc_chassis_warn - Fetches chassis warnings
+ * @retval: -1 on error, 0 on success
+ */
+int pdc_chassis_warn(unsigned long *warn)
+{
+       int retval = 0;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(pdc_result));
+       *warn = pdc_result[0];
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
 /**
  * pdc_coproc_cfg - To identify coprocessors attached to the processor.
  * @pdc_coproc_info: Return buffer address.
@@ -393,7 +407,9 @@ int pdc_model_info(struct pdc_model *model)
  * pdc_model_sysmodel - Get the system model name.
  * @name: A char array of at least 81 characters.
  *
- * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L)
+ * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L).
+ * Using OS_ID_HPUX will return the equivalent of the 'modelname' command
+ * on HP/UX.
  */
 int pdc_model_sysmodel(char *name)
 {
@@ -498,6 +514,26 @@ int pdc_cache_info(struct pdc_cache_info *cache_info)
         return retval;
 }
 
+/**
+ * pdc_spaceid_bits - Return whether Space ID hashing is turned on.
+ * @space_bits: Should be 0, if not, bad mojo!
+ *
+ * Returns information about Space ID hashing.
+ */
+int pdc_spaceid_bits(unsigned long *space_bits)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       pdc_result[0] = 0;
+       retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_RET_SPID, __pa(pdc_result), 0);
+       convert_to_wide(pdc_result);
+       *space_bits = pdc_result[0];
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
 #ifndef CONFIG_PA20
 /**
  * pdc_btlb_info - Return block TLB information.
index 197936d9359a4065332a2c9a67ad8bd69ad04f33..82fe6ba29727a6824bd4a83e5fef44322239f08f 100644 (file)
@@ -94,7 +94,7 @@ int cpu_check_affinity(unsigned int irq, cpumask_t *dest)
        if (irq == TIMER_IRQ || irq == IPI_IRQ) {
                /* Bad linux design decision.  The mask has already
                 * been set; we must reset it */
-               irq_affinity[irq] = CPU_MASK_ALL;
+               irq_desc[irq].affinity = CPU_MASK_ALL;
                return -EINVAL;
        }
 
@@ -110,7 +110,7 @@ static void cpu_set_affinity_irq(unsigned int irq, cpumask_t dest)
        if (cpu_check_affinity(irq, &dest))
                return;
 
-       irq_affinity[irq] = dest;
+       irq_desc[irq].affinity = dest;
 }
 #endif
 
@@ -125,6 +125,10 @@ static struct hw_interrupt_type cpu_interrupt_type = {
 #ifdef CONFIG_SMP
        .set_affinity   = cpu_set_affinity_irq,
 #endif
+       /* XXX: Needs to be written.  We managed without it so far, but
+        * we really ought to write it.
+        */
+       .retrigger      = NULL,
 };
 
 int show_interrupts(struct seq_file *p, void *v)
@@ -158,7 +162,7 @@ int show_interrupts(struct seq_file *p, void *v)
                seq_printf(p, "%10u ", kstat_irqs(i));
 #endif
 
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
 #ifndef PARISC_IRQ_CR16_COUNTS
                seq_printf(p, "  %s", action->name);
 
@@ -210,12 +214,12 @@ int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
 {
        if (irq_desc[irq].action)
                return -EBUSY;
-       if (irq_desc[irq].handler != &cpu_interrupt_type)
+       if (irq_desc[irq].chip != &cpu_interrupt_type)
                return -EBUSY;
 
        if (type) {
-               irq_desc[irq].handler = type;
-               irq_desc[irq].handler_data = data;
+               irq_desc[irq].chip = type;
+               irq_desc[irq].chip_data = data;
                cpu_interrupt_type.enable(irq);
        }
        return 0;
@@ -265,7 +269,7 @@ int txn_alloc_irq(unsigned int bits_wide)
 unsigned long txn_affinity_addr(unsigned int irq, int cpu)
 {
 #ifdef CONFIG_SMP
-       irq_affinity[irq] = cpumask_of_cpu(cpu);
+       irq_desc[irq].affinity = cpumask_of_cpu(cpu);
 #endif
 
        return cpu_data[cpu].txn_addr;
@@ -326,7 +330,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
                /* Work our way from MSb to LSb...same order we alloc EIRs */
                for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
 #ifdef CONFIG_SMP
-                       cpumask_t dest = irq_affinity[irq];
+                       cpumask_t dest = irq_desc[irq].affinity;
 #endif
                        if (!(bit & eirr_val))
                                continue;
@@ -378,7 +382,7 @@ static void claim_cpu_irqs(void)
 {
        int i;
        for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
-               irq_desc[i].handler = &cpu_interrupt_type;
+               irq_desc[i].chip = &cpu_interrupt_type;
        }
 
        irq_desc[TIMER_IRQ].action = &timer_action;
@@ -404,13 +408,6 @@ void __init init_IRQ(void)
 
 }
 
-void hw_resend_irq(struct hw_interrupt_type *type, unsigned int irq)
-{
-       /* XXX: Needs to be written.  We managed without it so far, but
-        * we really ought to write it.
-        */
-}
-
 void ack_bad_irq(unsigned int irq)
 {
        printk("unexpected IRQ %d\n", irq);
index f27cfe4771b88c1099995e5964cb2541440da180..aee311884f3fa114c2a4fa5f5f4b0dc4fbe2d5f3 100644 (file)
@@ -89,6 +89,12 @@ static inline int is_local(struct module *me, void *loc)
        return is_init(me, loc) || is_core(me, loc);
 }
 
+static inline int is_local_section(struct module *me, void *loc, void *dot)
+{
+       return (is_init(me, loc) && is_init(me, dot)) ||
+               (is_core(me, loc) && is_core(me, dot));
+}
+
 
 #ifndef __LP64__
 struct got_entry {
@@ -364,8 +370,14 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value)
 }
 #endif /* __LP64__ */
 
+enum elf_stub_type {
+       ELF_STUB_GOT,
+       ELF_STUB_MILLI,
+       ELF_STUB_DIRECT,
+};
+
 static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
-       int millicode, int init_section)
+       enum elf_stub_type stub_type, int init_section)
 {
        unsigned long i;
        struct stub_entry *stub;
@@ -396,7 +408,7 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
        stub->insns[1] |= reassemble_17(rrsel(value, addend) / 4);
 
 #else
-/* for 64-bit we have two kinds of stubs:
+/* for 64-bit we have three kinds of stubs:
  * for normal function calls:
  *     ldd 0(%dp),%dp
  *     ldd 10(%dp), %r1
@@ -408,18 +420,23 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
  *     ldo 0(%r1), %r1
  *     ldd 10(%r1), %r1
  *     bve,n (%r1)
+ *
+ * for direct branches (jumps between different section of the
+ * same module):
+ *     ldil 0, %r1
+ *     ldo 0(%r1), %r1
+ *     bve,n (%r1)
  */
-       if (!millicode)
-       {
+       switch (stub_type) {
+       case ELF_STUB_GOT:
                stub->insns[0] = 0x537b0000;    /* ldd 0(%dp),%dp       */
                stub->insns[1] = 0x53610020;    /* ldd 10(%dp),%r1      */
                stub->insns[2] = 0xe820d000;    /* bve (%r1)            */
                stub->insns[3] = 0x537b0030;    /* ldd 18(%dp),%dp      */
 
                stub->insns[0] |= reassemble_14(get_got(me, value, addend) & 0x3fff);
-       }
-       else
-       {
+               break;
+       case ELF_STUB_MILLI:
                stub->insns[0] = 0x20200000;    /* ldil 0,%r1           */
                stub->insns[1] = 0x34210000;    /* ldo 0(%r1), %r1      */
                stub->insns[2] = 0x50210020;    /* ldd 10(%r1),%r1      */
@@ -427,7 +444,17 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
 
                stub->insns[0] |= reassemble_21(lrsel(value, addend));
                stub->insns[1] |= reassemble_14(rrsel(value, addend));
+               break;
+       case ELF_STUB_DIRECT:
+               stub->insns[0] = 0x20200000;    /* ldil 0,%r1           */
+               stub->insns[1] = 0x34210000;    /* ldo 0(%r1), %r1      */
+               stub->insns[2] = 0xe820d002;    /* bve,n (%r1)          */
+
+               stub->insns[0] |= reassemble_21(lrsel(value, addend));
+               stub->insns[1] |= reassemble_14(rrsel(value, addend));
+               break;
        }
+
 #endif
 
        return (Elf_Addr)stub;
@@ -539,14 +566,14 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
                        break;
                case R_PARISC_PCREL17F:
                        /* 17-bit PC relative address */
-                       val = get_stub(me, val, addend, 0, is_init(me, loc));
+                       val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
                        val = (val - dot - 8)/4;
                        CHECK_RELOC(val, 17)
                        *loc = (*loc & ~0x1f1ffd) | reassemble_17(val);
                        break;
                case R_PARISC_PCREL22F:
                        /* 22-bit PC relative address; only defined for pa20 */
-                       val = get_stub(me, val, addend, 0, is_init(me, loc));
+                       val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
                        DEBUGP("STUB FOR %s loc %lx+%lx at %lx\n", 
                               strtab + sym->st_name, (unsigned long)loc, addend, 
                               val)
@@ -643,13 +670,23 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
                               strtab + sym->st_name,
                               loc, val);
                        /* can we reach it locally? */
-                       if(!is_local(me, (void *)val)) {
-                               if (strncmp(strtab + sym->st_name, "$$", 2)
+                       if(!is_local_section(me, (void *)val, (void *)dot)) {
+
+                               if (is_local(me, (void *)val))
+                                       /* this is the case where the
+                                        * symbol is local to the
+                                        * module, but in a different
+                                        * section, so stub the jump
+                                        * in case it's more than 22
+                                        * bits away */
+                                       val = get_stub(me, val, addend, ELF_STUB_DIRECT,
+                                                      is_init(me, loc));
+                               else if (strncmp(strtab + sym->st_name, "$$", 2)
                                    == 0)
-                                       val = get_stub(me, val, addend, 1,
+                                       val = get_stub(me, val, addend, ELF_STUB_MILLI,
                                                       is_init(me, loc));
                                else
-                                       val = get_stub(me, val, addend, 0,
+                                       val = get_stub(me, val, addend, ELF_STUB_GOT,
                                                       is_init(me, loc));
                        }
                        DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n", 
index 79c7db2705fd4b7b475a87af50e09cf57cc62a4a..7d6967ee367c7f8ef5784281d0eb082af7a9a9b2 100644 (file)
@@ -289,7 +289,7 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
  * than res->start.
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                               unsigned long size, unsigned long alignment)
+                               resource_size_t size, resource_size_t alignment)
 {
        unsigned long mask, align;
 
index a45e2e2ffd9f7ff21c2caf748b9e8ce01aa210ce..d47ba1aa825376fdce235befca626b6cb95762d8 100644 (file)
@@ -1,8 +1,8 @@
 /* 
- *    interfaces to log Chassis Codes via PDC (firmware)
+ *    interfaces to Chassis Codes via PDC (firmware)
  *
  *    Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
- *    Copyright (C) 2002-2004 Thibaut VARENE <varenet@parisc-linux.org>
+ *    Copyright (C) 2002-2006 Thibaut VARENE <varenet@parisc-linux.org>
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License, version 2, as
  *    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
+ *
+ *    TODO: poll chassis warns, trigger (configurable) machine shutdown when
+ *             needed.
+ *         Find out how to get Chassis warnings out of PAT boxes?
  */
 
 #undef PDC_CHASSIS_DEBUG
 #include <linux/reboot.h>
 #include <linux/notifier.h>
 #include <linux/cache.h>
+#include <linux/proc_fs.h>
 
 #include <asm/pdc_chassis.h>
 #include <asm/processor.h>
 #include <asm/pdc.h>
 #include <asm/pdcpat.h>
 
+#define PDC_CHASSIS_VER        "0.05"
 
 #ifdef CONFIG_PDC_CHASSIS
-static int pdc_chassis_old __read_mostly = 0;  
 static unsigned int pdc_chassis_enabled __read_mostly = 1;
 
 
@@ -64,7 +69,7 @@ __setup("pdcchassis=", pdc_chassis_setup);
  * Currently, only E class and A180 are known to work with this.
  * Inspired by Christoph Plattner
  */
-
+#if 0
 static void __init pdc_chassis_checkold(void)
 {
        switch(CPU_HVERSION) {
@@ -73,7 +78,6 @@ static void __init pdc_chassis_checkold(void)
                case 0x482:             /* E45 */
                case 0x483:             /* E55 */
                case 0x516:             /* A180 */
-                       pdc_chassis_old = 1;
                        break;
 
                default:
@@ -81,7 +85,7 @@ static void __init pdc_chassis_checkold(void)
        }
        DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old);
 }
-
+#endif
 
 /**
  * pdc_chassis_panic_event() - Called by the panic handler.
@@ -131,30 +135,20 @@ static struct notifier_block pdc_chassis_reboot_block = {
 void __init parisc_pdc_chassis_init(void)
 {
 #ifdef CONFIG_PDC_CHASSIS
-       int handle = 0;
        if (likely(pdc_chassis_enabled)) {
                DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__);
 
                /* Let see if we have something to handle... */
-               /* Check for PDC_PAT or old LED Panel */
-               pdc_chassis_checkold();
-               if (is_pdc_pat()) {
-                       printk(KERN_INFO "Enabling PDC_PAT chassis codes support.\n");
-                       handle = 1;
-               }
-               else if (unlikely(pdc_chassis_old)) {
-                       printk(KERN_INFO "Enabling old style chassis LED panel support.\n");
-                       handle = 1;
-               }
-
-               if (handle) {
-                       /* initialize panic notifier chain */
-                       atomic_notifier_chain_register(&panic_notifier_list,
-                                       &pdc_chassis_panic_block);
-
-                       /* initialize reboot notifier chain */
-                       register_reboot_notifier(&pdc_chassis_reboot_block);
-               }
+               printk(KERN_INFO "Enabling %s chassis codes support v%s\n",
+                               is_pdc_pat() ? "PDC_PAT" : "regular",
+                               PDC_CHASSIS_VER);
+
+               /* initialize panic notifier chain */
+               atomic_notifier_chain_register(&panic_notifier_list,
+                               &pdc_chassis_panic_block);
+
+               /* initialize reboot notifier chain */
+               register_reboot_notifier(&pdc_chassis_reboot_block);
        }
 #endif /* CONFIG_PDC_CHASSIS */
 }
@@ -215,9 +209,12 @@ int pdc_chassis_send_status(int message)
                        }
                } else retval = -1;
 #else
-               if (unlikely(pdc_chassis_old)) {
+               if (1) {
                        switch (message) {
                                case PDC_CHASSIS_DIRECT_BSTART:
+                                       retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_INIT));
+                                       break;
+
                                case PDC_CHASSIS_DIRECT_BCOMPLETE:
                                        retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN));
                                        break;
@@ -244,3 +241,61 @@ int pdc_chassis_send_status(int message)
 #endif /* CONFIG_PDC_CHASSIS */
        return retval;
 }
+
+#ifdef CONFIG_PDC_CHASSIS_WARN
+#ifdef CONFIG_PROC_FS
+static int pdc_chassis_warn_pread(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       char *out = page;
+       int len, ret;
+       unsigned long warn;
+       u32 warnreg;
+
+       ret = pdc_chassis_warn(&warn);
+       if (ret != PDC_OK)
+               return -EIO;
+
+       warnreg = (warn & 0xFFFFFFFF);
+
+       if ((warnreg >> 24) & 0xFF)
+               out += sprintf(out, "Chassis component failure! (eg fan or PSU): 0x%.2x\n", ((warnreg >> 24) & 0xFF));
+
+       out += sprintf(out, "Battery: %s\n", (warnreg & 0x04) ? "Low!" : "OK");
+       out += sprintf(out, "Temp low: %s\n", (warnreg & 0x02) ? "Exceeded!" : "OK");
+       out += sprintf(out, "Temp mid: %s\n", (warnreg & 0x01) ? "Exceeded!" : "OK");
+
+       len = out - page - off;
+       if (len < count) {
+               *eof = 1;
+               if (len <= 0) return 0;
+       } else {
+               len = count;
+       }
+       *start = page + off;
+       return len;
+}
+
+static int __init pdc_chassis_create_procfs(void)
+{
+       unsigned long test;
+       int ret;
+
+       ret = pdc_chassis_warn(&test);
+       if ((ret == PDC_BAD_PROC) || (ret == PDC_BAD_OPTION)) {
+               /* seems that some boxes (eg L1000) do not implement this */
+               printk(KERN_INFO "Chassis warnings not supported.\n");
+               return 0;
+       }
+
+       printk(KERN_INFO "Enabling PDC chassis warnings support v%s\n",
+                       PDC_CHASSIS_VER);
+       create_proc_read_entry("chassis", 0400, NULL, pdc_chassis_warn_pread,
+                               NULL);
+       return 0;
+}
+
+__initcall(pdc_chassis_create_procfs);
+
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_PDC_CHASSIS_WARN */
index 413292f1a4a36401fda3cc03129574b68e648f09..3f28de974556c838894ab5d12f40227d2c39c23e 100644 (file)
@@ -91,7 +91,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                int copied;
 
 #ifdef __LP64__
-               if (personality(child->personality) == PER_LINUX32) {
+               if (__is_compat_task(child)) {
                        unsigned int tmp;
 
                        addr &= 0xffffffffL;
@@ -123,7 +123,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        case PTRACE_POKEDATA:
                ret = 0;
 #ifdef __LP64__
-               if (personality(child->personality) == PER_LINUX32) {
+               if (__is_compat_task(child)) {
                        unsigned int tmp = (unsigned int)data;
                        DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
                                request == PTRACE_POKETEXT ? "TEXT" : "DATA",
@@ -146,7 +146,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        case PTRACE_PEEKUSR: {
                ret = -EIO;
 #ifdef __LP64__
-               if (personality(child->personality) == PER_LINUX32) {
+               if (__is_compat_task(child)) {
                        unsigned int tmp;
 
                        if (addr & (sizeof(int)-1))
@@ -205,7 +205,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        goto out_tsk;
                }
 #ifdef __LP64__
-               if (personality(child->personality) == PER_LINUX32) {
+               if (__is_compat_task(child)) {
                        if (addr & (sizeof(int)-1))
                                goto out_tsk;
                        if ((addr = translate_usr_offset(addr)) < 0)
index 8c2859cca77ee69ab0dfbcbb2af84cf2e70c76b8..453d01a9f97149ce44ea848667c1b3661e072e6f 100644 (file)
@@ -276,15 +276,6 @@ r64_ret:
 
 #endif
 
-       .export pc_in_user_space
-       .text
-       /* Doesn't belong here but I couldn't find a nicer spot. */
-       /* Should never get called, only used by profile stuff in time.c */
-pc_in_user_space:
-       bv,n    0(%rp)
-       nop
-
-
        .export __canonicalize_funcptr_for_compare
        .text
        /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html
index 4a36ec3f6ac15f9ae0466fcfc2992374a3962601..278f4b9f6a3878806c7199c8dedec4e48d41d8be 100644 (file)
@@ -303,6 +303,8 @@ extern void eisa_init(void);
 
 static int __init parisc_init(void)
 {
+       u32 osid = (OS_ID_LINUX << 16);
+
        parisc_proc_mkdir();
        parisc_init_resources();
        do_device_inventory();                  /* probe for hardware */
@@ -311,6 +313,9 @@ static int __init parisc_init(void)
        
        /* set up a new led state on systems shipped LED State panel */
        pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART);
+
+       /* tell PDC we're Linux. Nevermind failure. */
+       pdc_stable_write(0x40, &osid, sizeof(osid));
        
        processor_init();
        printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
index cc38edfd90c5bcac048647d5dacb298254314c8b..bb83880c5ee3458bd9940b96e527bf9146cb96e9 100644 (file)
@@ -76,7 +76,7 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *r
 #ifdef __LP64__
        compat_sigset_t newset32;
 
-       if(personality(current->personality) == PER_LINUX32){
+       if (is_compat_task()) {
                /* XXX: Don't preclude handling different sized sigset_t's.  */
                if (sigsetsize != sizeof(compat_sigset_t))
                        return -EINVAL;
@@ -153,7 +153,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
        compat_sigset_t compat_set;
        struct compat_rt_sigframe __user * compat_frame;
        
-       if(personality(current->personality) == PER_LINUX32)
+       if (is_compat_task())
                sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
 #endif
 
@@ -166,7 +166,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
 #ifdef __LP64__
        compat_frame = (struct compat_rt_sigframe __user *)frame;
        
-       if(personality(current->personality) == PER_LINUX32){
+       if (is_compat_task()) {
                DBG(2,"sys_rt_sigreturn: ELF32 process.\n");
                if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set)))
                        goto give_sigsegv;
@@ -186,7 +186,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
 
        /* Good thing we saved the old gr[30], eh? */
 #ifdef __LP64__
-       if(personality(current->personality) == PER_LINUX32){
+       if (is_compat_task()) {
                DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n",
                                &compat_frame->uc.uc_mcontext);
 // FIXME: Load upper half from register file
@@ -315,7 +315,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
        compat_frame = (struct compat_rt_sigframe __user *)frame;
        
-       if(personality(current->personality) == PER_LINUX32) {
+       if (is_compat_task()) {
                DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
                err |= copy_siginfo_to_user32(&compat_frame->info, info);
                DBG(1,"SETUP_RT_FRAME: 1\n");
@@ -392,7 +392,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        haddr = A(ka->sa.sa_handler);
        /* The sa_handler may be a pointer to a function descriptor */
 #ifdef __LP64__
-       if(personality(current->personality) == PER_LINUX32) {
+       if (is_compat_task()) {
 #endif
                if (haddr & PA_PLABEL_FDESC) {
                        Elf32_Fdesc fdesc;
@@ -427,19 +427,19 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
         */
        sigframe_size = PARISC_RT_SIGFRAME_SIZE;
 #ifdef __LP64__
-       if(personality(current->personality) == PER_LINUX32)
+       if (is_compat_task())
                sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
 #endif
        if (in_syscall) {
                regs->gr[31] = haddr;
 #ifdef __LP64__
-               if(personality(current->personality) == PER_LINUX)
+               if (personality(current->personality) == PER_LINUX)
                        sigframe_size |= 1;
 #endif
        } else {
                unsigned long psw = USER_PSW;
 #ifdef __LP64__
-               if(personality(current->personality) == PER_LINUX)
+               if (personality(current->personality) == PER_LINUX)
                        psw |= PSW_W;
 #endif
 
@@ -464,7 +464,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->gr[26] = sig;               /* signal number */
        
 #ifdef __LP64__
-       if(personality(current->personality) == PER_LINUX32){
+       if (is_compat_task()) {
                regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
                regs->gr[24] = A(&compat_frame->uc);   /* ucontext pointer */
        } else
index 479d9a017cd1ff3e19ea90c30f579a7b64f7acbb..9670a89c77fe480255ce79cf5a8705434e06d43e 100644 (file)
        .level          1.1
 #endif
 
-#ifndef CONFIG_64BIT
-       .macro fixup_branch,lbl
-       b           \lbl
-       .endm
-#else
-       .macro fixup_branch,lbl
-       ldil        L%\lbl, %r1
-       ldo         R%\lbl(%r1), %r1
-       bv,n        %r0(%r1)
-       .endm
-#endif
-
        .text
 
        .import syscall_exit,code
@@ -541,7 +529,7 @@ cas_nocontend:
 # endif
 /* ENABLE_LWS_DEBUG */
 
-       ldcw    0(%sr2,%r20), %r28                      /* Try to acquire the lock */
+       LDCW    0(%sr2,%r20), %r28                      /* Try to acquire the lock */
        cmpb,<>,n       %r0, %r28, cas_action           /* Did we get it? */
 cas_wouldblock:
        ldo     2(%r0), %r28                            /* 2nd case */
index 594930bc4bcf6d3df7231e0545bdbfbf5bb3842b..eb35e1c0bb532b679b660351fc5e28db1e6ee8b8 100644 (file)
@@ -157,8 +157,22 @@ do_gettimeofday (struct timeval *tv)
                usec += (xtime.tv_nsec / 1000);
        } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
 
-       while (usec >= 1000000) {
-               usec -= 1000000;
+       if (unlikely(usec > LONG_MAX)) {
+               /* This can happen if the gettimeoffset adjustment is
+                * negative and xtime.tv_nsec is smaller than the
+                * adjustment */
+               printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec);
+               usec += USEC_PER_SEC;
+               --sec;
+               /* This should never happen, it means the negative
+                * time adjustment was more than a second, so there's
+                * something seriously wrong */
+               BUG_ON(usec > LONG_MAX);
+       }
+
+
+       while (usec >= USEC_PER_SEC) {
+               usec -= USEC_PER_SEC;
                ++sec;
        }
 
index 3ba040050e4ca1d85a28448accea66e50a0ce0fb..068b20d822e7b9c672983135a0c038e11e491839 100644 (file)
@@ -26,11 +26,10 @@ static struct cpu cpu_devices[NR_CPUS] __read_mostly;
 
 static int __init topology_init(void)
 {
-       struct node *parent = NULL;
        int num;
 
        for_each_present_cpu(num) {
-               register_cpu(&cpu_devices[num], num, parent);
+               register_cpu(&cpu_devices[num], num);
        }
        return 0;
 }
index ff200608c851d5ef948908ff8b1b38f6fe2e56f2..348344a84bf7615fa4a31cbf2cb81cc3ca378ff9 100644 (file)
@@ -66,57 +66,42 @@ int printbinary(char *buf, unsigned long x, int nbits)
 #else
 #define RFMT "%08lx"
 #endif
+#define FFMT "%016llx" /* fpregs are 64-bit always */
 
-void show_regs(struct pt_regs *regs)
+#define PRINTREGS(lvl,r,f,fmt,x)       \
+       printk("%s%s%02d-%02d  " fmt " " fmt " " fmt " " fmt "\n",      \
+               lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1],             \
+               (r)[(x)+2], (r)[(x)+3])
+
+static void print_gr(char *level, struct pt_regs *regs)
 {
        int i;
-       char buf[128], *p;
-       char *level;
-       unsigned long cr30;
-       unsigned long cr31;
-       /* carlos says that gcc understands better memory in a struct,
-        * and it makes our life easier with fpregs -- T-Bone */
-       struct { u32 sw[2]; } s;
-       
-       level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
-
-       printk("%s\n", level); /* don't want to have that pretty register dump messed up */
+       char buf[64];
 
+       printk("%s\n", level);
        printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
        printbinary(buf, regs->gr[0], 32);
        printk("%sPSW: %s %s\n", level, buf, print_tainted());
 
-       for (i = 0; i < 32; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%sr%02d-%02d ", level, i, i + 3);
-               for (j = 0; j < 4; j++) {
-                       p += sprintf(p, " " RFMT, (i+j) == 0 ? 0 : regs->gr[i + j]);
-               }
-               printk("%s\n", buf);
-       }
+       for (i = 0; i < 32; i += 4)
+               PRINTREGS(level, regs->gr, "r", RFMT, i);
+}
 
-       for (i = 0; i < 8; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%ssr%d-%d  ", level, i, i + 3);
-               for (j = 0; j < 4; j++) {
-                       p += sprintf(p, " " RFMT, regs->sr[i + j]);
-               }
-               printk("%s\n", buf);
-       }
+static void print_fr(char *level, struct pt_regs *regs)
+{
+       int i;
+       char buf[64];
+       struct { u32 sw[2]; } s;
 
        /* FR are 64bit everywhere. Need to use asm to get the content
         * of fpsr/fper1, and we assume that we won't have a FP Identify
         * in our way, otherwise we're screwed.
         * The fldd is used to restore the T-bit if there was one, as the
         * store clears it anyway.
-        * BTW, PA2.0 book says "thou shall not use fstw on FPSR/FPERs". */ 
-       __asm__ (
-               "fstd %%fr0,0(%1)       \n\t"
-               "fldd 0(%1),%%fr0       \n\t"
-               : "=m" (s) : "r" (&s) : "%r0"
-               );
+        * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */
+       asm volatile ("fstd %%fr0,0(%1) \n\t"
+                     "fldd 0(%1),%%fr0 \n\t"
+                     : "=m" (s) : "r" (&s) : "r0");
 
        printk("%s\n", level);
        printk("%s      VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level);
@@ -125,14 +110,25 @@ void show_regs(struct pt_regs *regs)
        printk("%sFPER1: %08x\n", level, s.sw[1]);
 
        /* here we'll print fr0 again, tho it'll be meaningless */
-       for (i = 0; i < 32; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%sfr%02d-%02d ", level, i, i + 3);
-               for (j = 0; j < 4; j++)
-                       p += sprintf(p, " %016llx", (i+j) == 0 ? 0 : regs->fr[i+j]);
-               printk("%s\n", buf);
-       }
+       for (i = 0; i < 32; i += 4)
+               PRINTREGS(level, regs->fr, "fr", FFMT, i);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+       int i;
+       char *level;
+       unsigned long cr30, cr31;
+
+       level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
+
+       print_gr(level, regs);
+
+       for (i = 0; i < 8; i += 4)
+               PRINTREGS(level, regs->sr, "sr", RFMT, i);
+
+       if (user_mode(regs))
+               print_fr(level, regs);
 
        cr30 = mfctl(30);
        cr31 = mfctl(31);
index de0a1b21cb40cba92615f550a626a0612207d0cf..92328fbddb3e8becf3ffa346a02d7d9988624e38 100644 (file)
@@ -43,6 +43,8 @@
        "\tldil L%%" #lbl ", %%r1\n"                    \
        "\tldo R%%" #lbl "(%%r1), %%r1\n"               \
        "\tbv,n %%r0(%%r1)\n"
+/* If you use FIXUP_BRANCH, then you must list this clobber */
+#define FIXUP_BRANCH_CLOBBER "r1"
 
 /* 1111 1100 0000 0000 0001 0011 1100 0000 */
 #define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6) 
@@ -157,7 +159,7 @@ static int emulate_ldh(struct pt_regs *regs, int toreg)
 "      .previous\n"
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
-       : "r20" );
+       : "r20", FIXUP_BRANCH_CLOBBER );
 
        DPRINTF("val = 0x" RFMT "\n", val);
 
@@ -202,7 +204,7 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
 "      .previous\n"
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
-       : "r19", "r20" );
+       : "r19", "r20", FIXUP_BRANCH_CLOBBER );
 
        DPRINTF("val = 0x" RFMT "\n", val);
 
@@ -253,7 +255,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "      .previous\n"
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
-       : "r19", "r20" );
+       : "r19", "r20", FIXUP_BRANCH_CLOBBER );
 #else
     {
        unsigned long valh=0,vall=0;
@@ -287,7 +289,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "      .previous\n"
        : "=r" (valh), "=r" (vall), "=r" (ret)
        : "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr)
-       : "r19", "r20" );
+       : "r19", "r20", FIXUP_BRANCH_CLOBBER );
        val=((__u64)valh<<32)|(__u64)vall;
     }
 #endif
@@ -335,7 +337,7 @@ static int emulate_sth(struct pt_regs *regs, int frreg)
 "      .previous\n"
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
-       : "r19" );
+       : "r19", FIXUP_BRANCH_CLOBBER );
 
        return ret;
 }
@@ -389,7 +391,7 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
 "      .previous\n"
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
-       : "r19", "r20", "r21", "r22", "r1" );
+       : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 
        return 0;
 }
@@ -450,7 +452,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "      .previous\n"
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
-       : "r19", "r20", "r21", "r22", "r1" );
+       : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 #else
     {
        unsigned long valh=(val>>32),vall=(val&0xffffffffl);
@@ -495,7 +497,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "      .previous\n"
        : "=r" (ret)
        : "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr)
-       : "r19", "r20", "r21", "r1" );
+       : "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER );
     }
 #endif
 
index e898da2381aa18ef18f2bad62aeaff871b599ac5..b9a40a35a9ed22d98cdccaf519d14eb08dc1b040 100644 (file)
@@ -30,6 +30,10 @@ config GENERIC_HARDIRQS
        bool
        default y
 
+config IRQ_PER_CPU
+       bool
+       default y
+
 config RWSEM_GENERIC_SPINLOCK
        bool
 
@@ -631,6 +635,9 @@ config HOTPLUG_CPU
 
          Say N if you are unsure.
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
+
 config KEXEC
        bool "kexec system call (EXPERIMENTAL)"
        depends on PPC_MULTIPLATFORM && EXPERIMENTAL
index b537cfa4e09b167d383cc8a908790dfd3560127f..358cecdc6aef2e1ab8e91778897db3accce3fd11 100644 (file)
@@ -281,13 +281,13 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        local_irq_disable();
 
        for_each_irq(irq) {
-               struct irq_desc *desc = irq_descp(irq);
+               struct irq_desc *desc = irq_desc + irq;
 
                if (desc->status & IRQ_INPROGRESS)
-                       desc->handler->end(irq);
+                       desc->chip->end(irq);
 
                if (!(desc->status & IRQ_DISABLED))
-                       desc->handler->disable(irq);
+                       desc->chip->disable(irq);
        }
 
        /*
index 40d4c14fde8fa2ae3333062786688584b3387757..24f6050aa4abb2d13a873659e737ae13442409bc 100644 (file)
@@ -120,8 +120,8 @@ int show_interrupts(struct seq_file *p, void *v)
 #else
                seq_printf(p, "%10u ", kstat_irqs(i));
 #endif /* CONFIG_SMP */
-               if (desc->handler)
-                       seq_printf(p, " %s ", desc->handler->typename);
+               if (desc->chip)
+                       seq_printf(p, " %s ", desc->chip->typename);
                else
                        seq_puts(p, "  None      ");
                seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge  ");
@@ -164,13 +164,13 @@ void fixup_irqs(cpumask_t map)
                if (irq_desc[irq].status & IRQ_PER_CPU)
                        continue;
 
-               cpus_and(mask, irq_affinity[irq], map);
+               cpus_and(mask, irq_desc[irq].affinity, map);
                if (any_online_cpu(mask) == NR_CPUS) {
                        printk("Breaking affinity for irq %i\n", irq);
                        mask = map;
                }
-               if (irq_desc[irq].handler->set_affinity)
-                       irq_desc[irq].handler->set_affinity(irq, mask);
+               if (irq_desc[irq].chip->set_affinity)
+                       irq_desc[irq].chip->set_affinity(irq, mask);
                else if (irq_desc[irq].action && !(warned++))
                        printk("Cannot set affinity for irq %i\n", irq);
        }
index b5431ccf1147ae551c763b0fd360d3857c4ee00b..8474355a1a4f46d8a9e1df29a2ad403fc847713a 100644 (file)
@@ -99,7 +99,7 @@ pcibios_fixup_resources(struct pci_dev *dev)
                if (!res->flags)
                        continue;
                if (res->end == 0xffffffff) {
-                       DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
+                       DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n",
                            pci_name(dev), i, res->start, res->end);
                        res->end -= res->start;
                        res->start = 0;
@@ -117,7 +117,7 @@ pcibios_fixup_resources(struct pci_dev *dev)
                        res->start += offset;
                        res->end += offset;
 #ifdef DEBUG
-                       printk("Fixup res %d (%lx) of dev %s: %lx -> %lx\n",
+                       printk("Fixup res %d (%lx) of dev %s: %llx -> %llx\n",
                               i, res->flags, pci_name(dev),
                               res->start - offset, res->start);
 #endif
@@ -173,18 +173,18 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
  * but we want to try to avoid allocating at 0x2900-0x2bff
  * which might have be mirrored at 0x0100-0x03ff..
  */
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-                      unsigned long align)
+void pcibios_align_resource(void *data, struct resource *res,
+                               resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
 
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (size > 0x100) {
                        printk(KERN_ERR "PCI: I/O Region %s/%d too large"
-                              " (%ld bytes)\n", pci_name(dev),
-                              dev->resource - res, size);
+                              " (%lld bytes)\n", pci_name(dev),
+                              dev->resource - res, (unsigned long long)size);
                }
 
                if (start & 0x300) {
@@ -255,8 +255,8 @@ pcibios_allocate_bus_resources(struct list_head *bus_list)
                                }
                        }
 
-                       DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n",
-                           res->start, res->end, res->flags, pr);
+                       DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n",
+                               res->start, res->end, res->flags, pr);
                        if (pr) {
                                if (request_resource(pr, res) == 0)
                                        continue;
@@ -306,7 +306,7 @@ reparent_resources(struct resource *parent, struct resource *res)
        *pp = NULL;
        for (p = res->child; p != NULL; p = p->sibling) {
                p->parent = res;
-               DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n",
+               DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
                    p->name, p->start, p->end, res->name);
        }
        return 0;
@@ -362,13 +362,14 @@ pci_relocate_bridge_resource(struct pci_bus *bus, int i)
                try = conflict->start - 1;
        }
        if (request_resource(pr, res)) {
-               DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n",
+               DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n",
                    res->start, res->end);
                return -1;              /* "can't happen" */
        }
        update_bridge_base(bus, i);
-       printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n",
-              bus->number, i, res->start, res->end);
+       printk(KERN_INFO "PCI: bridge %d resource %d moved to %llx..%llx\n",
+              bus->number, i, (unsigned long long)res->start,
+              (unsigned long long)res->end);
        return 0;
 }
 
@@ -479,14 +480,14 @@ static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
        struct resource *pr, *r = &dev->resource[idx];
 
-       DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n",
+       DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n",
            pci_name(dev), idx, r->start, r->end, r->flags);
        pr = pci_find_parent_resource(dev, r);
        if (!pr || request_resource(pr, r) < 0) {
                printk(KERN_ERR "PCI: Cannot allocate resource region %d"
                       " of device %s\n", idx, pci_name(dev));
                if (pr)
-                       DBG("PCI:  parent is %p: %08lx-%08lx (f=%lx)\n",
+                       DBG("PCI:  parent is %p: %016llx-%016llx (f=%lx)\n",
                            pr, pr->start, pr->end, pr->flags);
                /* We'll assign a new address later */
                r->flags |= IORESOURCE_UNSET;
@@ -956,7 +957,7 @@ 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",
+                       DBG("PCI: IO 0x%llx -> 0x%llx\n",
                                    res->start, res->start + size - 1);
                        break;
                case 2:         /* memory space */
@@ -978,7 +979,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                if(ranges[0] & 0x40000000)
                                        res->flags |= IORESOURCE_PREFETCH;
                                res->start = ranges[na+2];
-                               DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno,
+                               DBG("PCI: MEM[%d] 0x%llx -> 0x%llx\n", memno,
                                            res->start, res->start + size - 1);
                        }
                        break;
@@ -1074,7 +1075,7 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
        DBG("Remapping Bus %d, bridge: %s\n", bus->number, pci_name(bridge));
        res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
        res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
-       DBG("  IO window: %08lx-%08lx\n", res.start, res.end);
+       DBG("  IO window: %016llx-%016llx\n", res.start, res.end);
 
        /* Set up the top and bottom of the PCI I/O segment for this bus. */
        pci_read_config_dword(bridge, PCI_IO_BASE, &l);
@@ -1223,8 +1224,8 @@ do_fixup_p2p_level(struct pci_bus *bus)
                                        continue;
                                if ((r->flags & IORESOURCE_IO) == 0)
                                        continue;
-                               DBG("Trying to allocate from %08lx, size %08lx from parent"
-                                   " res %d: %08lx -> %08lx\n",
+                               DBG("Trying to allocate from %016llx, size %016llx from parent"
+                                   " res %d: %016llx -> %016llx\n",
                                        res->start, res->end, i, r->start, r->end);
                        
                                if (allocate_resource(r, res, res->end + 1, res->start, max,
@@ -1574,8 +1575,8 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        else
                prot |= _PAGE_GUARDED;
 
-       printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
-              prot);
+       printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
+               (unsigned long long)rp->start, prot);
 
        return __pgprot(prot);
 }
@@ -1755,7 +1756,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
 
 void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
-                         u64 *start, u64 *end)
+                         resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
        unsigned long offset = 0;
index 247937dd8b736aab99a79df9bd6d5711bf951a4a..286aa52aae334db643c5769d5816ee7b6a8ba3f9 100644 (file)
@@ -138,11 +138,11 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
        unsigned long alignto;
 
        if (res->flags & IORESOURCE_IO) {
index e5a44812441ac121b980e3d296f19e09651df045..0932a62a1c9637d6834c4872f7f5bca7e2b5d11d 100644 (file)
@@ -215,7 +215,7 @@ int __init ppc_init(void)
 
        /* register CPU devices */
        for_each_possible_cpu(i)
-               register_cpu(&cpu_devices[i], i, NULL);
+               register_cpu(&cpu_devices[i], i);
 
        /* call platform init */
        if (ppc_md.init != NULL) {
index 5bc2585c8036d97e08b8fff0c174cce01ad61c14..4662b580efa1648939eb9e03ec932dd6b63680e2 100644 (file)
@@ -279,7 +279,7 @@ static void unregister_cpu_online(unsigned int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int sysfs_cpu_notify(struct notifier_block *self,
+static int __devinit sysfs_cpu_notify(struct notifier_block *self,
                                      unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned int)(long)hcpu;
@@ -297,30 +297,19 @@ static int sysfs_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block sysfs_cpu_nb = {
+static struct notifier_block __devinitdata sysfs_cpu_nb = {
        .notifier_call  = sysfs_cpu_notify,
 };
 
 /* NUMA stuff */
 
 #ifdef CONFIG_NUMA
-static struct node node_devices[MAX_NUMNODES];
-
 static void register_nodes(void)
 {
        int i;
 
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               if (node_online(i)) {
-                       int p_node = parent_node(i);
-                       struct node *parent = NULL;
-
-                       if (p_node != i)
-                               parent = &node_devices[p_node];
-
-                       register_node(&node_devices[i], i, parent);
-               }
-       }
+       for (i = 0; i < MAX_NUMNODES; i++)
+               register_one_node(i);
 }
 
 int sysfs_add_device_to_node(struct sys_device *dev, int nid)
@@ -359,23 +348,13 @@ static SYSDEV_ATTR(physical_id, 0444, show_physical_id, NULL);
 static int __init topology_init(void)
 {
        int cpu;
-       struct node *parent = NULL;
 
        register_nodes();
-
        register_cpu_notifier(&sysfs_cpu_nb);
 
        for_each_possible_cpu(cpu) {
                struct cpu *c = &per_cpu(cpu_devices, cpu);
 
-#ifdef CONFIG_NUMA
-               /* The node to which a cpu belongs can't be known
-                * until the cpu is made present.
-                */
-               parent = NULL;
-               if (cpu_present(cpu))
-                       parent = &node_devices[cpu_to_node(cpu)];
-#endif
                /*
                 * For now, we just see if the system supports making
                 * the RTAS calls for CPU hotplug.  But, there may be a
@@ -387,7 +366,7 @@ static int __init topology_init(void)
                        c->no_control = 1;
 
                if (cpu_online(cpu) || (c->no_control == 0)) {
-                       register_cpu(c, cpu, parent);
+                       register_cpu(c, cpu);
 
                        sysdev_create_file(&c->sysdev, &attr_physical_id);
                }
index 9e30f968c184af90dfad58f5ff357edfe81e0ed3..d454caada265d599addca7877ced6e5f7a318e04 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/idr.h>
 #include <linux/nodemask.h>
 #include <linux/module.h>
+#include <linux/poison.h>
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
@@ -90,7 +91,7 @@ void free_initmem(void)
 
        addr = (unsigned long)__init_begin;
        for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
-               memset((void *)addr, 0xcc, PAGE_SIZE);
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                ClearPageReserved(virt_to_page(addr));
                init_page_count(virt_to_page(addr));
                free_page(addr);
index 69f3b9a20beb768a093735b800628e18f3d1645f..089d939a0b3e9829b037cc95d38e27e2180746f9 100644 (file)
@@ -114,15 +114,20 @@ void online_page(struct page *page)
        num_physpages++;
 }
 
-int __devinit add_memory(u64 start, u64 size)
+#ifdef CONFIG_NUMA
+int memory_add_physaddr_to_nid(u64 start)
+{
+       return hot_add_scn_to_nid(start);
+}
+#endif
+
+int __devinit arch_add_memory(int nid, u64 start, u64 size)
 {
        struct pglist_data *pgdata;
        struct zone *zone;
-       int nid;
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
 
-       nid = hot_add_scn_to_nid(start);
        pgdata = NODE_DATA(nid);
 
        start = (unsigned long)__va(start);
index aa98cb3b59d82a3c9ff49f35089ba0244eca60d6..fbe23933f73192662b1780ff7d99c728a4eddaf9 100644 (file)
@@ -334,7 +334,7 @@ out:
        return nid;
 }
 
-static int cpu_numa_callback(struct notifier_block *nfb,
+static int __cpuinit cpu_numa_callback(struct notifier_block *nfb,
                             unsigned long action,
                             void *hcpu)
 {
@@ -609,14 +609,15 @@ static void __init *careful_allocation(int nid, unsigned long size,
        return (void *)ret;
 }
 
+static struct notifier_block __cpuinitdata ppc64_numa_nb = {
+       .notifier_call = cpu_numa_callback,
+       .priority = 1 /* Must run before sched domains notifier. */
+};
+
 void __init do_init_bootmem(void)
 {
        int nid;
        unsigned int i;
-       static struct notifier_block ppc64_numa_nb = {
-               .notifier_call = cpu_numa_callback,
-               .priority = 1 /* Must run before sched domains notifier. */
-       };
 
        min_low_pfn = 0;
        max_low_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
index 16f7d3b30e1dbf023e0229fe946441516fc3c845..3baceb00fefaacde0f2929e8572e17c8b3282960 100644 (file)
@@ -91,9 +91,10 @@ int __init add_bridge(struct device_node *dev)
                mpc83xx_pci2_busno = hose->first_busno;
        }
 
-       printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%08lx. "
+       printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. "
               "Firmware bus number: %d->%d\n",
-              rsrc.start, hose->first_busno, hose->last_busno);
+              (unsigned long long)rsrc.start, hose->first_busno,
+              hose->last_busno);
 
        DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
            hose, hose->cfg_addr, hose->cfg_data);
index bad290110ed1dcc34373b80670cefe770aee2587..48c8849c07ca39614caf78ae02206fa1a23dfdc1 100644 (file)
@@ -79,9 +79,10 @@ int __init add_bridge(struct device_node *dev)
                mpc85xx_pci2_busno = hose->first_busno;
        }
 
-       printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%08lx. "
+       printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. "
               "Firmware bus number: %d->%d\n",
-               rsrc.start, hose->first_busno, hose->last_busno);
+               (unsigned long long)rsrc.start, hose->first_busno,
+               hose->last_busno);
 
        DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
                hose, hose->cfg_addr, hose->cfg_data);
index 1bbf822b4efcafada7f9181af9de762772f37f29..7bff3cbc5723b1615b28a46c1e62fe91cdebaccd 100644 (file)
@@ -307,7 +307,7 @@ static void iic_request_ipi(int ipi, const char *name)
        irq = iic_ipi_to_irq(ipi);
        /* IPIs are marked SA_INTERRUPT as they must run with irqs
         * disabled */
-       get_irq_desc(irq)->handler = &iic_pic;
+       get_irq_desc(irq)->chip = &iic_pic;
        get_irq_desc(irq)->status |= IRQ_PER_CPU;
        request_irq(irq, iic_ipi_action, SA_INTERRUPT, name, NULL);
 }
@@ -330,7 +330,7 @@ static void iic_setup_spe_handlers(void)
        for (be=0; be < num_present_cpus() / 2; be++) {
                for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
                        int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
-                       get_irq_desc(irq)->handler = &iic_pic;
+                       get_irq_desc(irq)->chip = &iic_pic;
                }
        }
 }
index 55cbdd77a62dc417136209438e7e249622283ce3..7c3a0b6d34fdffb443ebaab6771575423a50f241 100644 (file)
@@ -162,7 +162,7 @@ void spider_init_IRQ_hardcoded(void)
                spider_pics[node] = ioremap(spiderpic, 0x800);
                for (n = 0; n < IIC_NUM_EXT; n++) {
                        int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-                       get_irq_desc(irq)->handler = &spider_pic;
+                       get_irq_desc(irq)->chip = &spider_pic;
                }
 
                /* do not mask any interrupts because of level */
@@ -217,7 +217,7 @@ void spider_init_IRQ(void)
 
                for (n = 0; n < IIC_NUM_EXT; n++) {
                        int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-                       get_irq_desc(irq)->handler = &spider_pic;
+                       get_irq_desc(irq)->chip = &spider_pic;
                }
 
                /* do not mask any interrupts because of level */
index 015a51787009dc360343ab1378a35dceb70d8a55..c7fea2cca5346fbbd675233bc2506fd1adc9576b 100644 (file)
@@ -2205,7 +2205,7 @@ void spu_init_csa(struct spu_state *csa)
 
        memset(lscsa, 0, sizeof(struct spu_lscsa));
        csa->lscsa = lscsa;
-       csa->register_lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&csa->register_lock);
 
        /* Set LS pages reserved to allow for user-space mapping. */
        for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
index ac224876ce5943f999a0def0007f7214cd35ff9a..53515daf01b18196ab671f56b485330247833807 100644 (file)
@@ -143,7 +143,7 @@ hydra_init(void)
        if (np == NULL || of_address_to_resource(np, 0, &r))
                return 0;
        Hydra = ioremap(r.start, r.end-r.start);
-       printk("Hydra Mac I/O at %lx\n", r.start);
+       printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start);
        printk("Hydra Feature_Control was %x",
               in_le32(&Hydra->Feature_Control));
        out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
@@ -267,7 +267,7 @@ chrp_find_bridges(void)
                               bus_range[0], bus_range[1]);
                printk(" controlled by %s", dev->type);
                if (!is_longtrail)
-                       printk(" at %lx", r.start);
+                       printk(" at %llx", (unsigned long long)r.start);
                printk("\n");
 
                hose = pcibios_alloc_controller();
index 62bbbcf5ded3e27d19f5c2ed0f1d2e402171b87f..33bb4aa0e1e819df8464376de3064b48622f76b1 100644 (file)
@@ -242,9 +242,9 @@ void __init iSeries_activate_IRQs()
        for_each_irq (irq) {
                irq_desc_t *desc = get_irq_desc(irq);
 
-               if (desc && desc->handler && desc->handler->startup) {
+               if (desc && desc->chip && desc->chip->startup) {
                        spin_lock_irqsave(&desc->lock, flags);
-                       desc->handler->startup(irq);
+                       desc->chip->startup(irq);
                        spin_unlock_irqrestore(&desc->lock, flags);
                }
        }
@@ -324,7 +324,7 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
                + function;
        virtirq = virt_irq_create_mapping(realirq);
 
-       irq_desc[virtirq].handler = &iSeries_IRQ_handler;
+       irq_desc[virtirq].chip = &iSeries_IRQ_handler;
        return virtirq;
 }
 
index 9a4efc0c3b2932f025275287f9c42f4f94f30ad9..f7170ff86dab2d04cc1c0e7ec0b235c1684b1cee 100644 (file)
@@ -376,9 +376,10 @@ static void __init maple_fixup_phb_resources(void)
                unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
                hose->io_resource.start += offset;
                hose->io_resource.end += offset;
-               printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
+               printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n",
                       hose->global_number,
-                      hose->io_resource.start, hose->io_resource.end);
+                      (unsigned long long)hose->io_resource.start,
+                      (unsigned long long)hose->io_resource.end);
        }
 }
 
index 498b042e1837567c2326c93faa404d6ffa6a4d00..c7a27eddca6d4b96f002f2c5b5a3725933849089 100644 (file)
@@ -119,7 +119,14 @@ int pmac_backlight_set_legacy_brightness(int brightness)
                down(&pmac_backlight->sem);
                props = pmac_backlight->props;
                props->brightness = brightness *
-                       props->max_brightness / OLD_BACKLIGHT_MAX;
+                       (props->max_brightness + 1) /
+                       (OLD_BACKLIGHT_MAX + 1);
+
+               if (props->brightness > props->max_brightness)
+                       props->brightness = props->max_brightness;
+               else if (props->brightness < 0)
+                       props->brightness = 0;
+
                props->update_status(pmac_backlight);
                up(&pmac_backlight->sem);
 
@@ -140,8 +147,11 @@ int pmac_backlight_get_legacy_brightness()
 
                down(&pmac_backlight->sem);
                props = pmac_backlight->props;
+
                result = props->brightness *
-                       OLD_BACKLIGHT_MAX / props->max_brightness;
+                       (OLD_BACKLIGHT_MAX + 1) /
+                       (props->max_brightness + 1);
+
                up(&pmac_backlight->sem);
        }
        mutex_unlock(&pmac_backlight_mutex);
index 80035853467b000fa1517920762b8bc1bfdfef8b..d524a915aa8646e19080d32d90b8c6292ddcefd0 100644 (file)
@@ -939,9 +939,10 @@ static int __init add_bridge(struct device_node *dev)
                disp_name = "Chaos";
                primary = 0;
        }
-       printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. "
+       printk(KERN_INFO "Found %s PCI host bridge at 0x%016llx. "
               "Firmware bus number: %d->%d\n",
-               disp_name, rsrc.start, hose->first_busno, hose->last_busno);
+               disp_name, (unsigned long long)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",
index 047f954a89eb933206396688cd45dcf3b28d2a12..93e7505debc59813fb30dc82afadf96b963ef0bc 100644 (file)
@@ -546,7 +546,7 @@ struct pmf_device {
 };
 
 static LIST_HEAD(pmf_devices);
-static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pmf_lock);
 static DEFINE_MUTEX(pmf_irq_mutex);
 
 static void pmf_release_device(struct kref *kref)
index 18bf3011d1e3ff103675b0bae793570f4c82606d..9f6189af6dd6b2c5daab9fb1d5d70a3e574ee233 100644 (file)
@@ -446,7 +446,7 @@ static void __init pmac_pic_probe_oldstyle(void)
 
        /* Set the handler for the main PIC */
        for ( i = 0; i < max_real_irqs ; i++ )
-               irq_desc[i].handler = &pmac_pic;
+               irq_desc[i].chip = &pmac_pic;
 
        /* Get addresses of first controller if we have a node for it */
        BUG_ON(of_address_to_resource(master, 0, &r));
@@ -493,7 +493,7 @@ static void __init pmac_pic_probe_oldstyle(void)
        /* 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;
+                       irq_desc[i].chip = &gatwick_pic;
                setup_irq(irq_cascade, &gatwick_cascade_action);
        }
        printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
index 8f2d12935b99fe47de2a273ad4b12338fbcb5f4f..45ccc687e57cbedc3395f0c113b7117a5c6c1b53 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 /* EEH event workqueue setup. */
-static spinlock_t eeh_eventlist_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(eeh_eventlist_lock);
 LIST_HEAD(eeh_eventlist);
 static void eeh_thread_launcher(void *);
 DECLARE_WORK(eeh_event_wq, eeh_thread_launcher, NULL);
index b14f9b5c114edebf110120973e8fe43b4fa1168e..19c03dd43000fdd46c31413da79e7a11d7e5397c 100644 (file)
@@ -238,7 +238,7 @@ static int get_irq_server(unsigned int irq)
 {
        unsigned int server;
        /* For the moment only implement delivery to all cpus or one cpu */
-       cpumask_t cpumask = irq_affinity[irq];
+       cpumask_t cpumask = irq_desc[irq].affinity;
        cpumask_t tmp = CPU_MASK_NONE;
 
        if (!distribute_irqs)
@@ -558,7 +558,7 @@ nextnode:
        }
 
        for (i = irq_offset_value(); i < NR_IRQS; ++i)
-               get_irq_desc(i)->handler = &xics_pic;
+               get_irq_desc(i)->chip = &xics_pic;
 
        xics_setup_cpu();
 
@@ -701,9 +701,9 @@ void xics_migrate_irqs_away(void)
                        continue;
 
                /* We only need to migrate enabled IRQS */
-               if (desc == NULL || desc->handler == NULL
+               if (desc == NULL || desc->chip == NULL
                    || desc->action == NULL
-                   || desc->handler->set_affinity == NULL)
+                   || desc->chip->set_affinity == NULL)
                        continue;
 
                spin_lock_irqsave(&desc->lock, flags);
@@ -728,8 +728,8 @@ void xics_migrate_irqs_away(void)
                       virq, cpu);
 
                /* Reset affinity to all cpus */
-               desc->handler->set_affinity(virq, CPU_MASK_ALL);
-               irq_affinity[virq] = CPU_MASK_ALL;
+               desc->chip->set_affinity(virq, CPU_MASK_ALL);
+               irq_desc[irq].affinity = CPU_MASK_ALL;
 unlock:
                spin_unlock_irqrestore(&desc->lock, flags);
        }
index b7ac32fdd7766f74ceff0d2098df4614eae83701..2bff30f6d6357aa4b44a8bba2ae7ec17d2d17fcd 100644 (file)
@@ -208,7 +208,7 @@ void __init i8259_init(unsigned long intack_addr, int offset)
        spin_unlock_irqrestore(&i8259_lock, flags);
 
        for (i = 0; i < NUM_ISA_INTERRUPTS; ++i)
-               irq_desc[offset + i].handler = &i8259_pic;
+               irq_desc[offset + i].chip = &i8259_pic;
 
        /* reserve our resources */
        setup_irq(offset + 2, &i8259_irqaction);
index 8f01e0f1d847404ceea8ce035f390c1fa2091f6c..46801f5ec03f3883b424239e7a9c13b958ae9144 100644 (file)
@@ -472,7 +472,7 @@ void __init ipic_init(phys_addr_t phys_addr,
        ipic_write(primary_ipic->regs, IPIC_SEMSR, temp);
 
        for (i = 0 ; i < NR_IPIC_INTS ; i++) {
-               irq_desc[i+irq_offset].handler = &ipic;
+               irq_desc[i+irq_offset].chip = &ipic;
                irq_desc[i+irq_offset].status = IRQ_LEVEL;
        }
 
index 74e0d31a3559cf9ca3859a0f3b55fff962966f97..615350d46b526110f55bb0c80f63c7b22e01ffe7 100644 (file)
@@ -32,7 +32,7 @@
 
 static void __iomem *mmio_nvram_start;
 static long mmio_nvram_len;
-static spinlock_t mmio_nvram_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(mmio_nvram_lock);
 
 static ssize_t mmio_nvram_read(char *buf, size_t count, loff_t *index)
 {
index bffe50d02c99578fc75f85055387216ee8a88761..28df9c827ca66b409d0b0427f09c22944dad2079 100644 (file)
@@ -379,14 +379,14 @@ static inline u32 mpic_physmask(u32 cpumask)
 /* Get the mpic structure from the IPI number */
 static inline struct mpic * mpic_from_ipi(unsigned int ipi)
 {
-       return container_of(irq_desc[ipi].handler, struct mpic, hc_ipi);
+       return container_of(irq_desc[ipi].chip, struct mpic, hc_ipi);
 }
 #endif
 
 /* Get the mpic structure from the irq number */
 static inline struct mpic * mpic_from_irq(unsigned int irq)
 {
-       return container_of(irq_desc[irq].handler, struct mpic, hc_irq);
+       return container_of(irq_desc[irq].chip, struct mpic, hc_irq);
 }
 
 /* Send an EOI */
@@ -752,7 +752,7 @@ void __init mpic_init(struct mpic *mpic)
                if (!(mpic->flags & MPIC_PRIMARY))
                        continue;
                irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU;
-               irq_desc[mpic->ipi_offset+i].handler = &mpic->hc_ipi;
+               irq_desc[mpic->ipi_offset+i].chip = &mpic->hc_ipi;
 #endif /* CONFIG_SMP */
        }
 
@@ -813,7 +813,7 @@ void __init mpic_init(struct mpic *mpic)
                /* init linux descriptors */
                if (i < mpic->irq_count) {
                        irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0;
-                       irq_desc[mpic->irq_offset+i].handler = &mpic->hc_irq;
+                       irq_desc[mpic->irq_offset+i].chip = &mpic->hc_irq;
                }
        }
        
@@ -906,7 +906,7 @@ void mpic_setup_this_cpu(void)
        /* let the mpic know we want intrs. default affinity is 0xffffffff
         * until changed via /proc. That's how it's done on x86. If we want
         * it differently, then we should make sure we also change the default
-        * values of irq_affinity in irq.c.
+        * values of irq_desc[].affinity in irq.c.
         */
        if (distribute_irqs) {
                for (i = 0; i < mpic->num_sources ; i++)
index 12b84ca51327f570d8becc0696c0cd405f2edadc..9b3ace26280cb85301fd2954492f6dcb47530750 100644 (file)
@@ -187,7 +187,7 @@ cpm_interrupt_init(void)
          * interrupt vectors
          */
         for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
-                irq_desc[i].handler = &cpm_pic;
+                irq_desc[i].chip = &cpm_pic;
 
        /* Set our interrupt handler with the core CPU. */
        if (setup_irq(CPM_INTERRUPT, &cpm_interrupt_irqaction))
index d20accf9650dcbacc4ec88806c074d150cd10dca..242bb052be679f66bca5345fdeda0f226ef90046 100644 (file)
@@ -95,8 +95,10 @@ pcibios_fixup_resources(struct pci_dev *dev)
                if (!res->flags)
                        continue;
                if (res->end == 0xffffffff) {
-                       DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
-                           pci_name(dev), i, res->start, res->end);
+                       DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n",
+                               pci_name(dev), i,
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                        res->end -= res->start;
                        res->start = 0;
                        res->flags |= IORESOURCE_UNSET;
@@ -169,18 +171,18 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
  * but we want to try to avoid allocating at 0x2900-0x2bff
  * which might have be mirrored at 0x0100-0x03ff..
  */
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-                      unsigned long align)
+void pcibios_align_resource(void *data, struct resource *res,
+                               resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
 
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (size > 0x100) {
                        printk(KERN_ERR "PCI: I/O Region %s/%d too large"
-                              " (%ld bytes)\n", pci_name(dev),
-                              dev->resource - res, size);
+                              " (%lld bytes)\n", pci_name(dev),
+                              dev->resource - res, (unsigned long long)size);
                }
 
                if (start & 0x300) {
@@ -251,8 +253,9 @@ pcibios_allocate_bus_resources(struct list_head *bus_list)
                                }
                        }
 
-                       DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n",
-                           res->start, res->end, res->flags, pr);
+                       DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n",
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end, res->flags, pr);
                        if (pr) {
                                if (request_resource(pr, res) == 0)
                                        continue;
@@ -302,8 +305,9 @@ reparent_resources(struct resource *parent, struct resource *res)
        *pp = NULL;
        for (p = res->child; p != NULL; p = p->sibling) {
                p->parent = res;
-               DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n",
-                   p->name, p->start, p->end, res->name);
+               DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
+                       p->name, (unsigned long long)p->start,
+                       (unsigned long long)p->end, res->name);
        }
        return 0;
 }
@@ -358,13 +362,15 @@ pci_relocate_bridge_resource(struct pci_bus *bus, int i)
                try = conflict->start - 1;
        }
        if (request_resource(pr, res)) {
-               DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n",
-                   res->start, res->end);
+               DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n",
+                       (unsigned long long)res->start,
+                       (unsigned long long)res->end);
                return -1;              /* "can't happen" */
        }
        update_bridge_base(bus, i);
-       printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n",
-              bus->number, i, res->start, res->end);
+       printk(KERN_INFO "PCI: bridge %d resource %d moved to %llx..%llx\n",
+               bus->number, i, (unsigned long long)res->start,
+               (unsigned long long)res->end);
        return 0;
 }
 
@@ -475,15 +481,17 @@ static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
        struct resource *pr, *r = &dev->resource[idx];
 
-       DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n",
-           pci_name(dev), idx, r->start, r->end, r->flags);
+       DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n",
+           pci_name(dev), idx, (unsigned long long)r->start,
+           (unsigned long long)r->end, r->flags);
        pr = pci_find_parent_resource(dev, r);
        if (!pr || request_resource(pr, r) < 0) {
                printk(KERN_ERR "PCI: Cannot allocate resource region %d"
                       " of device %s\n", idx, pci_name(dev));
                if (pr)
-                       DBG("PCI:  parent is %p: %08lx-%08lx (f=%lx)\n",
-                           pr, pr->start, pr->end, pr->flags);
+                       DBG("PCI:  parent is %p: %016llx-%016llx (f=%lx)\n",
+                               pr, (unsigned long long)pr->start,
+                               (unsigned long long)pr->end, pr->flags);
                /* We'll assign a new address later */
                r->flags |= IORESOURCE_UNSET;
                r->end -= r->start;
@@ -952,8 +960,8 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        else
                prot |= _PAGE_GUARDED;
 
-       printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
-              prot);
+       printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
+               (unsigned long long)rp->start, prot);
 
        return __pgprot(prot);
 }
@@ -1122,7 +1130,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
 
 void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
-                         u64 *start, u64 *end)
+                         resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
        unsigned long offset = 0;
index 1f79e84ab464dd8a416eaab3d104e8aff11ea6d5..4b4607d89bfa6e1c105a01d85c0a674748c5fa8f 100644 (file)
@@ -475,7 +475,7 @@ int __init ppc_init(void)
 
        /* register CPU devices */
        for_each_possible_cpu(i)
-               register_cpu(&cpu_devices[i], i, NULL);
+               register_cpu(&cpu_devices[i], i);
 
        /* call platform init */
        if (ppc_md.init != NULL) {
index fe0cdc04d4366b0c9460486e25d8b00eb4a58a76..5c4118a459f3eb1b6822b5817ee16248f9c9da48 100644 (file)
@@ -734,9 +734,9 @@ void apus_init_IRQ(void)
        for ( i = 0 ; i < AMI_IRQS; i++ ) {
                irq_desc[i].status = IRQ_LEVEL;
                if (i < IRQ_AMIGA_AUTO) {
-                       irq_desc[i].handler = &amiga_irqctrl;
+                       irq_desc[i].chip = &amiga_irqctrl;
                } else {
-                       irq_desc[i].handler = &amiga_sys_irqctrl;
+                       irq_desc[i].chip = &amiga_sys_irqctrl;
                        action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO];
                        if (action->name)
                                setup_irq(i, action);
index 866807b4ad0b32ffc32b92c281180b64a4356e9b..41006d2b4b3823a3438f2d79e43caf67b77ee5ab 100644 (file)
@@ -172,7 +172,7 @@ void __init sbc82xx_init_IRQ(void)
        
        /* Set up the interrupt handlers for the i8259 IRQs */
        for (i = NR_SIU_INTS; i < NR_SIU_INTS + 8; i++) {
-                irq_desc[i].handler = &sbc82xx_i8259_ic;
+                irq_desc[i].chip = &sbc82xx_i8259_ic;
                irq_desc[i].status |= IRQ_LEVEL;
        }
 
index 5add0a919ef6182695f88fee3d149bbdd985e7b5..172aa215fdb0d1ac059c725187f9afdc4f5aaaf7 100644 (file)
@@ -140,12 +140,12 @@ cpc700_init_IRQ(void)
                                                        /* IRQ 0 is highest */
 
        for (i = 0; i < 17; i++) {
-               irq_desc[i].handler = &cpc700_pic;
+               irq_desc[i].chip = &cpc700_pic;
                cpc700_pic_init_irq(i);
        }
 
        for (i = 20; i < 32; i++) {
-               irq_desc[i].handler = &cpc700_pic;
+               irq_desc[i].chip = &cpc700_pic;
                cpc700_pic_init_irq(i);
        }
 
index 29d95d415ceb7f70accd8c8381f9666f748be467..c0fee0beb81503722a64053122be7fe90d017b4f 100644 (file)
@@ -171,7 +171,7 @@ void cpm2_init_IRQ(void)
        /* Enable chaining to OpenPIC, and make everything level
         */
        for (i = 0; i < NR_CPM_INTS; i++) {
-               irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
+               irq_desc[i+CPM_IRQ_OFFSET].chip = &cpm2_pic;
                irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
        }
 }
index dc3bd9ecbbf6956c88079e1fc5a40e27c3c774f9..91096b38ae70297b77fcd8820e3e51a5d6ecf030 100644 (file)
@@ -98,7 +98,7 @@ gt64260_init_irq(void)
 
        /* use the gt64260 for all (possible) interrupt sources */
        for (i = gt64260_irq_base; i < (gt64260_irq_base + 96); i++)
-               irq_desc[i].handler = &gt64260_pic;
+               irq_desc[i].chip = &gt64260_pic;
 
        if (ppc_md.progress)
                ppc_md.progress("gt64260_init_irq: exit", 0x0);
index 1941a8c7ca9a3dbd851b619c6e55ea7b39bc5dcf..63fa5b313396b42fba12d24cc801b34921b49f96 100644 (file)
@@ -159,7 +159,7 @@ pq2pci_init_irq(void)
        immap->im_memctl.memc_or8 = 0xffff8010;
 #endif
        for (irq = NR_CPM_INTS; irq < NR_CPM_INTS + 4; irq++)
-               irq_desc[irq].handler = &pq2pci_ic;
+               irq_desc[irq].chip = &pq2pci_ic;
 
        /* make PCI IRQ level sensitive */
        immap->im_intctl.ic_siexr &=
index dae9af78bde1ba4674f889be162f87312bbe0733..0c4c0de7c59f0b10990969215b0bca76d37a8c55 100644 (file)
@@ -347,13 +347,13 @@ m8xx_init_IRQ(void)
        int i;
 
        for (i = SIU_IRQ_OFFSET ; i < SIU_IRQ_OFFSET + NR_SIU_INTS ; i++)
-               irq_desc[i].handler = &ppc8xx_pic;
+               irq_desc[i].chip = &ppc8xx_pic;
 
        cpm_interrupt_init();
 
 #if defined(CONFIG_PCI)
        for (i = I8259_IRQ_OFFSET ; i < I8259_IRQ_OFFSET + NR_8259_INTS ; i++)
-               irq_desc[i].handler = &i8259_pic;
+               irq_desc[i].chip = &i8259_pic;
 
        i8259_pic_irq_offset = I8259_IRQ_OFFSET;
        i8259_init(0);
index c4406f9dc6a3d0d8c2174524533b914a4313f1af..6425b5cee7db2bc7c638c5c5faa41b07467af98b 100644 (file)
@@ -204,9 +204,9 @@ mpc52xx_init_irq(void)
        out_be32(&intr->main_pri1, 0);
        out_be32(&intr->main_pri2, 0);
 
-       /* Initialize irq_desc[i].handler's with mpc52xx_ic. */
+       /* Initialize irq_desc[i].chip's with mpc52xx_ic. */
        for (i = 0; i < NR_IRQS; i++) {
-               irq_desc[i].handler = &mpc52xx_ic;
+               irq_desc[i].chip = &mpc52xx_ic;
                irq_desc[i].status = IRQ_LEVEL;
        }
 
index 5a19697060f0290ba124adb2fca72001ad82e0a3..a4244d46838197d0b6b20126ba7a454f2b7659f8 100644 (file)
@@ -119,7 +119,7 @@ mv64360_init_irq(void)
        /* All interrupts are level interrupts */
        for (i = mv64360_irq_base; i < (mv64360_irq_base + 96); i++) {
                irq_desc[i].status |= IRQ_LEVEL;
-               irq_desc[i].handler = &mv64360_pic;
+               irq_desc[i].chip = &mv64360_pic;
        }
 
        if (ppc_md.progress)
index 70456c8f998c7be7c992cad3ec8c8a61c2959fa4..767a0bc9581765fb21c70920a0fc93e7b3697735 100644 (file)
@@ -373,7 +373,7 @@ void __init openpic_init(int offset)
                                OPENPIC_VEC_IPI+i+offset);
                /* IPIs are per-CPU */
                irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
-               irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
+               irq_desc[OPENPIC_VEC_IPI+i+offset].chip = &open_pic_ipi;
        }
 #endif
 
@@ -408,7 +408,7 @@ void __init openpic_init(int offset)
 
        /* Init descriptors */
        for (i = offset; i < NumSources + offset; i++)
-               irq_desc[i].handler = &open_pic;
+               irq_desc[i].chip = &open_pic;
 
        /* Initialize the spurious interrupt */
        if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
@@ -615,8 +615,8 @@ void __devinit do_openpic_setup_cpu(void)
        /* let the openpic know we want intrs. default affinity
         * is 0xffffffff until changed via /proc
         * That's how it's done on x86. If we want it differently, then
-        * we should make sure we also change the default values of irq_affinity
-        * in irq.c.
+        * we should make sure we also change the default values of
+        * irq_desc[].affinity in irq.c.
         */
        for (i = 0; i < NumSources; i++)
                openpic_mapirq(i, msk, CPU_MASK_ALL);
index bcbe40de26fe511cf42aba2faa98ff449a7f00d9..b8154efff6ede2c7a14224a920542b4650488dac 100644 (file)
@@ -290,7 +290,7 @@ void __init openpic2_init(int offset)
 
        /* Init descriptors */
        for (i = offset; i < NumSources + offset; i++)
-               irq_desc[i].handler = &open_pic2;
+               irq_desc[i].chip = &open_pic2;
 
        /* Initialize the spurious interrupt */
        if (ppc_md.progress) ppc_md.progress("openpic2: spurious",0x3bd);
index c46043c47225b72b737d79dcaac46cb2a4ced2bf..1584c8b1229f76bac6627a939c4d3efd9b206d4d 100644 (file)
@@ -121,5 +121,5 @@ ppc4xx_pic_init(void)
        ppc_md.get_irq = ppc403_pic_get_irq;
 
        for (i = 0; i < NR_IRQS; i++)
-               irq_desc[i].handler = &ppc403_aic;
+               irq_desc[i].chip = &ppc403_aic;
 }
index fd9af0fc0e9f43ddce46abdba519b73e6c6c1810..e669c1335d47e93bf46a603e2e9ce1dd098420a3 100644 (file)
@@ -276,7 +276,7 @@ void __init ppc4xx_pic_init(void)
 
        /* Attach low-level handlers */
        for (i = 0; i < (NR_UICS << 5); ++i) {
-               irq_desc[i].handler = &__uic[i >> 5].decl;
+               irq_desc[i].chip = &__uic[i >> 5].decl;
                if (is_level_sensitive(i))
                        irq_desc[i].status |= IRQ_LEVEL;
        }
index e672b600f315499a50b84a5ee5750e86f0e8e5c7..39a93dc6375b82a074aad29b9774865e27f001a5 100644 (file)
@@ -143,7 +143,7 @@ ppc4xx_pic_init(void)
        ppc_md.get_irq = xilinx_pic_get_irq;
 
        for (i = 0; i < NR_IRQS; ++i) {
-               irq_desc[i].handler = &xilinx_intc;
+               irq_desc[i].chip = &xilinx_intc;
 
                if (XPAR_INTC_0_KIND_OF_INTR & (0x00000001 << i))
                        irq_desc[i].status &= ~IRQ_LEVEL;
index e806a8922bbbe83e180e806fcbdf28efef5af700..71d65eb30650463345a6d02ca7e680b3b3f27240 100644 (file)
@@ -3,9 +3,9 @@
  *
  * Definitions and interface for Linux - z/VM Monitor Stream.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 //#define APPLDATA_DEBUG                       /* Debug messages on/off */
 #define CTL_APPLDATA_NET_SUM   2125
 #define CTL_APPLDATA_PROC      2126
 
+#ifndef CONFIG_64BIT
+
+#define APPLDATA_START_INTERVAL_REC 0x00       /* Function codes for */
+#define APPLDATA_STOP_REC          0x01        /* DIAG 0xDC      */
+#define APPLDATA_GEN_EVENT_RECORD   0x02
+#define APPLDATA_START_CONFIG_REC   0x03
+
+#else
+
+#define APPLDATA_START_INTERVAL_REC 0x80
+#define APPLDATA_STOP_REC          0x81
+#define APPLDATA_GEN_EVENT_RECORD   0x82
+#define APPLDATA_START_CONFIG_REC   0x83
+
+#endif /* CONFIG_64BIT */
+
 #define P_INFO(x...)   printk(KERN_INFO MY_PRINT_NAME " info: " x)
 #define P_ERROR(x...)  printk(KERN_ERR MY_PRINT_NAME " error: " x)
 #define P_WARNING(x...)        printk(KERN_WARNING MY_PRINT_NAME " status: " x)
@@ -53,7 +69,11 @@ struct appldata_ops {
        void *data;                             /* record data */
        unsigned int size;                      /* size of record */
        struct module *owner;                   /* THIS_MODULE */
+       char mod_lvl[2];                        /* modification level, EBCDIC */
 };
 
 extern int appldata_register_ops(struct appldata_ops *ops);
 extern void appldata_unregister_ops(struct appldata_ops *ops);
+extern int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+                        u16 length, char *mod_lvl);
+
index 9a22434a580c52f1245bedd5d0a1a6a7d81d7866..61bc44626c043ec2bb41c0e61399b2e1127680ae 100644 (file)
@@ -5,9 +5,9 @@
  * Exports appldata_register_ops() and appldata_unregister_ops() for the
  * data gathering modules.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
 
 #define TOD_MICRO      0x01000                 /* nr. of TOD clock units
                                                   for 1 microsecond */
-#ifndef CONFIG_64BIT
-
-#define APPLDATA_START_INTERVAL_REC 0x00       /* Function codes for */
-#define APPLDATA_STOP_REC          0x01        /* DIAG 0xDC      */
-#define APPLDATA_GEN_EVENT_RECORD   0x02
-#define APPLDATA_START_CONFIG_REC   0x03
-
-#else
-
-#define APPLDATA_START_INTERVAL_REC 0x80
-#define APPLDATA_STOP_REC          0x81
-#define APPLDATA_GEN_EVENT_RECORD   0x82
-#define APPLDATA_START_CONFIG_REC   0x83
-
-#endif /* CONFIG_64BIT */
-
 
 /*
  * Parameter list for DIAGNOSE X'DC'
@@ -195,8 +179,8 @@ static void appldata_work_fn(void *data)
  *
  * prepare parameter list, issue DIAG 0xDC
  */
-static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
-                       u16 length)
+int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+                       u16 length, char *mod_lvl)
 {
        unsigned long ry;
        struct appldata_product_id {
@@ -214,7 +198,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
                .record_nr  = record_nr,
                .version_nr = {0xF2, 0xF6},             /* "26" */
                .release_nr = {0xF0, 0xF1},             /* "01" */
-               .mod_lvl    = {0xF0, 0xF0},             /* "00" */
+               .mod_lvl    = {mod_lvl[0], mod_lvl[1]},
        };
        struct appldata_parameter_list appldata_parameter_list = {
                                .diag = 0xDC,
@@ -467,24 +451,25 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                        module_put(ops->owner);
                        return -ENODEV;
                }
-               ops->active = 1;
                ops->callback(ops->data);       // init record
                rc = appldata_diag(ops->record_nr,
                                        APPLDATA_START_INTERVAL_REC,
-                                       (unsigned long) ops->data, ops->size);
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("START DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
                        module_put(ops->owner);
-                       ops->active = 0;
                } else {
                        P_INFO("Monitoring %s data enabled, "
                                "DIAG 0xDC started.\n", ops->name);
+                       ops->active = 1;
                }
        } else if ((buf[0] == '0') && (ops->active == 1)) {
                ops->active = 0;
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size);
+                               (unsigned long) ops->data, ops->size,
+                               ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("STOP DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
@@ -633,7 +618,7 @@ appldata_offline_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static int
+static int __cpuinit
 appldata_cpu_notify(struct notifier_block *self,
                    unsigned long action, void *hcpu)
 {
@@ -652,7 +637,7 @@ appldata_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block appldata_nb = {
+static struct notifier_block __devinitdata appldata_nb = {
        .notifier_call = appldata_cpu_notify,
 };
 
@@ -710,7 +695,8 @@ static void __exit appldata_exit(void)
        list_for_each(lh, &appldata_ops_list) {
                ops = list_entry(lh, struct appldata_ops, list);
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size);
+                               (unsigned long) ops->data, ops->size,
+                               ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("STOP DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
@@ -739,6 +725,7 @@ MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
 
 EXPORT_SYMBOL_GPL(appldata_register_ops);
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
+EXPORT_SYMBOL_GPL(appldata_diag);
 
 #ifdef MODULE
 /*
@@ -779,7 +766,6 @@ unsigned long nr_iowait(void)
 #endif /* MODULE */
 EXPORT_SYMBOL_GPL(si_swapinfo);
 EXPORT_SYMBOL_GPL(nr_threads);
-EXPORT_SYMBOL_GPL(avenrun);
 EXPORT_SYMBOL_GPL(get_full_page_state);
 EXPORT_SYMBOL_GPL(nr_running);
 EXPORT_SYMBOL_GPL(nr_iowait);
index f0e2fbed3d4cf86a8000ec212e435546098507fc..7915a197d96d227bb2175ada9125be89399fafa5 100644 (file)
@@ -4,9 +4,9 @@
  * Data gathering module for Linux-VM Monitor Stream, Stage 1.
  * Collects data related to memory management.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -152,6 +152,7 @@ static struct appldata_ops ops = {
        .callback  = &appldata_get_mem_data,
        .data      = &appldata_mem_data,
        .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF0},              /* EBCDIC "00" */
 };
 
 
index 2a4c7432db4ac2960cde34ee6033671fe171cfc5..39b7bdecbf0563f38046245af32d0258c2054c05 100644 (file)
@@ -5,9 +5,9 @@
  * Collects accumulated network statistics (Packets received/transmitted,
  * dropped, errors, ...).
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -152,6 +152,7 @@ static struct appldata_ops ops = {
        .callback  = &appldata_get_net_sum_data,
        .data      = &appldata_net_sum_data,
        .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF0},              /* EBCDIC "00" */
 };
 
 
index 99ddd3bf2fbaac6bb2e5ef49fbd43e7c16bac0f2..f2b44a2f1deca958c9f1840d47407b149a730041 100644 (file)
@@ -4,9 +4,9 @@
  * Data gathering module for Linux-VM Monitor Stream, Stage 1.
  * Collects misc. OS related data (CPU utilization, running processes).
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -44,11 +44,14 @@ struct appldata_os_per_cpu {
        u32 per_cpu_system;     /* ... spent in kernel mode         */
        u32 per_cpu_idle;       /* ... spent in idle mode           */
 
-// New in 2.6 -->
+       /* New in 2.6 */
        u32 per_cpu_irq;        /* ... spent in interrupts          */
        u32 per_cpu_softirq;    /* ... spent in softirqs            */
        u32 per_cpu_iowait;     /* ... spent while waiting for I/O  */
-// <-- New in 2.6
+
+       /* New in modification level 01 */
+       u32 per_cpu_steal;      /* ... stolen by hypervisor         */
+       u32 cpu_id;             /* number of this CPU               */
 } __attribute__((packed));
 
 struct appldata_os_data {
@@ -68,10 +71,9 @@ struct appldata_os_data {
        u32 avenrun[3];         /* average nr. of running processes during */
                                /* the last 1, 5 and 15 minutes */
 
-// New in 2.6 -->
+       /* New in 2.6 */
        u32 nr_iowait;          /* number of blocked threads
                                   (waiting for I/O)               */
-// <-- New in 2.6
 
        /* per cpu data */
        struct appldata_os_per_cpu os_cpu[0];
@@ -79,6 +81,14 @@ struct appldata_os_data {
 
 static struct appldata_os_data *appldata_os_data;
 
+static struct appldata_ops ops = {
+       .ctl_nr    = CTL_APPLDATA_OS,
+       .name      = "os",
+       .record_nr = APPLDATA_RECORD_OS_ID,
+       .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF1},              /* EBCDIC "01" */
+};
+
 
 static inline void appldata_print_debug(struct appldata_os_data *os_data)
 {
@@ -100,15 +110,17 @@ static inline void appldata_print_debug(struct appldata_os_data *os_data)
        P_DEBUG("nr_cpus = %u\n", os_data->nr_cpus);
        for (i = 0; i < os_data->nr_cpus; i++) {
                P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, "
-                       "idle = %u, irq = %u, softirq = %u, iowait = %u\n",
-                               i,
+                       "idle = %u, irq = %u, softirq = %u, iowait = %u, "
+                       "steal = %u\n",
+                               os_data->os_cpu[i].cpu_id,
                                os_data->os_cpu[i].per_cpu_user,
                                os_data->os_cpu[i].per_cpu_nice,
                                os_data->os_cpu[i].per_cpu_system,
                                os_data->os_cpu[i].per_cpu_idle,
                                os_data->os_cpu[i].per_cpu_irq,
                                os_data->os_cpu[i].per_cpu_softirq,
-                               os_data->os_cpu[i].per_cpu_iowait);
+                               os_data->os_cpu[i].per_cpu_iowait,
+                               os_data->os_cpu[i].per_cpu_steal);
        }
 
        P_DEBUG("sync_count_1 = %u\n", os_data->sync_count_1);
@@ -123,14 +135,13 @@ static inline void appldata_print_debug(struct appldata_os_data *os_data)
  */
 static void appldata_get_os_data(void *data)
 {
-       int i, j;
+       int i, j, rc;
        struct appldata_os_data *os_data;
+       unsigned int new_size;
 
        os_data = data;
        os_data->sync_count_1++;
 
-       os_data->nr_cpus = num_online_cpus();
-
        os_data->nr_threads = nr_threads;
        os_data->nr_running = nr_running();
        os_data->nr_iowait  = nr_iowait();
@@ -154,9 +165,44 @@ static void appldata_get_os_data(void *data)
                        cputime_to_jiffies(kstat_cpu(i).cpustat.softirq);
                os_data->os_cpu[j].per_cpu_iowait =
                        cputime_to_jiffies(kstat_cpu(i).cpustat.iowait);
+               os_data->os_cpu[j].per_cpu_steal =
+                       cputime_to_jiffies(kstat_cpu(i).cpustat.steal);
+               os_data->os_cpu[j].cpu_id = i;
                j++;
        }
 
+       os_data->nr_cpus = j;
+
+       new_size = sizeof(struct appldata_os_data) +
+                  (os_data->nr_cpus * sizeof(struct appldata_os_per_cpu));
+       if (ops.size != new_size) {
+               if (ops.active) {
+                       rc = appldata_diag(APPLDATA_RECORD_OS_ID,
+                                          APPLDATA_START_INTERVAL_REC,
+                                          (unsigned long) ops.data, new_size,
+                                          ops.mod_lvl);
+                       if (rc != 0) {
+                               P_ERROR("os: START NEW DIAG 0xDC failed, "
+                                       "return code: %d, new size = %i\n", rc,
+                                       new_size);
+                               P_INFO("os: stopping old record now\n");
+                       } else
+                               P_INFO("os: new record size = %i\n", new_size);
+
+                       rc = appldata_diag(APPLDATA_RECORD_OS_ID,
+                                          APPLDATA_STOP_REC,
+                                          (unsigned long) ops.data, ops.size,
+                                          ops.mod_lvl);
+                       if (rc != 0)
+                               P_ERROR("os: STOP OLD DIAG 0xDC failed, "
+                                       "return code: %d, old size = %i\n", rc,
+                                       ops.size);
+                       else
+                               P_INFO("os: old record size = %i stopped\n",
+                                       ops.size);
+               }
+               ops.size = new_size;
+       }
        os_data->timestamp = get_clock();
        os_data->sync_count_2++;
 #ifdef APPLDATA_DEBUG
@@ -165,15 +211,6 @@ static void appldata_get_os_data(void *data)
 }
 
 
-static struct appldata_ops ops = {
-       .ctl_nr    = CTL_APPLDATA_OS,
-       .name      = "os",
-       .record_nr = APPLDATA_RECORD_OS_ID,
-       .callback  = &appldata_get_os_data,
-       .owner     = THIS_MODULE,
-};
-
-
 /*
  * appldata_os_init()
  *
@@ -181,26 +218,25 @@ static struct appldata_ops ops = {
  */
 static int __init appldata_os_init(void)
 {
-       int rc, size;
+       int rc, max_size;
 
-       size = sizeof(struct appldata_os_data) +
-               (NR_CPUS * sizeof(struct appldata_os_per_cpu));
-       if (size > APPLDATA_MAX_REC_SIZE) {
-               P_ERROR("Size of record = %i, bigger than maximum (%i)!\n",
-                       size, APPLDATA_MAX_REC_SIZE);
+       max_size = sizeof(struct appldata_os_data) +
+                  (NR_CPUS * sizeof(struct appldata_os_per_cpu));
+       if (max_size > APPLDATA_MAX_REC_SIZE) {
+               P_ERROR("Max. size of OS record = %i, bigger than maximum "
+                       "record size (%i)\n", max_size, APPLDATA_MAX_REC_SIZE);
                rc = -ENOMEM;
                goto out;
        }
-       P_DEBUG("sizeof(os) = %i, sizeof(os_cpu) = %lu\n", size,
+       P_DEBUG("max. sizeof(os) = %i, sizeof(os_cpu) = %lu\n", max_size,
                sizeof(struct appldata_os_per_cpu));
 
-       appldata_os_data = kmalloc(size, GFP_DMA);
+       appldata_os_data = kzalloc(max_size, GFP_DMA);
        if (appldata_os_data == NULL) {
                P_ERROR("No memory for %s!\n", ops.name);
                rc = -ENOMEM;
                goto out;
        }
-       memset(appldata_os_data, 0, size);
 
        appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu);
        appldata_os_data->cpu_offset   = offsetof(struct appldata_os_data,
@@ -208,7 +244,7 @@ static int __init appldata_os_init(void)
        P_DEBUG("cpu offset = %u\n", appldata_os_data->cpu_offset);
 
        ops.data = appldata_os_data;
-       ops.size = size;
+       ops.callback  = &appldata_get_os_data;
        rc = appldata_register_ops(&ops);
        if (rc != 0) {
                P_ERROR("Error registering ops, rc = %i\n", rc);
index 1f451c2cb071896f7032e990ac78256769a74c58..12a6311e9838901ed2ca106a9e34f778bd33be27 100644 (file)
@@ -177,11 +177,6 @@ struct elf_prpsinfo32
 
 #include <linux/highuid.h>
 
-#undef NEW_TO_OLD_UID
-#undef NEW_TO_OLD_GID
-#define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
-#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) 
-
 #define elf_addr_t     u32
 /*
 #define init_elf_binfmt init_elf32_binfmt
index b2448487854cfbd5a36aae778be1eebec9184211..aa8b52c2140f1e672bed5c4be2715d10140e01f4 100644 (file)
@@ -93,13 +93,22 @@ STACK_SIZE  = 1 << STACK_SHIFT
        l       %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13
        .endm
 
-       .macro  SAVE_ALL psworg,savearea,sync
+       .macro  SAVE_ALL_SYNC psworg,savearea
        la      %r12,\psworg
-       .if     \sync
        tm      \psworg+1,0x01          # test problem state bit
        bz      BASED(2f)               # skip stack setup save
        l       %r15,__LC_KERNEL_STACK  # problem state -> load ksp
-       .else
+#ifdef CONFIG_CHECK_STACK
+       b       BASED(3f)
+2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
+       bz      BASED(stack_overflow)
+3:
+#endif
+2:
+       .endm
+
+       .macro  SAVE_ALL_ASYNC psworg,savearea
+       la      %r12,\psworg
        tm      \psworg+1,0x01          # test problem state bit
        bnz     BASED(1f)               # from user -> load async stack
        clc     \psworg+4(4),BASED(.Lcritical_end)
@@ -115,7 +124,6 @@ STACK_SIZE  = 1 << STACK_SHIFT
        sra     %r14,STACK_SHIFT
        be      BASED(2f)
 1:     l       %r15,__LC_ASYNC_STACK
-       .endif
 #ifdef CONFIG_CHECK_STACK
        b       BASED(3f)
 2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
@@ -196,7 +204,7 @@ system_call:
        STORE_TIMER __LC_SYNC_ENTER_TIMER
 sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
-        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        lh      %r7,0x8a          # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -425,7 +433,7 @@ pgm_check_handler:
        SAVE_ALL_BASE __LC_SAVE_AREA
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         bnz     BASED(pgm_per)           # got per exception -> special case
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -464,7 +472,7 @@ pgm_per:
 # Normal per exception
 #
 pgm_per_std:
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -490,7 +498,7 @@ pgm_no_vtime2:
 # it was a single stepped SVC that is causing all the trouble
 #
 pgm_svcper:
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -519,7 +527,7 @@ io_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
-        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
+       SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
        CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -631,7 +639,7 @@ ext_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
-        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
+       SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
        CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -657,21 +665,31 @@ __critical_end:
         .globl mcck_int_handler
 mcck_int_handler:
        spt     __LC_CPU_TIMER_SAVE_AREA        # revalidate cpu timer
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
        lm      %r0,%r15,__LC_GPREGS_SAVE_AREA  # revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+32
        la      %r12,__LC_MCK_OLD_PSW
        tm      __LC_MCCK_CODE,0x80     # system damage?
        bo      BASED(mcck_int_main)    # yes -> rest of mcck code invalid
-       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
-       bo      BASED(0f)
-       spt     __LC_LAST_UPDATE_TIMER  # revalidate cpu timer
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_SYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_EXIT_TIMER(8),__LC_LAST_UPDATE_TIMER
+       mvc     __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       bo      BASED(1f)
+       la      %r14,__LC_SYNC_ENTER_TIMER
+       clc     0(8,%r14),__LC_ASYNC_ENTER_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_ASYNC_ENTER_TIMER
+0:     clc     0(8,%r14),__LC_EXIT_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_EXIT_TIMER
+0:     clc     0(8,%r14),__LC_LAST_UPDATE_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_LAST_UPDATE_TIMER
+0:     spt     0(%r14)
+       mvc     __LC_ASYNC_ENTER_TIMER(8),0(%r14)
+1:
 #endif
-0:     tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
        bno     BASED(mcck_int_main)    # no -> skip cleanup critical
        tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
        bnz     BASED(mcck_int_main)    # from user -> load async stack
@@ -691,7 +709,7 @@ mcck_int_main:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      __LC_MCCK_CODE+2,0x08   # mwp of old psw valid?
        bno     BASED(mcck_no_vtime)    # no -> skip cleanup critical
-       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(mcck_no_vtime)
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -715,6 +733,20 @@ mcck_no_vtime:
        l       %r1,BASED(.Ls390_handle_mcck)
        basr    %r14,%r1                # call machine check handler
 mcck_return:
+       mvc     __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW
+       ni      __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52
+       tm      __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
+       bno     BASED(0f)
+       lm      %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+       stpt    __LC_EXIT_TIMER
+       lpsw    __LC_RETURN_MCCK_PSW    # back to caller
+0:
+#endif
+       lm      %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+       lpsw    __LC_RETURN_MCCK_PSW    # back to caller
+
         RESTORE_ALL __LC_RETURN_MCCK_PSW,0
 
 #ifdef CONFIG_SMP
@@ -781,6 +813,8 @@ cleanup_table_sysc_leave:
        .long   sysc_leave + 0x80000000, sysc_work_loop + 0x80000000
 cleanup_table_sysc_work_loop:
        .long   sysc_work_loop + 0x80000000, sysc_reschedule + 0x80000000
+cleanup_table_io_return:
+       .long   io_return + 0x80000000, io_leave + 0x80000000
 cleanup_table_io_leave:
        .long   io_leave + 0x80000000, io_done + 0x80000000
 cleanup_table_io_work_loop:
@@ -806,6 +840,11 @@ cleanup_critical:
        bl      BASED(0f)
        clc     4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
        bl      BASED(cleanup_sysc_return)
+0:
+       clc     4(4,%r12),BASED(cleanup_table_io_return)
+       bl      BASED(0f)
+       clc     4(4,%r12),BASED(cleanup_table_io_return+4)
+       bl      BASED(cleanup_io_return)
 0:
        clc     4(4,%r12),BASED(cleanup_table_io_leave)
        bl      BASED(0f)
@@ -839,7 +878,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(16),0(%r12)
 0:     st      %r13,4(%r12)
        st      %r12,__LC_SAVE_AREA+48  # argh
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        l       %r12,__LC_SAVE_AREA+48  # argh
        st      %r15,12(%r12)
@@ -980,7 +1019,6 @@ cleanup_io_leave_insn:
                .long  cleanup_critical
 
 #define SYSCALL(esa,esame,emu) .long esa
-       .globl  sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
index 2ac095bc0e250373588ba658916d0bdc700577fc..f3222a1b286174b97ed2141f0007a98b8a5af780 100644 (file)
@@ -87,13 +87,22 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
        larl    %r13,system_call
        .endm
 
-        .macro  SAVE_ALL psworg,savearea,sync
+       .macro  SAVE_ALL_SYNC psworg,savearea
        la      %r12,\psworg
-       .if     \sync
        tm      \psworg+1,0x01          # test problem state bit
        jz      2f                      # skip stack setup save
        lg      %r15,__LC_KERNEL_STACK  # problem state -> load ksp
-       .else
+#ifdef CONFIG_CHECK_STACK
+       j       3f
+2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
+       jz      stack_overflow
+3:
+#endif
+2:
+       .endm
+
+       .macro  SAVE_ALL_ASYNC psworg,savearea
+       la      %r12,\psworg
        tm      \psworg+1,0x01          # test problem state bit
        jnz     1f                      # from user -> load kernel stack
        clc     \psworg+8(8),BASED(.Lcritical_end)
@@ -108,7 +117,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
        srag    %r14,%r14,STACK_SHIFT
        jz      2f
 1:     lg      %r15,__LC_ASYNC_STACK   # load async stack
-       .endif
 #ifdef CONFIG_CHECK_STACK
        j       3f
 2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
@@ -187,7 +195,7 @@ system_call:
        STORE_TIMER __LC_SYNC_ENTER_TIMER
 sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
-        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
         CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -446,7 +454,7 @@ pgm_check_handler:
        SAVE_ALL_BASE __LC_SAVE_AREA
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jnz     pgm_per                  # got per exception -> special case
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -485,7 +493,7 @@ pgm_per:
 # Normal per exception
 #
 pgm_per_std:
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -511,7 +519,7 @@ pgm_no_vtime2:
 # it was a single stepped SVC that is causing all the trouble
 #
 pgm_svcper:
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -539,7 +547,7 @@ io_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
-        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
+       SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
        CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -647,7 +655,7 @@ ext_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
-        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
+       SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
        CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -672,21 +680,32 @@ __critical_end:
 mcck_int_handler:
        la      %r1,4095                # revalidate r1
        spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # revalidate cpu timer
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r1)
        lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+64
        la      %r12,__LC_MCK_OLD_PSW
        tm      __LC_MCCK_CODE,0x80     # system damage?
        jo      mcck_int_main           # yes -> rest of mcck code invalid
-       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
-       jo      0f
-       spt     __LC_LAST_UPDATE_TIMER
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_SYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_EXIT_TIMER(8),__LC_LAST_UPDATE_TIMER
+       la      %r14,4095
+       mvc     __LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14)
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       jo      1f
+       la      %r14,__LC_SYNC_ENTER_TIMER
+       clc     0(8,%r14),__LC_ASYNC_ENTER_TIMER
+       jl      0f
+       la      %r14,__LC_ASYNC_ENTER_TIMER
+0:     clc     0(8,%r14),__LC_EXIT_TIMER
+       jl      0f
+       la      %r14,__LC_EXIT_TIMER
+0:     clc     0(8,%r14),__LC_LAST_UPDATE_TIMER
+       jl      0f
+       la      %r14,__LC_LAST_UPDATE_TIMER
+0:     spt     0(%r14)
+       mvc     __LC_ASYNC_ENTER_TIMER(8),0(%r14)
+1:
 #endif
-0:     tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
        jno     mcck_int_main           # no -> skip cleanup critical
        tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
        jnz     mcck_int_main           # from user -> load kernel stack
@@ -705,7 +724,7 @@ mcck_int_main:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      __LC_MCCK_CODE+2,0x08   # mwp of old psw valid?
        jno     mcck_no_vtime           # no -> no timer update
-       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        jz      mcck_no_vtime
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -727,7 +746,17 @@ mcck_no_vtime:
        jno     mcck_return
        brasl   %r14,s390_handle_mcck
 mcck_return:
-        RESTORE_ALL __LC_RETURN_MCCK_PSW,0
+       mvc     __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW
+       ni      __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
+       lmg     %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104
+       tm      __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
+       jno     0f
+       stpt    __LC_EXIT_TIMER
+0:
+#endif
+       lpswe   __LC_RETURN_MCCK_PSW    # back to caller
 
 #ifdef CONFIG_SMP
 /*
@@ -789,6 +818,8 @@ cleanup_table_sysc_leave:
        .quad   sysc_leave, sysc_work_loop
 cleanup_table_sysc_work_loop:
        .quad   sysc_work_loop, sysc_reschedule
+cleanup_table_io_return:
+       .quad   io_return, io_leave
 cleanup_table_io_leave:
        .quad   io_leave, io_done
 cleanup_table_io_work_loop:
@@ -814,6 +845,11 @@ cleanup_critical:
        jl      0f
        clc     8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
        jl      cleanup_sysc_return
+0:
+       clc     8(8,%r12),BASED(cleanup_table_io_return)
+       jl      0f
+       clc     8(8,%r12),BASED(cleanup_table_io_return+8)
+       jl      cleanup_io_return
 0:
        clc     8(8,%r12),BASED(cleanup_table_io_leave)
        jl      0f
@@ -847,7 +883,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(32),0(%r12)
 0:     stg     %r13,8(%r12)
        stg     %r12,__LC_SAVE_AREA+96  # argh
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        lg      %r12,__LC_SAVE_AREA+96  # argh
        stg     %r15,24(%r12)
@@ -957,7 +993,6 @@ cleanup_io_leave_insn:
                .quad  __critical_end
 
 #define SYSCALL(esa,esame,emu) .long esame
-       .globl  sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
@@ -965,7 +1000,6 @@ sys_call_table:
 #ifdef CONFIG_COMPAT
 
 #define SYSCALL(esa,esame,emu) .long emu
-       .globl  sys_call_table_emu
 sys_call_table_emu:
 #include "syscalls.S"
 #undef SYSCALL
index ea88d066bf04138a19bfa31fb7351b8737b2e81d..538c82da49b1b2d614f8aaa1e57b2d864fac2975 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/s390/kernel/head.S
  *
- * (C) Copyright IBM Corp. 1999, 2005
+ * Copyright (C) IBM Corp. 1999,2006
  *
  *    Author(s): Hartmut Penner <hp@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -482,24 +482,23 @@ start:
 
 .macro GET_IPL_DEVICE
 .Lget_ipl_device:
-       basr  %r12,0
-.LGID: l     %r1,0xb8                  # get sid
+       l     %r1,0xb8                  # get sid
        sll   %r1,15                    # test if subchannel is enabled
        srl   %r1,31
        ltr   %r1,%r1
-       bz    0(%r14)                   # subchannel disabled
+       bz    2f-.LPG1(%r13)            # subchannel disabled
        l     %r1,0xb8
-       la    %r5,.Lipl_schib-.LGID(%r12)
+       la    %r5,.Lipl_schib-.LPG1(%r13)
        stsch 0(%r5)                    # get schib of subchannel
-       bnz   0(%r14)                   # schib not available
+       bnz   2f-.LPG1(%r13)            # schib not available
        tm    5(%r5),0x01               # devno valid?
-       bno   0(%r14)
-       la    %r6,ipl_parameter_flags-.LGID(%r12)
+       bno   2f-.LPG1(%r13)
+       la    %r6,ipl_parameter_flags-.LPG1(%r13)
        oi    3(%r6),0x01               # set flag
-       la    %r2,ipl_devno-.LGID(%r12)
+       la    %r2,ipl_devno-.LPG1(%r13)
        mvc   0(2,%r2),6(%r5)           # store devno
        tm    4(%r5),0x80               # qdio capable device?
-       bno   0(%r14)
+       bno   2f-.LPG1(%r13)
        oi    3(%r6),0x02               # set flag
 
        # copy ipl parameters
@@ -523,7 +522,7 @@ start:
        ar    %r2,%r1
        sr    %r0,%r4
        jne   1b
-       b     0(%r14)
+       b     2f-.LPG1(%r13)
 
        .align 4
 .Lipl_schib:
@@ -537,6 +536,7 @@ ipl_parameter_flags:
        .globl ipl_devno
 ipl_devno:
        .word 0
+2:
 .endm
 
 #ifdef CONFIG_64BIT
index 2d3b089bfb83d37acbc8427889034573ed2d1213..d00de17b3778ef9fde54a971de2175922ab5b03d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/s390/kernel/head31.S
  *
- * (C) Copyright IBM Corp. 2005
+ * Copyright (C) IBM Corp. 2005,2006
  *
  *   Author(s):        Hartmut Penner <hp@de.ibm.com>
  *             Martin Schwidefsky <schwidefsky@de.ibm.com>
 # or linload or SALIPL
 #
        .org    0x10000
-startup:basr   %r13,0                   # get base
-.LPG1: l       %r1, .Lget_ipl_device_addr-.LPG1(%r13)
-       basr    %r14, %r1
+startup:basr   %r13,0                  # get base
+.LPG0: l       %r13,0f-.LPG0(%r13)
+       b       0(%r13)
+0:     .long   startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+       .org    PARMAREA
+       .long   0,0                     # IPL_DEVICE
+       .long   0,RAMDISK_ORIGIN        # INITRD_START
+       .long   0,RAMDISK_SIZE          # INITRD_SIZE
+
+       .org    COMMAND_LINE
+       .byte   "root=/dev/ram0 ro"
+       .byte   0
+
+       .org    0x11000
+
+startup_continue:
+       basr    %r13,0                  # get base
+.LPG1: GET_IPL_DEVICE
        lctl    %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-       la      %r12,_pstart-.LPG1(%r13) # pointer to parameter area
-                                        # move IPL device to lowcore
+       l       %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
+                                       # move IPL device to lowcore
        mvc     __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
 
 #
@@ -51,8 +70,8 @@ startup:basr  %r13,0                   # get base
        a       %r1,__LC_EXT_NEW_PSW+4  # set handler
        st      %r1,__LC_EXT_NEW_PSW+4
 
-       la      %r4,_pstart-.LPG1(%r13) # %r4 is our index for sccb stuff
-       la      %r1, .Lsccb-PARMAREA(%r4)       # our sccb
+       l       %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff
+       lr      %r1,%r4                 # our sccb
        .insn   rre,0xb2200000,%r2,%r1  # service call
        ipm     %r1
        srl     %r1,28                  # get cc code
@@ -63,7 +82,7 @@ startup:basr  %r13,0                   # get base
        be      .Lservicecall-.LPG1(%r13)
        lpsw    .Lwaitsclp-.LPG1(%r13)
 .Lsclph:
-       lh      %r1,.Lsccbr-PARMAREA(%r4)
+       lh      %r1,.Lsccbr-.Lsccb(%r4)
        chi     %r1,0x10                # 0x0010 is the sucess code
        je      .Lprocsccb              # let's process the sccb
        chi     %r1,0x1f0
@@ -74,7 +93,7 @@ startup:basr  %r13,0                   # get base
        b       .Lservicecall-.LPG1(%r13)
 .Lprocsccb:
        lhi     %r1,0
-       icm     %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
+       icm     %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
        jnz     .Lscnd
        lhi     %r1,0x800               # otherwise report 2GB
 .Lscnd:
@@ -84,10 +103,10 @@ startup:basr       %r13,0                   # get base
        lr      %r1,%r3
 .Lno2gb:
        xr      %r3,%r3                 # same logic
-       ic      %r3,.Lscpa1-PARMAREA(%r4)
+       ic      %r3,.Lscpa1-.Lsccb(%r4)
        chi     %r3,0x00
        jne     .Lcompmem
-       l       %r3,.Lscpa2-PARMAREA(%r13)
+       l       %r3,.Lscpa2-.Lsccb(%r4)
 .Lcompmem:
        mr      %r2,%r1                 # mem in MB on 128-bit
        l       %r1,.Lonemb-.LPG1(%r13)
@@ -95,8 +114,6 @@ startup:basr %r13,0                   # get base
        b       .Lfchunk-.LPG1(%r13)
 
        .align 4
-.Lget_ipl_device_addr:
-       .long   .Lget_ipl_device
 .Lpmask:
        .byte   0
 .align 8
@@ -242,6 +259,8 @@ startup:basr        %r13,0                   # get base
        .long   0                       # cr13: home space segment table
        .long   0xc0000000              # cr14: machine check handling off
        .long   0                       # cr15: linkage stack operations
+.Lduct:        .long   0,0,0,0,0,0,0,0
+       .long   0,0,0,0,0,0,0,0
 .Lpcmem:.long  0x00080000,0x80000000 + .Lchkmem
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
@@ -252,25 +271,9 @@ startup:basr       %r13,0                   # get base
 .Lmflags:.long machine_flags
 .Lbss_bgn:  .long __bss_start
 .Lbss_end:  .long _end
-
-       .org    PARMAREA-64
-.Lduct:        .long   0,0,0,0,0,0,0,0
-       .long   0,0,0,0,0,0,0,0
-
-#
-# params at 10400 (setup.h)
-#
-       .org    PARMAREA
-       .global _pstart
-_pstart:
-       .long   0,0                     # IPL_DEVICE
-       .long   0,RAMDISK_ORIGIN        # INITRD_START
-       .long   0,RAMDISK_SIZE          # INITRD_SIZE
-
-       .org    COMMAND_LINE
-       .byte   "root=/dev/ram0 ro"
-       .byte   0
-       .org    0x11000
+.Lparmaddr: .long PARMAREA
+.Lsccbaddr: .long .Lsccb
+       .align  4096
 .Lsccb:
        .hword  0x1000                  # length, one page
        .byte   0x00,0x00,0x00
@@ -287,18 +290,14 @@ _pstart:
 .Lscpincr2:
        .quad   0x00
        .fill   3984,1,0
-       .org    0x12000
-       .global _pend
-_pend:
-
-       GET_IPL_DEVICE
+       .align  4096
 
 #ifdef CONFIG_SHARED_KERNEL
        .org    0x100000
 #endif
 
 #
-# startup-code, running in virtual mode
+# startup-code, running in absolute addressing mode
 #
        .globl  _stext
 _stext:        basr    %r13,0                  # get base
index f08c06f45d5ceea01fcb70ab3051037af13fcf70..47744fcca930d92f3e2dad3184a64be84009d3c8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/s390/kernel/head64.S
  *
- * (C) Copyright IBM Corp. 1999,2005
+ * Copyright (C) IBM Corp. 1999,2006
  *
  *   Author(s):        Hartmut Penner <hp@de.ibm.com>
  *             Martin Schwidefsky <schwidefsky@de.ibm.com>
 # this is called either by the ipl loader or directly by PSW restart
 # or linload or SALIPL
 #
-        .org  0x10000
-startup:basr  %r13,0                     # get base
+       .org  0x10000
+startup:basr  %r13,0                    # get base
+.LPG0: l     %r13,0f-.LPG0(%r13)
+       b     0(%r13)
+0:     .long startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+       .org   PARMAREA
+       .quad  0                        # IPL_DEVICE
+       .quad  RAMDISK_ORIGIN           # INITRD_START
+       .quad  RAMDISK_SIZE             # INITRD_SIZE
+
+       .org   COMMAND_LINE
+       .byte  "root=/dev/ram0 ro"
+       .byte  0
+
+       .org   0x11000
+
+startup_continue:
+       basr  %r13,0                     # get base
 .LPG1:  sll   %r13,1                     # remove high order bit
         srl   %r13,1
-       l     %r1,.Lget_ipl_device_addr-.LPG1(%r13)
-       basr  %r14,%r1
+       GET_IPL_DEVICE
         lhi   %r1,1                      # mode 1 = esame
         slr   %r0,%r0                    # set cpuid to zero
         sigp  %r1,%r0,0x12               # switch to esame mode
        sam64                            # switch to 64 bit mode
        lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-       larl  %r12,_pstart               # pointer to parameter area
+       lg    %r12,.Lparmaddr-.LPG1(%r13)# pointer to parameter area
                                         # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
 
@@ -55,8 +74,8 @@ startup:basr  %r13,0                     # get base
        larl  %r1,.Lsclph
        stg   %r1,__LC_EXT_NEW_PSW+8    # set handler
 
-       larl  %r4,_pstart               # %r4 is our index for sccb stuff
-       la    %r1,.Lsccb-PARMAREA(%r4)  # our sccb
+       larl  %r4,.Lsccb                # %r4 is our index for sccb stuff
+       lgr   %r1,%r4                   # our sccb
        .insn rre,0xb2200000,%r2,%r1    # service call
        ipm   %r1
        srl   %r1,28                    # get cc code
@@ -67,7 +86,7 @@ startup:basr  %r13,0                     # get base
        be    .Lservicecall-.LPG1(%r13)
        lpswe .Lwaitsclp-.LPG1(%r13)
 .Lsclph:
-       lh    %r1,.Lsccbr-PARMAREA(%r4)
+       lh    %r1,.Lsccbr-.Lsccb(%r4)
        chi   %r1,0x10                  # 0x0010 is the sucess code
        je    .Lprocsccb                # let's process the sccb
        chi   %r1,0x1f0
@@ -78,15 +97,15 @@ startup:basr  %r13,0                     # get base
        b     .Lservicecall-.LPG1(%r13)
 .Lprocsccb:
        lghi  %r1,0
-       icm   %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
+       icm   %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
        jnz   .Lscnd
-       lg    %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one
+       lg    %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one
 .Lscnd:
        xr    %r3,%r3                   # same logic
-       ic    %r3,.Lscpa1-PARMAREA(%r4)
+       ic    %r3,.Lscpa1-.Lsccb(%r4)
        chi   %r3,0x00
        jne   .Lcompmem
-       l     %r3,.Lscpa2-PARMAREA(%r13)
+       l     %r3,.Lscpa2-.Lsccb(%r4)
 .Lcompmem:
        mlgr  %r2,%r1                   # mem in MB on 128-bit
        l     %r1,.Lonemb-.LPG1(%r13)
@@ -94,8 +113,6 @@ startup:basr  %r13,0                     # get base
        b     .Lfchunk-.LPG1(%r13)
 
        .align 4
-.Lget_ipl_device_addr:
-       .long .Lget_ipl_device
 .Lpmask:
        .byte 0
        .align 8
@@ -242,29 +259,16 @@ startup:basr  %r13,0                     # get base
         .quad  0                        # cr13: home space segment table
         .quad  0xc0000000               # cr14: machine check handling off
         .quad  0                        # cr15: linkage stack operations
+.Lduct: .long 0,0,0,0,0,0,0,0
+       .long 0,0,0,0,0,0,0,0
 .Lpcmsk:.quad  0x0000000180000000
 .L4malign:.quad 0xffffffffffc00000
 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
 .Lnop: .long  0x07000700
+.Lparmaddr:
+       .quad   PARMAREA
 
-       .org PARMAREA-64
-.Lduct:        .long 0,0,0,0,0,0,0,0
-       .long 0,0,0,0,0,0,0,0
-
-#
-# params at 10400 (setup.h)
-#
-       .org   PARMAREA
-       .global _pstart
-_pstart:
-       .quad  0                        # IPL_DEVICE
-        .quad  RAMDISK_ORIGIN           # INITRD_START
-        .quad  RAMDISK_SIZE             # INITRD_SIZE
-
-        .org   COMMAND_LINE
-       .byte  "root=/dev/ram0 ro"
-        .byte  0
-       .org   0x11000
+       .align 4096
 .Lsccb:
        .hword 0x1000                   # length, one page
        .byte 0x00,0x00,0x00
@@ -281,18 +285,14 @@ _pstart:
 .Lscpincr2:
        .quad 0x00
        .fill 3984,1,0
-       .org 0x12000
-       .global _pend
-_pend: 
-
-       GET_IPL_DEVICE
+       .align 4096
 
 #ifdef CONFIG_SHARED_KERNEL
        .org   0x100000
 #endif
        
 #
-# startup-code, running in virtual mode
+# startup-code, running in absolute addressing mode
 #
         .globl _stext
 _stext:        basr  %r13,0                    # get base
@@ -326,4 +326,3 @@ _stext:     basr  %r13,0                    # get base
             .align 8
 .Ldw:       .quad  0x0002000180000000,0x0000000000000000
 .Laregs:    .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
index 4176c77670c41f222f22311376fc633e48f901d1..0886e739d12269a121b3a0cdf85f02e4b3c0c7fe 100644 (file)
@@ -46,8 +46,6 @@ EXPORT_SYMBOL(__down_interruptible);
  */
 extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs);
 EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(overflowuid);
-EXPORT_SYMBOL(overflowgid);
 EXPORT_SYMBOL(empty_zero_page);
 
 /*
index b282034452a4707357dadd5b75d9be0f3bd83206..2b2551e3510b196c30fe5834b2a18a9d151e52a5 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/seq_file.h>
 #include <linux/kernel_stat.h>
 #include <linux/device.h>
+#include <linux/notifier.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -115,6 +116,7 @@ void __devinit cpu_init (void)
  */
 char vmhalt_cmd[128] = "";
 char vmpoff_cmd[128] = "";
+char vmpanic_cmd[128] = "";
 
 static inline void strncpy_skip_quote(char *dst, char *src, int n)
 {
@@ -146,6 +148,38 @@ static int __init vmpoff_setup(char *str)
 
 __setup("vmpoff=", vmpoff_setup);
 
+static int vmpanic_notify(struct notifier_block *self, unsigned long event,
+                         void *data)
+{
+       if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
+               cpcmd(vmpanic_cmd, NULL, 0, NULL);
+
+       return NOTIFY_OK;
+}
+
+#define PANIC_PRI_VMPANIC      0
+
+static struct notifier_block vmpanic_nb = {
+       .notifier_call = vmpanic_notify,
+       .priority = PANIC_PRI_VMPANIC
+};
+
+static int __init vmpanic_setup(char *str)
+{
+       static int register_done __initdata = 0;
+
+       strncpy_skip_quote(vmpanic_cmd, str, 127);
+       vmpanic_cmd[127] = 0;
+       if (!register_done) {
+               register_done = 1;
+               atomic_notifier_chain_register(&panic_notifier_list,
+                                              &vmpanic_nb);
+       }
+       return 1;
+}
+
+__setup("vmpanic=", vmpanic_setup);
+
 /*
  * condev= and conmode= setup parameter.
  */
@@ -289,19 +323,34 @@ void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 
 void machine_restart(char *command)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_restart(command);
 }
 
 void machine_halt(void)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_halt();
 }
 
 void machine_power_off(void)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_power_off();
 }
 
index 343120c9223d798d6cad38703153df30f83e683b..8e03219eea76051f23d5f97edf5f61cab622ba38 100644 (file)
@@ -869,7 +869,7 @@ static int __init topology_init(void)
        int ret;
 
        for_each_possible_cpu(cpu) {
-               ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL);
+               ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu);
                if (ret)
                        printk(KERN_WARNING "topology_init: register_cpu %d "
                               "failed (%d)\n", cpu, ret);
index a46793beeddda592d70797ed79fc4c462477f1d6..b7630436f693cda60aa7976b8c3a9b43212ab327 100644 (file)
@@ -150,13 +150,11 @@ void show_stack(struct task_struct *task, unsigned long *sp)
        unsigned long *stack;
        int i;
 
-       // debugging aid: "show_stack(NULL);" prints the
-       // back trace for this cpu.
-
        if (!sp)
-               sp = task ? (unsigned long *) task->thread.ksp : __r15;
+               stack = task ? (unsigned long *) task->thread.ksp : __r15;
+       else
+               stack = sp;
 
-       stack = sp;
        for (i = 0; i < kstack_depth_to_print; i++) {
                if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
                        break;
index c0973f8d57bae3c6060a9f4e67ddf9a11adfef21..357fab1bac2ba518eebfc968260b2cd259ec8798 100644 (file)
@@ -102,6 +102,6 @@ static void end_maskreg_irq(unsigned int irq)
 void make_maskreg_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &maskreg_irq_type;
+       irq_desc[irq].chip = &maskreg_irq_type;
        disable_maskreg_irq(irq);
 }
index 6ddbcc77244da4d81653baa2c6bb2a6bb838debd..1d32425782c00cec5fb8ee72875202d2cd667268 100644 (file)
@@ -253,7 +253,7 @@ static void make_bigsur_l1isr(unsigned int irq) {
         /* sanity check first */
         if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
                 /* save the handler in the main description table */
-                irq_desc[irq].handler = &bigsur_l1irq_type;
+                irq_desc[irq].chip = &bigsur_l1irq_type;
                 irq_desc[irq].status = IRQ_DISABLED;
                 irq_desc[irq].action = 0;
                 irq_desc[irq].depth = 1;
@@ -270,7 +270,7 @@ static void make_bigsur_l2isr(unsigned int irq) {
         /* sanity check first */
         if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
                 /* save the handler in the main description table */
-                irq_desc[irq].handler = &bigsur_l2irq_type;
+                irq_desc[irq].chip = &bigsur_l2irq_type;
                 irq_desc[irq].status = IRQ_DISABLED;
                 irq_desc[irq].action = 0;
                 irq_desc[irq].depth = 1;
index d1da0d844567f66156bff7632a4c73012e466fbe..2955adc52310a8afedaa0fe868165d1d7c467403 100644 (file)
@@ -103,7 +103,7 @@ void __init init_cqreek_IRQ(void)
                cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT;
                cqreek_irq_data[14].bit = 1;
 
-               irq_desc[14].handler = &cqreek_irq_type;
+               irq_desc[14].chip = &cqreek_irq_type;
                irq_desc[14].status = IRQ_DISABLED;
                irq_desc[14].action = 0;
                irq_desc[14].depth = 1;
@@ -117,7 +117,7 @@ void __init init_cqreek_IRQ(void)
                cqreek_irq_data[10].bit = (1 << 10);
 
                /* XXX: Err... we may need demultiplexer for ISA irq... */
-               irq_desc[10].handler = &cqreek_irq_type;
+               irq_desc[10].chip = &cqreek_irq_type;
                irq_desc[10].status = IRQ_DISABLED;
                irq_desc[10].action = 0;
                irq_desc[10].depth = 1;
index 55dece35cde5c3be7c687a0eeab5ced10508ba06..0027b80a23435cfd005e45f255ddd62fd5801a52 100644 (file)
@@ -70,7 +70,7 @@ int __init platform_setup(void)
 
        /* Assign all virtual IRQs to the System ASIC int. handler */
        for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
-               irq_desc[i].handler = &systemasic_int;
+               irq_desc[i].chip = &systemasic_int;
 
        board_time_init = aica_time_init;
 
index 5130ba2b6ff1aeb95f2631f496a3a72c25d9e1e3..4b3ef16a0e960dc11d207966454e902dfc3e42c2 100644 (file)
@@ -63,7 +63,7 @@ int __init platform_setup(void)
                str[i] = ctrl_readb(EC3104_BASE + i);
 
        for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
-               irq_desc[i].handler = &ec3104_int;
+               irq_desc[i].chip = &ec3104_int;
 
        printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
               str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
index 52d0ba39031b7215a1a9c62dc3af49461c6f817f..701fa55d52978b25cc0f0067700e9fe49e1bdce8 100644 (file)
@@ -114,7 +114,7 @@ static void enable_harp_irq(unsigned int irq)
 static void __init make_harp_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &harp_irq_type;
+       irq_desc[irq].chip = &harp_irq_type;
        disable_harp_irq(irq);
 }
 
index ba3a6543975227fb6a40c3a6f93f18c3989a884c..9f7ccd33ffb603d76e8262af032ca93e87b03911 100644 (file)
@@ -273,9 +273,9 @@ void __init pcibios_fixup_irqs(void)
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO) {
                if (start >= 0x10000UL) {
index 2bb581b916834749a71c0ff0c0e66996b51372e5..b72f009c52c26cee58fe5317adb246e83b1ac23d 100644 (file)
@@ -194,7 +194,7 @@ static struct hw_interrupt_type mpc1211_irq_type = {
 
 static void make_mpc1211_irq(unsigned int irq)
 {
-       irq_desc[irq].handler = &mpc1211_irq_type;
+       irq_desc[irq].chip = &mpc1211_irq_type;
        irq_desc[irq].status  = IRQ_DISABLED;
        irq_desc[irq].action  = 0;
        irq_desc[irq].depth   = 1;
index 276fa11ee4ce0c4ad581415c146217a825d68141..b055809d2ac1a4459befa360b5d20d4e632db8f1 100644 (file)
@@ -536,7 +536,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size)
+                           resource_size_t size)
 {
 }
 
index 715e8feb3a68783cc8d1b4375beb632db0f21a7d..2c13a7de6b22ada84a822b199b84cad8af6a4b7b 100644 (file)
@@ -150,7 +150,7 @@ static void enable_od_irq(unsigned int irq)
 static void __init make_od_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &od_irq_type;
+       irq_desc[irq].chip = &od_irq_type;
        disable_od_irq(irq);
 }
 
index ed4c5b50ea45edc29cb77c57f0731dfeda251f47..52a98b524e1fe6263522db00488974dd079046a2 100644 (file)
@@ -86,7 +86,7 @@ static struct hw_interrupt_type hs7751rvoip_irq_type = {
 static void make_hs7751rvoip_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &hs7751rvoip_irq_type;
+       irq_desc[irq].chip = &hs7751rvoip_irq_type;
        disable_hs7751rvoip_irq(irq);
 }
 
index d36c9374aed1dffc9daf9980a5a8439f3da2dd00..e16915d9cda440a3b6e754c6f90e0075eb608cf1 100644 (file)
@@ -100,7 +100,7 @@ static struct hw_interrupt_type rts7751r2d_irq_type = {
 static void make_rts7751r2d_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &rts7751r2d_irq_type;
+       irq_desc[irq].chip = &rts7751r2d_irq_type;
        disable_rts7751r2d_irq(irq);
 }
 
index 7a2eb10edb563c4b108b35204528b536aa1d6e45..845979181059e708cf68d9d902e9b626a1bc1a27 100644 (file)
@@ -105,7 +105,7 @@ static void end_systemh_irq(unsigned int irq)
 void make_systemh_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &systemh_irq_type;
+       irq_desc[irq].chip = &systemh_irq_type;
        disable_systemh_irq(irq);
 }
 
index 70f04caad9a414a1897eab2c585700bd9e8384fa..402735c7c89831cec484953cac01a8d3d5f8bb12 100644 (file)
@@ -85,7 +85,7 @@ void
 make_intreq_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &intreq_irq_type;
+       irq_desc[irq].chip = &intreq_irq_type;
        disable_intreq_irq(irq);
 }
 
index efcbd86b7cd2ff0c546671aaa318916f3ba15def..cb5999425d163641619ce4b403d10675c40e1b9a 100644 (file)
@@ -147,7 +147,7 @@ static void enable_microdev_irq(unsigned int irq)
 static void __init make_microdev_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &microdev_irq_type;
+       irq_desc[irq].chip = &microdev_irq_type;
        disable_microdev_irq(irq);
 }
 
index f014b9bf69224003bdbbb05ff62cfc0540e70e40..724db04cb3929acf6c53ae8ff343a5964045c10c 100644 (file)
@@ -154,7 +154,7 @@ int __init setup_hd64461(void)
        outw(0xffff, HD64461_NIMR);
 
        for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) {
-               irq_desc[i].handler = &hd64461_irq_type;
+               irq_desc[i].chip = &hd64461_irq_type;
        }
 
        setup_irq(CONFIG_HD64461_IRQ, &irq0);
index 68e4c4e4283dc6341b6cc20d63f8244c2766cb04..cf9142c620b7fbc7b30916dab36e02482fc2b10a 100644 (file)
@@ -182,7 +182,7 @@ static int __init setup_hd64465(void)
        outw(0xffff, HD64465_REG_NIMR);         /* mask all interrupts */
 
        for (i = 0; i < HD64465_IRQ_NUM ; i++) {
-               irq_desc[HD64465_IRQ_BASE + i].handler = &hd64465_irq_type;
+               irq_desc[HD64465_IRQ_BASE + i].chip = &hd64465_irq_type;
        }
 
        setup_irq(CONFIG_HD64465_IRQ, &irq0);
index 2ee330b3c38f68e5b2b3113ab1ffd56aaf54427e..892214bade194edf67e0387b435ef04b3c792e50 100644 (file)
@@ -191,7 +191,7 @@ void __init setup_voyagergx_irq(void)
                        flag = 1;
                }
                if (flag == 1)
-                       irq_desc[VOYAGER_IRQ_BASE + i].handler = &voyagergx_irq_type;
+                       irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
        }
 
        setup_irq(IRQ_VOYAGER, &irq0);
index c1669905abe4d8e632fe823d48b0d0d5420aba27..3d546ba329cfb866a9457751f6ab888523b867cd 100644 (file)
@@ -75,7 +75,7 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
                            __attribute__ ((weak));
 
 /*
@@ -85,10 +85,10 @@ void pcibios_align_resource(void *data, struct resource *res,
  * modulo 0x400.
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index baed9a550d39d9aff4223992b9db6d48b0eb4c5e..a33ae3e0a5a5dc808f72c425d69afca96d4ed531 100644 (file)
@@ -105,6 +105,6 @@ static void shutdown_imask_irq(unsigned int irq)
 void make_imask_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &imask_irq_type;
+       irq_desc[irq].chip = &imask_irq_type;
        enable_irq(irq);
 }
index 06e8afab32e438f75f49c83385229c6f9776a43d..30064bf6e154bf5f46a2f5c0cfea97bf50c616d4 100644 (file)
@@ -137,7 +137,7 @@ void make_intc2_irq(unsigned int irq,
 
        local_irq_restore(flags);
 
-       irq_desc[irq].handler = &intc2_irq_type;
+       irq_desc[irq].chip = &intc2_irq_type;
 
        disable_intc2_irq(irq);
 }
index e55150ed085619d5962e039e1ebb2a4fdc2e9b15..0373b65c77f9c452b9f9d60cb5ad9bf0cf2862be 100644 (file)
@@ -115,7 +115,7 @@ void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority)
        ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */
        ipr_data[irq].priority = priority;
 
-       irq_desc[irq].handler = &ipr_irq_type;
+       irq_desc[irq].chip = &ipr_irq_type;
        disable_ipr_irq(irq);
 }
 
index 95d6024fe1ae8b0c218ffd665b7b09d1abe05673..714963a25bbaaa7767ff86ad66adc6791724dcd4 100644 (file)
@@ -85,7 +85,7 @@ static void end_pint_irq(unsigned int irq)
 void make_pint_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &pint_irq_type;
+       irq_desc[irq].chip = &pint_irq_type;
        disable_pint_irq(irq);
 }
 
index b56e79632f241aaa28fb91935ef3dace2c69924c..c2e07f7f3496a45efa79b87be2cc953b2ebd49e0 100644 (file)
@@ -47,7 +47,7 @@ int show_interrupts(struct seq_file *p, void *v)
                        goto unlock;
                seq_printf(p, "%3d: ",i);
                seq_printf(p, "%10u ", kstat_irqs(i));
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index bb229ef030f3cbf70c5afa777cd50e194fed6025..9af22116c9a2b3a78e02c8533e59660769d95723 100644 (file)
@@ -402,7 +402,7 @@ static int __init topology_init(void)
        int cpu_id;
 
        for_each_possible_cpu(cpu_id)
-               register_cpu(&cpu[cpu_id], cpu_id, NULL);
+               register_cpu(&cpu[cpu_id], cpu_id);
 
        return 0;
 }
index d69879c0e063dc7ed39f890fd5020345f830a268..675776a5477e04d5e72dfcda1c02f42d61878d00 100644 (file)
@@ -65,7 +65,7 @@ int show_interrupts(struct seq_file *p, void *v)
                        goto unlock;
                seq_printf(p, "%3d: ",i);
                seq_printf(p, "%10u ", kstat_irqs(i));
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index fc99bf4e362c9dfca4dada4ff45263baa3f46a08..fa730f5fe2e6e6729ab1b9a2b19ae4c7556ecfc9 100644 (file)
@@ -178,7 +178,7 @@ static void end_intc_irq(unsigned int irq)
 void make_intc_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &intc_irq_type;
+       irq_desc[irq].chip = &intc_irq_type;
        disable_intc_irq(irq);
 }
 
@@ -208,7 +208,7 @@ void __init init_IRQ(void)
        /* Set default: per-line enable/disable, priority driven ack/eoi */
        for (i = 0; i < NR_INTC_IRQS; i++) {
                if (platform_int_priority[i] != NO_PRIORITY) {
-                       irq_desc[i].handler = &intc_irq_type;
+                       irq_desc[i].chip = &intc_irq_type;
                }
        }
 
index 50c61dcb9faee7b79bcdc071ef79634d13bbda8e..945920bc24db62421f0948ada2ab91125644b96c 100644 (file)
@@ -69,10 +69,10 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
  * modulo 0x400.
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index d2711c9c9d13954dbadaecdf0665e7b3d06cdbe1..da98d8dbcf95324284de3d601e2364cc1923c896 100644 (file)
@@ -309,7 +309,7 @@ static struct cpu cpu[1];
 
 static int __init topology_init(void)
 {
-       return register_cpu(cpu, 0, NULL);
+       return register_cpu(cpu, 0);
 }
 
 subsys_initcall(topology_init);
index f797c84bfdd1e9dae8c26211d9ca2024e9297861..05eb7cdc26f0557921231486893d869338974eef 100644 (file)
@@ -187,7 +187,7 @@ void init_cayman_irq(void)
        }
 
        for (i=0; i<NR_EXT_IRQS; i++) {
-               irq_desc[START_EXT_IRQS + i].handler = &cayman_irq_type;
+               irq_desc[START_EXT_IRQS + i].chip = &cayman_irq_type;
        }
 
        /* Setup the SMSC interrupt */
index ae4c667c906f5caf0ef2d049bc5b35382330be03..79d177149fdb351825c750559a05a0f4b92b4094 100644 (file)
@@ -208,7 +208,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz)
        pa &= PAGE_MASK;
        sparc_mapiorange(bus, pa, res->start, res->end - res->start + 1);
 
-       return (void __iomem *) (res->start + offset);
+       return (void __iomem *)(unsigned long)(res->start + offset);
 }
 
 /*
@@ -325,7 +325,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
                res->name = sdev->prom_name;
        }
 
-       return (void *)res->start;
+       return (void *)(unsigned long)res->start;
 
 err_noiommu:
        release_resource(res);
@@ -819,7 +819,9 @@ _sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof,
                if (p + 32 >= e)        /* Better than nothing */
                        break;
                if ((nm = r->name) == 0) nm = "???";
-               p += sprintf(p, "%08lx-%08lx: %s\n", r->start, r->end, nm);
+               p += sprintf(p, "%016llx-%016llx: %s\n",
+                               (unsigned long long)r->start,
+                               (unsigned long long)r->end, nm);
        }
 
        return p-buf;
index bcfdddd0418aeda77ab17a87c46e8df5f16287d8..5df3ebdc0ab180b3cbffdfa5a3d9cdbebf33439b 100644 (file)
@@ -860,7 +860,7 @@ char * __init pcibios_setup(char *str)
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
 }
 
index a893a9cc953473a335668569407c0b8d7a35ccf1..2e5d08ce217b28104dc9e8ce9d49bec867ed5d9d 100644 (file)
@@ -496,7 +496,7 @@ static int __init topology_init(void)
                if (!p)
                        err = -ENOMEM;
                else
-                       register_cpu(p, i, NULL);
+                       register_cpu(p, i);
        }
 
        return err;
index cc89b06d01785a73ca974202da67f6852f52e9da..ab9e640df22820a5ffd9084b73258ea09042c41e 100644 (file)
@@ -151,7 +151,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %9s", irq_desc[i].handler->typename);
+               seq_printf(p, " %9s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -224,7 +224,7 @@ static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq)
 #ifdef CONFIG_SMP
 static int irq_choose_cpu(unsigned int virt_irq)
 {
-       cpumask_t mask = irq_affinity[virt_irq];
+       cpumask_t mask = irq_desc[virt_irq].affinity;
        int cpuid;
 
        if (cpus_equal(mask, CPU_MASK_ALL)) {
@@ -414,8 +414,8 @@ void irq_install_pre_handler(int virt_irq,
        data->pre_handler_arg1 = arg1;
        data->pre_handler_arg2 = arg2;
 
-       desc->handler = (desc->handler == &sun4u_irq ?
-                        &sun4u_irq_ack : &sun4v_irq_ack);
+       desc->chip = (desc->chip == &sun4u_irq ?
+                     &sun4u_irq_ack : &sun4v_irq_ack);
 }
 
 unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
@@ -431,7 +431,7 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
        bucket = &ivector_table[ino];
        if (!bucket->virt_irq) {
                bucket->virt_irq = virt_irq_alloc(__irq(bucket));
-               irq_desc[bucket->virt_irq].handler = &sun4u_irq;
+               irq_desc[bucket->virt_irq].chip = &sun4u_irq;
        }
 
        desc = irq_desc + bucket->virt_irq;
@@ -465,7 +465,7 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
        bucket = &ivector_table[sysino];
        if (!bucket->virt_irq) {
                bucket->virt_irq = virt_irq_alloc(__irq(bucket));
-               irq_desc[bucket->virt_irq].handler = &sun4v_irq;
+               irq_desc[bucket->virt_irq].chip = &sun4v_irq;
        }
 
        desc = irq_desc + bucket->virt_irq;
index 6c9e3e94abaa74a68fb06f05f9ba857c0721661f..20ca9ec8fd3bbef18c844490c4f8f553c9a23116 100644 (file)
@@ -357,7 +357,7 @@ void pcibios_update_irq(struct pci_dev *pdev, int irq)
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
 }
 
index a6a7d8168346c6b50b9910727ccd344f9566b5f1..116d9632002defd035dfdae91f0d80767d75d3b6 100644 (file)
@@ -537,7 +537,7 @@ static int __init topology_init(void)
        for_each_possible_cpu(i) {
                struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
                if (p) {
-                       register_cpu(p, i, NULL);
+                       register_cpu(p, i);
                        err = 0;
                }
        }
index 5c2bcf354ce64aa3d74ad75dbc7a7eb0ba0091bd..cb75a27adb517bba8b2d43289b0cb8e1a64ef81d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/initrd.h>
 #include <linux/swap.h>
 #include <linux/pagemap.h>
+#include <linux/poison.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/kprobes.h>
@@ -1520,7 +1521,7 @@ void free_initmem(void)
                page = (addr +
                        ((unsigned long) __va(kern_base)) -
                        ((unsigned long) KERNBASE));
-               memset((void *)addr, 0xcc, PAGE_SIZE);
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                p = virt_to_page(page);
 
                ClearPageReserved(p);
index 2ffda012385e9e5f9f3f15be42389f42c3e1164c..fae43a3054a0bec3c00782e70e66926186a28e8c 100644 (file)
@@ -63,7 +63,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -451,13 +451,13 @@ void __init init_IRQ(void)
        irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
        irq_desc[TIMER_IRQ].action = NULL;
        irq_desc[TIMER_IRQ].depth = 1;
-       irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
+       irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type;
        enable_irq(TIMER_IRQ);
        for (i = 1; i < NR_IRQS; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &normal_irq_type;
+               irq_desc[i].chip = &normal_irq_type;
                enable_irq(i);
        }
 }
index 7a151c26f82e2bd7be47a0053deb18bf84f0004d..858c45819aabe496dd663eb27195ea3d835b4f1c 100644 (file)
@@ -65,10 +65,10 @@ int show_interrupts(struct seq_file *p, void *v)
                        int j;
                        int count = 0;
                        int num = -1;
-                       const char *type_name = irq_desc[irq].handler->typename;
+                       const char *type_name = irq_desc[irq].chip->typename;
 
                        for (j = 0; j < NR_IRQS; j++)
-                               if (irq_desc[j].handler->typename == type_name){
+                               if (irq_desc[j].chip->typename == type_name){
                                        if (irq == j)
                                                num = count;
                                        count++;
@@ -117,7 +117,7 @@ init_irq_handlers (int base_irq, int num, int interval,
                irq_desc[base_irq].status  = IRQ_DISABLED;
                irq_desc[base_irq].action  = NULL;
                irq_desc[base_irq].depth   = 1;
-               irq_desc[base_irq].handler = irq_type;
+               irq_desc[base_irq].chip = irq_type;
                base_irq += interval;
        }
 }
index ffbb6d073bf2b39e9f24814662d6a6129a132171..3a7c5c9c3ac66f5fd248c81d823e582dadcce1e9 100644 (file)
@@ -329,7 +329,7 @@ void pcibios_fixup_bus(struct pci_bus *b)
 
 void
 pcibios_align_resource (void *data, struct resource *res,
-                       unsigned long size, unsigned long align)
+                       resource_size_t size, resource_size_t align)
 {
 }
 
index ccc4a7fb97a370f8d56baf16e4eb1439a17621d3..91039844820ce5b29f516e427f569a48b7d632b0 100644 (file)
@@ -370,6 +370,8 @@ config HOTPLUG_CPU
                can be controlled through /sys/devices/system/cpu/cpu#.
                Say N if you want to disable CPU hotplug.
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
 
 config HPET_TIMER
        bool
index 7290e72b9a34d2a56be1a90e3c96989d9df1d844..22cac4487b57fd1e9aef98769071a8e4f02f0d81 100644 (file)
@@ -588,7 +588,7 @@ END(common_interrupt)
  */            
        .macro apicinterrupt num,func
        INTR_FRAME
-       pushq $\num-256
+       pushq $~(\num)
        CFI_ADJUST_CFA_OFFSET 8
        interrupt \func
        jmp ret_from_intr
index 86b2c1e197aa3f6b1b86c7537aa7d42c6959bcc8..3dd1659427dc3a78f6c09c3e2827d36278f2b1e7 100644 (file)
@@ -235,7 +235,7 @@ void make_8259A_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
        io_apic_irqs &= ~(1<<irq);
-       irq_desc[irq].handler = &i8259A_irq_type;
+       irq_desc[irq].chip = &i8259A_irq_type;
        enable_irq(irq);
 }
 
@@ -468,12 +468,12 @@ void __init init_ISA_irqs (void)
                        /*
                         * 16 old-style INTA-cycle interrupts:
                         */
-                       irq_desc[i].handler = &i8259A_irq_type;
+                       irq_desc[i].chip = &i8259A_irq_type;
                } else {
                        /*
                         * 'high' PCI IRQs filled in on demand
                         */
-                       irq_desc[i].handler = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_type;
                }
        }
 }
index c768d8a036d0c7998e802944f4cc0103e4ec0dbc..401b687fef21b2f4736c6a79d3f51b1fa1ac99b8 100644 (file)
@@ -876,15 +876,17 @@ static struct hw_interrupt_type ioapic_edge_type;
 #define IOAPIC_EDGE    0
 #define IOAPIC_LEVEL   1
 
-static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
+static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-       unsigned idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+       unsigned idx;
+
+       idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
                        trigger == IOAPIC_LEVEL)
-               irq_desc[idx].handler = &ioapic_level_type;
+               irq_desc[idx].chip = &ioapic_level_type;
        else
-               irq_desc[idx].handler = &ioapic_edge_type;
+               irq_desc[idx].chip = &ioapic_edge_type;
        set_intr_gate(vector, interrupt[idx]);
 }
 
@@ -986,7 +988,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
         * The timer IRQ doesn't have to know that behind the
         * scene we have a 8259A-master in AEOI mode ...
         */
-       irq_desc[0].handler = &ioapic_edge_type;
+       irq_desc[0].chip = &ioapic_edge_type;
 
        /*
         * Add it to the IO-APIC irq-routing table:
@@ -1616,6 +1618,13 @@ static void set_ioapic_affinity_vector (unsigned int vector,
 #endif // CONFIG_SMP
 #endif // CONFIG_PCI_MSI
 
+static int ioapic_retrigger(unsigned int irq)
+{
+       send_IPI_self(IO_APIC_VECTOR(irq));
+
+       return 1;
+}
+
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
  * so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -1636,6 +1645,7 @@ static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static struct hw_interrupt_type ioapic_level_type __read_mostly = {
@@ -1649,6 +1659,7 @@ static struct hw_interrupt_type ioapic_level_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -1683,7 +1694,7 @@ static inline void init_IO_APIC_traps(void)
                                make_8259A_irq(irq);
                        else
                                /* Strange. Oh, well.. */
-                               irq_desc[irq].handler = &no_irq_type;
+                               irq_desc[irq].chip = &no_irq_type;
                }
        }
 }
@@ -1900,7 +1911,7 @@ static inline void check_timer(void)
        apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
        disable_8259A_irq(0);
-       irq_desc[0].handler = &lapic_irq_type;
+       irq_desc[0].chip = &lapic_irq_type;
        apic_write(APIC_LVT0, APIC_DM_FIXED | vector);  /* Fixed mode */
        enable_8259A_irq(0);
 
index 59518d4d43589a9b99724ecefbd6b6162b43ac28..a1f1df5f7bfc2d5a40d6269e5a37f69d6dc746af 100644 (file)
@@ -79,7 +79,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
 
                seq_printf(p, "  %s", action->name);
                for (action=action->next; action; action = action->next)
@@ -115,8 +115,14 @@ skip:
  */
 asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
 {      
-       /* high bits used in ret_from_ code  */
-       unsigned irq = regs->orig_rax & 0xff;
+       /* high bit used in ret_from_ code  */
+       unsigned irq = ~regs->orig_rax;
+
+       if (unlikely(irq >= NR_IRQS)) {
+               printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+                                       __FUNCTION__, irq);
+               BUG();
+       }
 
        exit_idle();
        irq_enter();
@@ -140,13 +146,13 @@ void fixup_irqs(cpumask_t map)
                if (irq == 2)
                        continue;
 
-               cpus_and(mask, irq_affinity[irq], map);
+               cpus_and(mask, irq_desc[irq].affinity, map);
                if (any_online_cpu(mask) == NR_CPUS) {
                        printk("Breaking affinity for irq %i\n", irq);
                        mask = map;
                }
-               if (irq_desc[irq].handler->set_affinity)
-                       irq_desc[irq].handler->set_affinity(irq, mask);
+               if (irq_desc[irq].chip->set_affinity)
+                       irq_desc[irq].chip->set_affinity(irq, mask);
                else if (irq_desc[irq].action && !(warned++))
                        printk("Cannot set affinity for irq %i\n", irq);
        }
index acd5816b1a6f214d2dfc5253d674ed9d81492fe5..88845674c661a39feefc5b35bb5c5dd9b2255be8 100644 (file)
@@ -629,7 +629,7 @@ static __cpuinit void mce_remove_device(unsigned int cpu)
 #endif
 
 /* Get notified when a cpu comes on/off. Be hotplug friendly. */
-static int
+static __cpuinit int
 mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -647,7 +647,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-static struct notifier_block mce_cpu_notifier = {
+static struct notifier_block __cpuinitdata mce_cpu_notifier = {
        .notifier_call = mce_cpu_callback,
 };
 
index 399489c93132c2b9c3d6954b9b2d7149ad084f63..0ef9cf2bc45e4ea809e3a76fb2c4f61dc4a3c7b4 100644 (file)
@@ -607,11 +607,13 @@ void set_nmi_callback(nmi_callback_t callback)
        vmalloc_sync_all();
        rcu_assign_pointer(nmi_callback, callback);
 }
+EXPORT_SYMBOL_GPL(set_nmi_callback);
 
 void unset_nmi_callback(void)
 {
        nmi_callback = dummy_nmi_callback;
 }
+EXPORT_SYMBOL_GPL(unset_nmi_callback);
 
 #ifdef CONFIG_SYSCTL
 
index acee4bc3f6fa945799d194b17cfbf4cac20285e6..5a1c0a3bf87262c027c327773628e93e58194188 100644 (file)
@@ -135,10 +135,10 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs)
 
        cpu = smp_processor_id();
        /*
-        * orig_rax contains the interrupt vector - 256.
+        * orig_rax contains the negated interrupt vector.
         * Use that to determine where the sender put the data.
         */
-       sender = regs->orig_rax + 256 - INVALIDATE_TLB_VECTOR_START;
+       sender = ~regs->orig_rax - INVALIDATE_TLB_VECTOR_START;
        f = &per_cpu(flush_state, sender);
 
        if (!cpu_isset(cpu, f->flush_cpumask))
index 4e9755179ecf57022bcb8e4e6adaa76d62612010..540c0ccbcccc8953c95ee6b6c2baf5ad11e44aaf 100644 (file)
@@ -455,10 +455,12 @@ cpumask_t cpu_coregroup_map(int cpu)
        struct cpuinfo_x86 *c = cpu_data + cpu;
        /*
         * For perf, we return last level cache shared map.
-        * TBD: when power saving sched policy is added, we will return
-        *      cpu_core_map when power saving policy is enabled
+        * And for power savings, we return cpu_core_map
         */
-       return c->llc_shared_map;
+       if (sched_mc_power_savings || sched_smt_power_savings)
+               return cpu_core_map[cpu];
+       else
+               return c->llc_shared_map;
 }
 
 /* representing cpus for which sibling maps can be computed */
index 02add1d1dfa88aa0843b0fffc245399fd5e4adbf..95bd232ff0cf3d37fc3b5838e0b477666115aebb 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/bootmem.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
+#include <linux/poison.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/memory_hotplug.h>
@@ -506,8 +507,6 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size)
 /*
  * Memory hotplug specific functions
  */
-#if defined(CONFIG_ACPI_HOTPLUG_MEMORY) || defined(CONFIG_ACPI_HOTPLUG_MEMORY_MODULE)
-
 void online_page(struct page *page)
 {
        ClearPageReserved(page);
@@ -517,31 +516,17 @@ void online_page(struct page *page)
        num_physpages++;
 }
 
-#ifndef CONFIG_MEMORY_HOTPLUG
+#ifdef CONFIG_MEMORY_HOTPLUG
 /*
- * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance,
- * just online the pages.
+ * XXX: memory_add_physaddr_to_nid() is to find node id from physical address
+ *     via probe interface of sysfs. If acpi notifies hot-add event, then it
+ *     can tell node id by searching dsdt. But, probe interface doesn't have
+ *     node id. So, return 0 as node id at this time.
  */
-int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages)
+#ifdef CONFIG_NUMA
+int memory_add_physaddr_to_nid(u64 start)
 {
-       int err = -EIO;
-       unsigned long pfn;
-       unsigned long total = 0, mem = 0;
-       for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) {
-               if (pfn_valid(pfn)) {
-                       online_page(pfn_to_page(pfn));
-                       err = 0;
-                       mem++;
-               }
-               total++;
-       }
-       if (!err) {
-               z->spanned_pages += total;
-               z->present_pages += mem;
-               z->zone_pgdat->node_spanned_pages += total;
-               z->zone_pgdat->node_present_pages += mem;
-       }
-       return err;
+       return 0;
 }
 #endif
 
@@ -549,9 +534,9 @@ int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages)
  * Memory is added always to NORMAL zone. This means you will never get
  * additional DMA/DMA32 memory.
  */
-int add_memory(u64 start, u64 size)
+int arch_add_memory(int nid, u64 start, u64 size)
 {
-       struct pglist_data *pgdat = NODE_DATA(0);
+       struct pglist_data *pgdat = NODE_DATA(nid);
        struct zone *zone = pgdat->node_zones + MAX_NR_ZONES-2;
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
@@ -568,7 +553,7 @@ error:
        printk("%s: Problem encountered in __add_pages!\n", __func__);
        return ret;
 }
-EXPORT_SYMBOL_GPL(add_memory);
+EXPORT_SYMBOL_GPL(arch_add_memory);
 
 int remove_memory(u64 start, u64 size)
 {
@@ -576,7 +561,33 @@ int remove_memory(u64 start, u64 size)
 }
 EXPORT_SYMBOL_GPL(remove_memory);
 
-#endif
+#else /* CONFIG_MEMORY_HOTPLUG */
+/*
+ * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance,
+ * just online the pages.
+ */
+int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages)
+{
+       int err = -EIO;
+       unsigned long pfn;
+       unsigned long total = 0, mem = 0;
+       for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) {
+               if (pfn_valid(pfn)) {
+                       online_page(pfn_to_page(pfn));
+                       err = 0;
+                       mem++;
+               }
+               total++;
+       }
+       if (!err) {
+               z->spanned_pages += total;
+               z->present_pages += mem;
+               z->zone_pgdat->node_spanned_pages += total;
+               z->zone_pgdat->node_present_pages += mem;
+       }
+       return err;
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
 
 static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
                         kcore_vsyscall;
@@ -650,7 +661,8 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
        for (addr = begin; addr < end; addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
                init_page_count(virt_to_page(addr));
-               memset((void *)(addr & ~(PAGE_SIZE-1)), 0xcc, PAGE_SIZE); 
+               memset((void *)(addr & ~(PAGE_SIZE-1)),
+                       POISON_FREE_INITMEM, PAGE_SIZE);
                free_page(addr);
                totalram_pages++;
        }
@@ -658,7 +670,8 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
 
 void free_initmem(void)
 {
-       memset(__initdata_begin, 0xba, __initdata_end - __initdata_begin);
+       memset(__initdata_begin, POISON_FREE_INITDATA,
+               __initdata_end - __initdata_begin);
        free_init_pages("unused kernel memory",
                        (unsigned long)(&__init_begin),
                        (unsigned long)(&__init_end));
index 51f9bed455fab0c0576933a7702efb0d51cb84f4..1cf744ee0959e2515d5c47ebcbaffb9e6ac9fba3 100644 (file)
@@ -100,7 +100,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -181,7 +181,7 @@ void __init init_IRQ(void)
        int i;
 
        for (i=0; i < XTENSA_NR_IRQS; i++)
-               irq_desc[i].handler = &xtensa_irq_type;
+               irq_desc[i].chip = &xtensa_irq_type;
 
        cached_irq_mask = 0;
 
index c6f471b9eaa0c603f356441bea6b980c2e85492e..eda029fc897218a53d38a4f82a66db0a42272963 100644 (file)
@@ -71,13 +71,13 @@ static int pci_bus_count;
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-                      unsigned long align)
+pcibios_align_resource(void *data, struct resource *res, resource_size_t size,
+                      resource_size_t align)
 {
        struct pci_dev *dev = data;
 
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (size > 0x100) {
                        printk(KERN_ERR "PCI: I/O Region %s/%d too large"
index 937d81f62f43e73e90e75e1280a0ef899cbbadbe..fe14909f45e057983c1100c5dab33359d718d7c6 100644 (file)
@@ -29,7 +29,7 @@
 
 extern volatile unsigned long wall_jiffies;
 
-spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 
 
index 225d64d73f04c8700f9dc939bcbb26b0e56bf3e5..27e409089a7b9837ce33927236f21ea89323fdf1 100644 (file)
@@ -461,7 +461,7 @@ void show_code(unsigned int *pc)
        }
 }
 
-spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
index c04422a502da8ebd0cb03cc76d5962433fde6b0b..eee03a3876a3f2f875260b64c1c0bc51267219a3 100644 (file)
@@ -3403,7 +3403,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
 }
 
 
-static struct notifier_block blk_cpu_notifier = {
+static struct notifier_block __devinitdata blk_cpu_notifier = {
        .notifier_call  = blk_cpu_notify,
 };
 
@@ -3541,9 +3541,7 @@ int __init blk_dev_init(void)
                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
+       register_hotcpu_notifier(&blk_cpu_notifier);
 
        blk_max_low_pfn = max_low_pfn;
        blk_max_pfn = max_pfn;
index 94b8d820c51229bcb3f669f9f176720c20e5af42..610d2cc02cf8f500e8eed0158df3f3967cb520cf 100644 (file)
@@ -328,7 +328,7 @@ config ACPI_CONTAINER
 config ACPI_HOTPLUG_MEMORY
        tristate "Memory Hotplug"
        depends on ACPI
-       depends on MEMORY_HOTPLUG || X86_64
+       depends on MEMORY_HOTPLUG
        default n
        help
          This driver adds supports for ACPI Memory Hotplug.  This driver
index e0a95ba72371562fc1c250ebcadd0b170eb50881..1012284ff4f7eb4fc55d0ed1a3e200e7ef84b3a0 100644 (file)
@@ -57,6 +57,7 @@ MODULE_LICENSE("GPL");
 
 static int acpi_memory_device_add(struct acpi_device *device);
 static int acpi_memory_device_remove(struct acpi_device *device, int type);
+static int acpi_memory_device_start(struct acpi_device *device);
 
 static struct acpi_driver acpi_memory_device_driver = {
        .name = ACPI_MEMORY_DEVICE_DRIVER_NAME,
@@ -65,48 +66,79 @@ static struct acpi_driver acpi_memory_device_driver = {
        .ops = {
                .add = acpi_memory_device_add,
                .remove = acpi_memory_device_remove,
+               .start = acpi_memory_device_start,
                },
 };
 
+struct acpi_memory_info {
+       struct list_head list;
+       u64 start_addr;         /* Memory Range start physical addr */
+       u64 length;             /* Memory Range length */
+       unsigned short caching; /* memory cache attribute */
+       unsigned short write_protect;   /* memory read/write attribute */
+       unsigned int enabled:1;
+};
+
 struct acpi_memory_device {
        acpi_handle handle;
        unsigned int state;     /* State of the memory device */
-       unsigned short caching; /* memory cache attribute */
-       unsigned short write_protect;   /* memory read/write attribute */
-       u64 start_addr;         /* Memory Range start physical addr */
-       u64 length;             /* Memory Range length */
+       struct list_head res_list;
 };
 
+static acpi_status
+acpi_memory_get_resource(struct acpi_resource *resource, void *context)
+{
+       struct acpi_memory_device *mem_device = context;
+       struct acpi_resource_address64 address64;
+       struct acpi_memory_info *info, *new;
+       acpi_status status;
+
+       status = acpi_resource_to_address64(resource, &address64);
+       if (ACPI_FAILURE(status) ||
+           (address64.resource_type != ACPI_MEMORY_RANGE))
+               return AE_OK;
+
+       list_for_each_entry(info, &mem_device->res_list, list) {
+               /* Can we combine the resource range information? */
+               if ((info->caching == address64.info.mem.caching) &&
+                   (info->write_protect == address64.info.mem.write_protect) &&
+                   (info->start_addr + info->length == address64.minimum)) {
+                       info->length += address64.address_length;
+                       return AE_OK;
+               }
+       }
+
+       new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
+       if (!new)
+               return AE_ERROR;
+
+       INIT_LIST_HEAD(&new->list);
+       new->caching = address64.info.mem.caching;
+       new->write_protect = address64.info.mem.write_protect;
+       new->start_addr = address64.minimum;
+       new->length = address64.address_length;
+       list_add_tail(&new->list, &mem_device->res_list);
+
+       return AE_OK;
+}
+
 static int
 acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
 {
        acpi_status status;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_resource *resource = NULL;
-       struct acpi_resource_address64 address64;
+       struct acpi_memory_info *info, *n;
 
        ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources");
 
-       /* Get the range from the _CRS */
-       status = acpi_get_current_resources(mem_device->handle, &buffer);
-       if (ACPI_FAILURE(status))
-               return_VALUE(-EINVAL);
-
-       resource = (struct acpi_resource *)buffer.pointer;
-       status = acpi_resource_to_address64(resource, &address64);
-       if (ACPI_SUCCESS(status)) {
-               if (address64.resource_type == ACPI_MEMORY_RANGE) {
-                       /* Populate the structure */
-                       mem_device->caching = address64.info.mem.caching;
-                       mem_device->write_protect =
-                           address64.info.mem.write_protect;
-                       mem_device->start_addr = address64.minimum;
-                       mem_device->length = address64.address_length;
-               }
+       status = acpi_walk_resources(mem_device->handle, METHOD_NAME__CRS,
+                                    acpi_memory_get_resource, mem_device);
+       if (ACPI_FAILURE(status)) {
+               list_for_each_entry_safe(info, n, &mem_device->res_list, list)
+                       kfree(info);
+               return -EINVAL;
        }
 
-       acpi_os_free(buffer.pointer);
-       return_VALUE(0);
+       return 0;
 }
 
 static int
@@ -181,7 +213,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
 
 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
 {
-       int result;
+       int result, num_enabled = 0;
+       struct acpi_memory_info *info;
+       int node;
 
        ACPI_FUNCTION_TRACE("acpi_memory_enable_device");
 
@@ -194,15 +228,35 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
                return result;
        }
 
+       node = acpi_get_node(mem_device->handle);
        /*
         * Tell the VM there is more memory here...
         * Note: Assume that this function returns zero on success
+        * We don't have memory-hot-add rollback function,now.
+        * (i.e. memory-hot-remove function)
         */
-       result = add_memory(mem_device->start_addr, mem_device->length);
-       if (result) {
+       list_for_each_entry(info, &mem_device->res_list, list) {
+               u64 start_pfn, end_pfn;
+
+               start_pfn = info->start_addr >> PAGE_SHIFT;
+               end_pfn = (info->start_addr + info->length - 1) >> PAGE_SHIFT;
+
+               if (pfn_valid(start_pfn) || pfn_valid(end_pfn)) {
+                       /* already enabled. try next area */
+                       num_enabled++;
+                       continue;
+               }
+
+               result = add_memory(node, info->start_addr, info->length);
+               if (result)
+                       continue;
+               info->enabled = 1;
+               num_enabled++;
+       }
+       if (!num_enabled) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n"));
                mem_device->state = MEMORY_INVALID_STATE;
-               return result;
+               return -EINVAL;
        }
 
        return result;
@@ -246,8 +300,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
 static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
 {
        int result;
-       u64 start = mem_device->start_addr;
-       u64 len = mem_device->length;
+       struct acpi_memory_info *info, *n;
 
        ACPI_FUNCTION_TRACE("acpi_memory_disable_device");
 
@@ -255,10 +308,13 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
         * Ask the VM to offline this memory range.
         * Note: Assume that this function returns zero on success
         */
-       result = remove_memory(start, len);
-       if (result) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n"));
-               return_VALUE(result);
+       list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
+               if (info->enabled) {
+                       result = remove_memory(info->start_addr, info->length);
+                       if (result)
+                               return result;
+               }
+               kfree(info);
        }
 
        /* Power-off and eject the device */
@@ -356,6 +412,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
                return_VALUE(-ENOMEM);
        memset(mem_device, 0, sizeof(struct acpi_memory_device));
 
+       INIT_LIST_HEAD(&mem_device->res_list);
        mem_device->handle = device->handle;
        sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
        sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
@@ -391,6 +448,25 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type)
        return_VALUE(0);
 }
 
+static int acpi_memory_device_start (struct acpi_device *device)
+{
+       struct acpi_memory_device *mem_device;
+       int result = 0;
+
+       ACPI_FUNCTION_TRACE("acpi_memory_device_start");
+
+       mem_device = acpi_driver_data(device);
+
+       if (!acpi_memory_check_device(mem_device)) {
+               /* call add_memory func */
+               result = acpi_memory_enable_device(mem_device);
+               if (result)
+                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                               "Error in acpi_memory_enable_device\n"));
+       }
+       return_VALUE(result);
+}
+
 /*
  * Helper function to check for memory device
  */
index e2c1a16078c990113d4813024e0abf170e04928b..13d6d5bdea264f16dbe6239d2cde0a5b5d5daa20 100644 (file)
@@ -254,5 +254,18 @@ int acpi_get_pxm(acpi_handle h)
        } while (ACPI_SUCCESS(status));
        return -1;
 }
-
 EXPORT_SYMBOL(acpi_get_pxm);
+
+int acpi_get_node(acpi_handle *handle)
+{
+       int pxm, node = -1;
+
+       ACPI_FUNCTION_TRACE("acpi_get_node");
+
+       pxm = acpi_get_pxm(handle);
+       if (pxm >= 0)
+               node = acpi_map_pxm_to_node(pxm);
+
+       return_VALUE(node);
+}
+EXPORT_SYMBOL(acpi_get_node);
index 889855d8d9f9080ee9b98c3a1a1bcd0691006f59..9e3e2a69c03a6dedd375b32666e94b0989ed1566 100644 (file)
@@ -180,8 +180,9 @@ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 amba_attr(id, "%08x\n", dev->periphid);
 amba_attr(irq0, "%u\n", dev->irq[0]);
 amba_attr(irq1, "%u\n", dev->irq[1]);
-amba_attr(resource, "\t%08lx\t%08lx\t%08lx\n",
-         dev->res.start, dev->res.end, dev->res.flags);
+amba_attr(resource, "\t%016llx\t%016llx\t%016lx\n",
+        (unsigned long long)dev->res.start, (unsigned long long)dev->res.end,
+        dev->res.flags);
 
 /**
  *     amba_device_register - register an AMBA device
index 4b6bf19c39c004d4b2277f11e68ac2ea59a4b753..4048681f36d503ca2030d0954311ce97327cc183 100644 (file)
@@ -2257,7 +2257,8 @@ static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_
        }
 
        PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"
-               " IO %lx, IRQ %u, MEM %p", pci_resource_start(pci_dev, 1),
+               " IO %llx, IRQ %u, MEM %p",
+               (unsigned long long)pci_resource_start(pci_dev, 1),
                irq, bus_to_virt(pci_resource_start(pci_dev, 0)));
 
        // check IO region
index f2eeaf9dc56a4fffe9dff197a5899588d02f5098..d40605c1af73819daf6095dbcd3112bd7fb1c724 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
+#include <linux/poison.h>
 #include <linux/errno.h>
 #include <linux/atm.h>
 #include <linux/atmdev.h>
@@ -754,7 +755,7 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q)
                        fs_kfree_skb (skb);
 
                        fs_dprintk (FS_DEBUG_ALLOC, "Free trans-d: %p\n", td); 
-                       memset (td, 0x12, sizeof (struct FS_BPENTRY));
+                       memset (td, ATM_POISON_FREE, sizeof(struct FS_BPENTRY));
                        kfree (td);
                        break;
                default:
@@ -1657,9 +1658,10 @@ static int __devinit fs_init (struct fs_dev *dev)
        func_enter ();
        pci_dev = dev->pci_dev;
 
-       printk (KERN_INFO "found a FireStream %d card, base %08lx, irq%d.\n", 
+       printk (KERN_INFO "found a FireStream %d card, base %16llx, irq%d.\n",
                IS_FS50(dev)?50:155,
-               pci_resource_start(pci_dev, 0), dev->pci_dev->irq);
+               (unsigned long long)pci_resource_start(pci_dev, 0),
+               dev->pci_dev->irq);
 
        if (fs_debug & FS_DEBUG_INIT)
                my_hd ((unsigned char *) dev, sizeof (*dev));
index dd712b24ec91900f3b75506af6ecf6467f7ba160..4bef76a2f3f2a7611ff0dcbca79c8d774d7a7255 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/cpu.h>
 #include <linux/topology.h>
 #include <linux/device.h>
+#include <linux/node.h>
 
 #include "base.h"
 
@@ -57,13 +58,12 @@ static void __devinit register_cpu_control(struct cpu *cpu)
 {
        sysdev_create_file(&cpu->sysdev, &attr_online);
 }
-void unregister_cpu(struct cpu *cpu, struct node *root)
+void unregister_cpu(struct cpu *cpu)
 {
        int logical_cpu = cpu->sysdev.id;
 
-       if (root)
-               sysfs_remove_link(&root->sysdev.kobj,
-                                 kobject_name(&cpu->sysdev.kobj));
+       unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu));
+
        sysdev_remove_file(&cpu->sysdev, &attr_online);
 
        sysdev_unregister(&cpu->sysdev);
@@ -109,23 +109,21 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
  *
  * Initialize and register the CPU device.
  */
-int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
+int __devinit register_cpu(struct cpu *cpu, int num)
 {
        int error;
-
        cpu->node_id = cpu_to_node(num);
        cpu->sysdev.id = num;
        cpu->sysdev.cls = &cpu_sysdev_class;
 
        error = sysdev_register(&cpu->sysdev);
-       if (!error && root)
-               error = sysfs_create_link(&root->sysdev.kobj,
-                                         &cpu->sysdev.kobj,
-                                         kobject_name(&cpu->sysdev.kobj));
+
        if (!error && !cpu->no_control)
                register_cpu_control(cpu);
        if (!error)
                cpu_sys_devices[num] = &cpu->sysdev;
+       if (!error)
+               register_cpu_under_node(num, cpu_to_node(num));
 
 #ifdef CONFIG_KEXEC
        if (!error)
@@ -145,5 +143,13 @@ EXPORT_SYMBOL_GPL(get_cpu_sysdev);
 
 int __init cpu_dev_init(void)
 {
-       return sysdev_class_register(&cpu_sysdev_class);
+       int err;
+
+       err = sysdev_class_register(&cpu_sysdev_class);
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+       if (!err)
+               err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
+#endif
+
+       return err;
 }
index e2f64f91ed0558fcc6b9a70feb9620170685c485..33c5cce1560b261b767fa56faa410e19ed47d5e4 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/dmapool.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/poison.h>
 
 /*
  * Pool allocator ... wraps the dma_alloc_coherent page allocator, so
@@ -35,8 +36,6 @@ struct dma_page {     /* cacheable header for 'allocation' bytes */
 };
 
 #define        POOL_TIMEOUT_JIFFIES    ((100 /* msec */ * HZ) / 1000)
-#define        POOL_POISON_FREED       0xa7    /* !inuse */
-#define        POOL_POISON_ALLOCATED   0xa9    /* !initted */
 
 static DECLARE_MUTEX (pools_lock);
 
index dd547af4681a50c87dc976cea8c22ee497f9a133..c6b7d9c4b65115054f3f9cd3591c7dbf2c75142d 100644 (file)
@@ -306,11 +306,13 @@ static ssize_t
 memory_probe_store(struct class *class, const char *buf, size_t count)
 {
        u64 phys_addr;
+       int nid;
        int ret;
 
        phys_addr = simple_strtoull(buf, NULL, 0);
 
-       ret = add_memory(phys_addr, PAGES_PER_SECTION << PAGE_SHIFT);
+       nid = memory_add_physaddr_to_nid(phys_addr);
+       ret = add_memory(nid, phys_addr, PAGES_PER_SECTION << PAGE_SHIFT);
 
        if (ret)
                count = ret;
index c80c3aeed004a558de9cf9db0632191cf1c16c99..eae2bdc183bb7741a85c23f086d156c95b1d0317 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/cpumask.h>
 #include <linux/topology.h>
 #include <linux/nodemask.h>
+#include <linux/cpu.h>
 
 static struct sysdev_class node_class = {
        set_kset_name("node"),
@@ -190,6 +191,66 @@ void unregister_node(struct node *node)
        sysdev_unregister(&node->sysdev);
 }
 
+struct node node_devices[MAX_NUMNODES];
+
+/*
+ * register cpu under node
+ */
+int register_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+       if (node_online(nid)) {
+               struct sys_device *obj = get_cpu_sysdev(cpu);
+               if (!obj)
+                       return 0;
+               return sysfs_create_link(&node_devices[nid].sysdev.kobj,
+                                        &obj->kobj,
+                                        kobject_name(&obj->kobj));
+        }
+
+       return 0;
+}
+
+int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+       if (node_online(nid)) {
+               struct sys_device *obj = get_cpu_sysdev(cpu);
+               if (obj)
+                       sysfs_remove_link(&node_devices[nid].sysdev.kobj,
+                                        kobject_name(&obj->kobj));
+       }
+       return 0;
+}
+
+int register_one_node(int nid)
+{
+       int error = 0;
+       int cpu;
+
+       if (node_online(nid)) {
+               int p_node = parent_node(nid);
+               struct node *parent = NULL;
+
+               if (p_node != nid)
+                       parent = &node_devices[p_node];
+
+               error = register_node(&node_devices[nid], nid, parent);
+
+               /* link cpu under this node */
+               for_each_present_cpu(cpu) {
+                       if (cpu_to_node(cpu) == nid)
+                               register_cpu_under_node(cpu, nid);
+               }
+       }
+
+       return error;
+
+}
+
+void unregister_one_node(int nid)
+{
+       unregister_node(&node_devices[nid]);
+}
+
 static int __init register_node_type(void)
 {
        return sysdev_class_register(&node_class);
index 8c52421cbc545b54a6ce1c84c0cf1bf3f734c751..c2d621632383306a493fd5f60d5d3b9b55721f70 100644 (file)
@@ -107,7 +107,7 @@ static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
        return 0;
 }
 
-static int topology_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
                unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -125,7 +125,7 @@ static int topology_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block topology_cpu_notifier =
+static struct notifier_block __cpuinitdata topology_cpu_notifier =
 {
        .notifier_call = topology_cpu_callback,
 };
index 3c74ea729fc79529ed766b98f3e1d2b78bb3da57..18dd026f470dcf6d1d6d056df23d299efb2fa422 100644 (file)
@@ -210,7 +210,7 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
 {
        struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
        struct address_space *mapping = file->f_mapping;
-       struct address_space_operations *aops = mapping->a_ops;
+       const struct address_space_operations *aops = mapping->a_ops;
        pgoff_t index;
        unsigned offset, bv_offs;
        int len, ret;
@@ -784,7 +784,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
 
        error = -EINVAL;
        if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
-               struct address_space_operations *aops = mapping->a_ops;
+               const struct address_space_operations *aops = mapping->a_ops;
                /*
                 * If we can't read - sorry. If we only can't write - well,
                 * it's going to be read-only.
index 852b564e903a69566a1f3b82d3a339d884db9b98..1a9dee19efcf11cfc61d02dc383a4cb04ff222d9 100644 (file)
@@ -707,7 +707,7 @@ static int pf_detect(void)
                        if (pi_init(pf->pi, 0, conf[D_PRT], conf[D_MOD],
                                    conf[D_UNI], conf[D_PRO], conf[D_DLY],
                                    pf_scratch, PI_PF, verbose, pf->name)) {
-                               if (!pf_probe(pf) && pf->disk) {
+                               if (pf->disk && !pf_probe(pf)) {
                                        pf->present = 1;
                                        k++;
                                } else
index 940bfd7951e5c1c582a672447b65dd28ff1367c7..0378da04cfa23c0c38b967a0162aee3563119171 100644 (file)
@@ -191,7 +191,7 @@ static int ramdisk_set_page_dirty(struct page *page)
        return 0;
 }
 
-static struct address_space_operations ramdisk_aops = {
+static const struct address_space_operations ramdisk_aops = {
        .readpage       = ramdisk_readpage,
        .prepare_write  = ramdisk_prepare_write,
        .commit_write   = ramdisk_commit_write,
index 2ae08b343b935518c86098959866299e73f213e8..8144ce9f4df0543555aa71573ad1c69a43748013 100644 (file)
@@ -1694,9 +1694,10 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        DPRINTK("waiting for probe_comp\n");
        wait_for_completion(&host->probe_comp);
 
-       printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n",
+       printk(KERN_INFO "%s: pci %s, ports %d, io %llx, irq %u, major %d\n",
               host->name, pci_name(pdev), (int) CARM_MAX_PORTS,
-              pci_resource_start(pdev, 0), pdev->irq, host->major);
+              (unsigned long long)pci_resource_start(pdev, 0),
+                  pdev->irq, host->major);
 
        carm_host_id++;
        pci_set_drvdata(pdev, host);
index 3610c57295533c81807bbddfd174ab1ede354551..c40e487d9f5cd8a35475e4357800968eca3ba838 100644 (file)
@@ -939,12 +939,36 @@ config MWAVE
 config SCx200_GPIO
        tristate "NatSemi SCx200 GPIO Support"
        depends on SCx200
+       select NSC_GPIO
        help
          Give userspace access to the GPIO pins on the National
          Semiconductor SCx200 processors.
 
          If compiled as a module, it will be called scx200_gpio.
 
+config PC8736x_GPIO
+       tristate "NatSemi PC8736x GPIO Support"
+       depends on X86
+       default SCx200_GPIO     # mostly N
+       select NSC_GPIO         # needed for support routines
+       help
+         Give userspace access to the GPIO pins on the National
+         Semiconductor PC-8736x (x=[03456]) SuperIO chip.  The chip
+         has multiple functional units, inc several managed by
+         hwmon/pc87360 driver.  Tested with PC-87366
+
+         If compiled as a module, it will be called pc8736x_gpio.
+
+config NSC_GPIO
+       tristate "NatSemi Base GPIO Support"
+       depends on X86_32
+       # selected by SCx200_GPIO and PC8736x_GPIO
+       # what about 2 selectors differing: m != y
+       help
+         Common support used (and needed) by scx200_gpio and
+         pc8736x_gpio drivers.  If those drivers are built as
+         modules, this one will be too, named nsc_gpio
+
 config CS5535_GPIO
        tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)"
        depends on X86_32
index 524105597ea7d7ff82339902afc0c15cda691447..6e0f4469d8bbdbf37197a7e722131acf48378bf7 100644 (file)
@@ -82,6 +82,8 @@ obj-$(CONFIG_PPDEV)           += ppdev.o
 obj-$(CONFIG_NWBUTTON)         += nwbutton.o
 obj-$(CONFIG_NWFLASH)          += nwflash.o
 obj-$(CONFIG_SCx200_GPIO)      += scx200_gpio.o
+obj-$(CONFIG_PC8736x_GPIO)     += pc8736x_gpio.o
+obj-$(CONFIG_NSC_GPIO)         += nsc_gpio.o
 obj-$(CONFIG_CS5535_GPIO)      += cs5535_gpio.o
 obj-$(CONFIG_GPIO_VR41XX)      += vr41xx_giu.o
 obj-$(CONFIG_TANBAC_TB0219)    += tb0219.o
index cfa7922cb431f500788b6d0ba6360312137eee03..d73be4c2db8a9c5c6fffe250d36e2e3593ac53f5 100644 (file)
@@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void)
 
 static void __devexit agp_sgi_cleanup(void)
 {
-       if (sgi_tioca_agp_bridges)
-               kfree(sgi_tioca_agp_bridges);
-       sgi_tioca_agp_bridges=NULL;
+       kfree(sgi_tioca_agp_bridges);
+       sgi_tioca_agp_bridges = NULL;
 }
 
 module_init(agp_sgi_init);
index 9275d5e52e6de63d86309c82096f19ac5776592e..72fb60765c45a4f973c77ae67c916e85aff80485 100644 (file)
@@ -209,13 +209,16 @@ static int __init applicom_init(void)
                RamIO = ioremap(dev->resource[0].start, LEN_RAM_IO);
 
                if (!RamIO) {
-                       printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", dev->resource[0].start);
+                       printk(KERN_INFO "ac.o: Failed to ioremap PCI memory "
+                               "space at 0x%llx\n",
+                               (unsigned long long)dev->resource[0].start);
                        pci_disable_device(dev);
                        return -EIO;
                }
 
-               printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n",
-                      applicom_pci_devnames[dev->device-1], dev->resource[0].start, 
+               printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n",
+                      applicom_pci_devnames[dev->device-1],
+                          (unsigned long long)dev->resource[0].start,
                       dev->irq);
 
                boardno = ac_register_board(dev->resource[0].start, RamIO,0);
index 6543b9a14c42e677038bd001309e35143c5a10a1..d117cc9971922f5ec8a6c713da435221c4eb2af7 100644 (file)
@@ -43,7 +43,7 @@ typedef struct drm_mem_stats {
        unsigned long bytes_freed;
 } drm_mem_stats_t;
 
-static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(drm_mem_lock);
 static unsigned long drm_ram_available = 0;    /* In pages */
 static unsigned long drm_ram_used = 0;
 static drm_mem_stats_t drm_mem_stats[] =
index b7f17457b4243bb1c18e8dea11b6b7149a22e7fe..78a81a4a99c5c60fda46b05497351e211d94df1f 100644 (file)
@@ -557,7 +557,7 @@ via_init_dmablit(drm_device_t *dev)
                blitq->num_outstanding = 0;
                blitq->is_active = 0;
                blitq->aborting = 0;
-               blitq->blit_lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&blitq->blit_lock);
                for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) {
                        DRM_INIT_WAITQUEUE(blitq->blit_queue + j);
                }
index 9cad8501d62c9fca6a93656c204bb1dea1e09a15..dc0602ae8503041046e794790957c33be39d9ba8 100644 (file)
@@ -80,7 +80,7 @@ static int invalid_lilo_config;
 /* The ISA boards do window flipping into the same spaces so its only sane
    with a single lock. It's still pretty efficient */
 
-static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(epca_lock);
 
 /* -----------------------------------------------------------------------
        MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 
index 8d97b3911293bf46436bd743ae9c28aaad714316..afa26b65dac3b7fb4313df3e1b6e003951bf2d9d 100644 (file)
@@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = {
 static int hvcs_alloc_index_list(int n)
 {
        int i;
+
        hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL);
        if (!hvcs_index_list)
                return -ENOMEM;
        hvcs_index_count = n;
-       for(i = 0; i < hvcs_index_count; i++)
+       for (i = 0; i < hvcs_index_count; i++)
                hvcs_index_list[i] = -1;
        return 0;
 }
@@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n)
 static void hvcs_free_index_list(void)
 {
        /* Paranoia check to be thorough. */
-       if (hvcs_index_list) {
-               kfree(hvcs_index_list);
-               hvcs_index_list = NULL;
-               hvcs_index_count = 0;
-       }
+       kfree(hvcs_index_list);
+       hvcs_index_list = NULL;
+       hvcs_index_count = 0;
 }
 
 static int __init hvcs_module_init(void)
index b03ddab1bef57bae9a81acd79d31c42297d364cd..ad26f4b997c5bc7508a2abe11a36bda7a65e4eab 100644 (file)
@@ -57,8 +57,7 @@ static int ipmi_init_msghandler(void);
 static int initialized = 0;
 
 #ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_ipmi_root = NULL;
-EXPORT_SYMBOL(proc_ipmi_root);
+static struct proc_dir_entry *proc_ipmi_root = NULL;
 #endif /* CONFIG_PROC_FS */
 
 #define MAX_EVENTS_IN_QUEUE    25
@@ -3739,11 +3738,8 @@ static int ipmi_init_msghandler(void)
        proc_ipmi_root->owner = THIS_MODULE;
 #endif /* CONFIG_PROC_FS */
 
-       init_timer(&ipmi_timer);
-       ipmi_timer.data = 0;
-       ipmi_timer.function = ipmi_timeout;
-       ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
-       add_timer(&ipmi_timer);
+       setup_timer(&ipmi_timer, ipmi_timeout, 0);
+       mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
 
        atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
index 02a7dd7a8a55571cbf261e63a9dcdf3cf7fbb969..bd4f2248b758e40a87039a75359a403c14357cb7 100644 (file)
 #include <linux/mutex.h>
 #include <linux/kthread.h>
 #include <asm/irq.h>
-#ifdef CONFIG_HIGH_RES_TIMERS
-#include <linux/hrtime.h>
-# if defined(schedule_next_int)
-/* Old high-res timer code, do translations. */
-#  define get_arch_cycles(a) quick_update_jiffies_sub(a)
-#  define arch_cycles_per_jiffy cycles_per_jiffies
-# endif
-static inline void add_usec_to_timer(struct timer_list *t, long v)
-{
-       t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000);
-       while (t->arch_cycle_expires >= arch_cycles_per_jiffy)
-       {
-               t->expires++;
-               t->arch_cycle_expires -= arch_cycles_per_jiffy;
-       }
-}
-#endif
 #include <linux/interrupt.h>
 #include <linux/rcupdate.h>
 #include <linux/ipmi_smi.h>
@@ -243,8 +226,6 @@ static int register_xaction_notifier(struct notifier_block * nb)
        return atomic_notifier_chain_register(&xaction_notifier_list, nb);
 }
 
-static void si_restart_short_timer(struct smi_info *smi_info);
-
 static void deliver_recv_msg(struct smi_info *smi_info,
                             struct ipmi_smi_msg *msg)
 {
@@ -768,7 +749,6 @@ static void sender(void                *send_info,
            && (smi_info->curr_msg == NULL))
        {
                start_next_msg(smi_info);
-               si_restart_short_timer(smi_info);
        }
        spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 }
@@ -809,7 +789,7 @@ static int ipmi_thread(void *data)
                        /* do nothing */
                }
                else if (smi_result == SI_SM_CALL_WITH_DELAY)
-                       udelay(1);
+                       schedule();
                else
                        schedule_timeout_interruptible(1);
        }
@@ -833,37 +813,6 @@ static void request_events(void *send_info)
 
 static int initialized = 0;
 
-/* Must be called with interrupts off and with the si_lock held. */
-static void si_restart_short_timer(struct smi_info *smi_info)
-{
-#if defined(CONFIG_HIGH_RES_TIMERS)
-       unsigned long flags;
-       unsigned long jiffies_now;
-       unsigned long seq;
-
-       if (del_timer(&(smi_info->si_timer))) {
-               /* If we don't delete the timer, then it will go off
-                  immediately, anyway.  So we only process if we
-                  actually delete the timer. */
-
-               do {
-                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
-                       jiffies_now = jiffies;
-                       smi_info->si_timer.expires = jiffies_now;
-                       smi_info->si_timer.arch_cycle_expires
-                               = get_arch_cycles(jiffies_now);
-               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-               add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
-
-               add_timer(&(smi_info->si_timer));
-               spin_lock_irqsave(&smi_info->count_lock, flags);
-               smi_info->timeout_restarts++;
-               spin_unlock_irqrestore(&smi_info->count_lock, flags);
-       }
-#endif
-}
-
 static void smi_timeout(unsigned long data)
 {
        struct smi_info   *smi_info = (struct smi_info *) data;
@@ -904,31 +853,15 @@ static void smi_timeout(unsigned long data)
        /* If the state machine asks for a short delay, then shorten
            the timer timeout. */
        if (smi_result == SI_SM_CALL_WITH_DELAY) {
-#if defined(CONFIG_HIGH_RES_TIMERS)
-               unsigned long seq;
-#endif
                spin_lock_irqsave(&smi_info->count_lock, flags);
                smi_info->short_timeouts++;
                spin_unlock_irqrestore(&smi_info->count_lock, flags);
-#if defined(CONFIG_HIGH_RES_TIMERS)
-               do {
-                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
-                       smi_info->si_timer.expires = jiffies;
-                       smi_info->si_timer.arch_cycle_expires
-                               = get_arch_cycles(smi_info->si_timer.expires);
-               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-               add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
-#else
                smi_info->si_timer.expires = jiffies + 1;
-#endif
        } else {
                spin_lock_irqsave(&smi_info->count_lock, flags);
                smi_info->long_timeouts++;
                spin_unlock_irqrestore(&smi_info->count_lock, flags);
                smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
-#if defined(CONFIG_HIGH_RES_TIMERS)
-               smi_info->si_timer.arch_cycle_expires = 0;
-#endif
        }
 
  do_add_timer:
index 8f8867170973ccb95960b57a90cd5e58dc9d5ddb..1a0a19c53605ed6f4c9f54afa70fbdbab2e002ea 100644 (file)
@@ -949,9 +949,10 @@ static int wdog_reboot_handler(struct notifier_block *this,
                        /* Disable the WDT if we are shutting down. */
                        ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
                        panic_halt_ipmi_set_timeout();
-               } else {
+               } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
                        /* Set a long timer to let the reboot happens, but
-                          reboot if it hangs. */
+                          reboot if it hangs, but only if the watchdog
+                          timer was already running. */
                        timeout = 120;
                        pretimeout = 0;
                        ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
@@ -973,16 +974,17 @@ static int wdog_panic_handler(struct notifier_block *this,
 {
        static int panic_event_handled = 0;
 
-       /* On a panic, if we have a panic timeout, make sure that the thing
-          reboots, even if it hangs during that panic. */
-       if (watchdog_user && !panic_event_handled) {
-               /* Make sure the panic doesn't hang, and make sure we
-                  do this only once. */
+       /* On a panic, if we have a panic timeout, make sure to extend
+          the watchdog timer to a reasonable value to complete the
+          panic, if the watchdog timer is running.  Plus the
+          pretimeout is meaningless at panic time. */
+       if (watchdog_user && !panic_event_handled &&
+           ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
+               /* Make sure we do this only once. */
                panic_event_handled = 1;
            
                timeout = 255;
                pretimeout = 0;
-               ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
                panic_halt_ipmi_set_timeout();
        }
 
index ef20c1fc9c4c121cf51d7102096cfb55f3fd5227..216c79256de3e36566bc3bb2df61d9c7c5a6b269 100644 (file)
 #include <linux/devfs_fs_kernel.h>
 #include <linux/device.h>
 #include <linux/wait.h>
+#include <linux/eisa.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_PCI
 #include <linux/pci.h>
-#endif
 
 /*****************************************************************************/
 
@@ -137,6 +136,10 @@ static stlconf_t   stli_brdconf[] = {
 
 static int     stli_nrbrds = ARRAY_SIZE(stli_brdconf);
 
+/* stli_lock must NOT be taken holding brd_lock */
+static spinlock_t stli_lock;   /* TTY logic lock */
+static spinlock_t brd_lock;    /* Board logic lock */
+
 /*
  *     There is some experimental EISA board detection code in this driver.
  *     By default it is disabled, but for those that want to try it out,
@@ -173,14 +176,6 @@ static char        *stli_serialname = "ttyE";
 
 static struct tty_driver       *stli_serial;
 
-/*
- *     We will need to allocate a temporary write buffer for chars that
- *     come direct from user space. The problem is that a copy from user
- *     space might cause a page fault (typically on a system that is
- *     swapping!). All ports will share one buffer - since if the system
- *     is already swapping a shared buffer won't make things any worse.
- */
-static char                    *stli_tmpwritebuf;
 
 #define        STLI_TXBUFSIZE          4096
 
@@ -419,7 +414,7 @@ static int  stli_eisamempsize = ARRAY_SIZE(stli_eisamemprobeaddrs);
 #endif
 
 static struct pci_device_id istallion_pci_tbl[] = {
-       { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA), },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, istallion_pci_tbl);
@@ -682,7 +677,7 @@ static int  stli_startbrd(stlibrd_t *brdp);
 static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
 static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
 static int     stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
-static void    stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp);
+static void    stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp);
 static void    stli_poll(unsigned long arg);
 static int     stli_hostcmd(stlibrd_t *brdp, stliport_t *portp);
 static int     stli_initopen(stlibrd_t *brdp, stliport_t *portp);
@@ -693,7 +688,8 @@ static void stli_dohangup(void *arg);
 static int     stli_setport(stliport_t *portp);
 static int     stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void    stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp);
+static void    __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void    stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp);
 static void    stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp);
 static void    stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
 static long    stli_mktiocm(unsigned long sigvalue);
@@ -799,18 +795,8 @@ static struct class *istallion_class;
 
 static int __init istallion_module_init(void)
 {
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk("init_module()\n");
-#endif
-
-       save_flags(flags);
-       cli();
        stli_init();
-       restore_flags(flags);
-
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -819,33 +805,24 @@ static void __exit istallion_module_exit(void)
 {
        stlibrd_t       *brdp;
        stliport_t      *portp;
-       unsigned long   flags;
        int             i, j;
 
-#ifdef DEBUG
-       printk("cleanup_module()\n");
-#endif
-
        printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
                stli_drvversion);
 
-       save_flags(flags);
-       cli();
-
-/*
- *     Free up all allocated resources used by the ports. This includes
- *     memory and interrupts.
- */
+       /*
+        *      Free up all allocated resources used by the ports. This includes
+        *      memory and interrupts.
+        */
        if (stli_timeron) {
                stli_timeron = 0;
-               del_timer(&stli_timerlist);
+               del_timer_sync(&stli_timerlist);
        }
 
        i = tty_unregister_driver(stli_serial);
        if (i) {
                printk("STALLION: failed to un-register tty driver, "
                        "errno=%d\n", -i);
-               restore_flags(flags);
                return;
        }
        put_tty_driver(stli_serial);
@@ -859,16 +836,15 @@ static void __exit istallion_module_exit(void)
                printk("STALLION: failed to un-register serial memory device, "
                        "errno=%d\n", -i);
 
-       kfree(stli_tmpwritebuf);
        kfree(stli_txcookbuf);
 
        for (i = 0; (i < stli_nrbrds); i++) {
-               if ((brdp = stli_brds[i]) == (stlibrd_t *) NULL)
+               if ((brdp = stli_brds[i]) == NULL)
                        continue;
                for (j = 0; (j < STL_MAXPORTS); j++) {
                        portp = brdp->ports[j];
-                       if (portp != (stliport_t *) NULL) {
-                               if (portp->tty != (struct tty_struct *) NULL)
+                       if (portp != NULL) {
+                               if (portp->tty != NULL)
                                        tty_hangup(portp->tty);
                                kfree(portp);
                        }
@@ -878,10 +854,8 @@ static void __exit istallion_module_exit(void)
                if (brdp->iosize > 0)
                        release_region(brdp->iobase, brdp->iosize);
                kfree(brdp);
-               stli_brds[i] = (stlibrd_t *) NULL;
+               stli_brds[i] = NULL;
        }
-
-       restore_flags(flags);
 }
 
 module_init(istallion_module_init);
@@ -895,19 +869,15 @@ module_exit(istallion_module_exit);
 
 static void stli_argbrds(void)
 {
-       stlconf_t       conf;
-       stlibrd_t       *brdp;
-       int             i;
-
-#ifdef DEBUG
-       printk("stli_argbrds()\n");
-#endif
+       stlconf_t conf;
+       stlibrd_t *brdp;
+       int i;
 
        for (i = stli_nrbrds; i < ARRAY_SIZE(stli_brdsp); i++) {
                memset(&conf, 0, sizeof(conf));
                if (stli_parsebrd(&conf, stli_brdsp[i]) == 0)
                        continue;
-               if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
+               if ((brdp = stli_allocbrd()) == NULL)
                        continue;
                stli_nrbrds = i + 1;
                brdp->brdnr = i;
@@ -926,9 +896,9 @@ static void stli_argbrds(void)
 
 static unsigned long stli_atol(char *str)
 {
-       unsigned long   val;
-       int             base, c;
-       char            *sp;
+       unsigned long val;
+       int base, c;
+       char *sp;
 
        val = 0;
        sp = str;
@@ -962,15 +932,11 @@ static unsigned long stli_atol(char *str)
 
 static int stli_parsebrd(stlconf_t *confp, char **argp)
 {
-       char    *sp;
-       int     i;
-
-#ifdef DEBUG
-       printk("stli_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);
-#endif
+       char *sp;
+       int i;
 
-       if ((argp[0] == (char *) NULL) || (*argp[0] == 0))
-               return(0);
+       if (argp[0] == NULL || *argp[0] == 0)
+               return 0;
 
        for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
                *sp = TOLOWER(*sp);
@@ -985,9 +951,9 @@ static int stli_parsebrd(stlconf_t *confp, char **argp)
        }
 
        confp->brdtype = stli_brdstr[i].type;
-       if ((argp[1] != (char *) NULL) && (*argp[1] != 0))
+       if (argp[1] != NULL && *argp[1] != 0)
                confp->ioaddr1 = stli_atol(argp[1]);
-       if ((argp[2] != (char *) NULL) && (*argp[2] != 0))
+       if (argp[2] !=  NULL && *argp[2] != 0)
                confp->memaddr = stli_atol(argp[2]);
        return(1);
 }
@@ -998,34 +964,29 @@ static int stli_parsebrd(stlconf_t *confp, char **argp)
 
 static int stli_open(struct tty_struct *tty, struct file *filp)
 {
-       stlibrd_t       *brdp;
-       stliport_t      *portp;
-       unsigned int    minordev;
-       int             brdnr, portnr, rc;
-
-#ifdef DEBUG
-       printk("stli_open(tty=%x,filp=%x): device=%s\n", (int) tty,
-               (int) filp, tty->name);
-#endif
+       stlibrd_t *brdp;
+       stliport_t *portp;
+       unsigned int minordev;
+       int brdnr, portnr, rc;
 
        minordev = tty->index;
        brdnr = MINOR2BRD(minordev);
        if (brdnr >= stli_nrbrds)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
        if ((brdp->state & BST_STARTED) == 0)
-               return(-ENODEV);
+               return -ENODEV;
        portnr = MINOR2PORT(minordev);
        if ((portnr < 0) || (portnr > brdp->nrports))
-               return(-ENODEV);
+               return -ENODEV;
 
        portp = brdp->ports[portnr];
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
+       if (portp == NULL)
+               return -ENODEV;
        if (portp->devnr < 1)
-               return(-ENODEV);
+               return -ENODEV;
 
 
 /*
@@ -1037,8 +998,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        if (portp->flags & ASYNC_CLOSING) {
                interruptible_sleep_on(&portp->close_wait);
                if (portp->flags & ASYNC_HUP_NOTIFY)
-                       return(-EAGAIN);
-               return(-ERESTARTSYS);
+                       return -EAGAIN;
+               return -ERESTARTSYS;
        }
 
 /*
@@ -1054,7 +1015,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_INITIALIZING, &portp->state));
        if (signal_pending(current))
-               return(-ERESTARTSYS);
+               return -ERESTARTSYS;
 
        if ((portp->flags & ASYNC_INITIALIZED) == 0) {
                set_bit(ST_INITIALIZING, &portp->state);
@@ -1065,7 +1026,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
                clear_bit(ST_INITIALIZING, &portp->state);
                wake_up_interruptible(&portp->raw_wait);
                if (rc < 0)
-                       return(rc);
+                       return rc;
        }
 
 /*
@@ -1077,8 +1038,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        if (portp->flags & ASYNC_CLOSING) {
                interruptible_sleep_on(&portp->close_wait);
                if (portp->flags & ASYNC_HUP_NOTIFY)
-                       return(-EAGAIN);
-               return(-ERESTARTSYS);
+                       return -EAGAIN;
+               return -ERESTARTSYS;
        }
 
 /*
@@ -1088,38 +1049,33 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
  */
        if (!(filp->f_flags & O_NONBLOCK)) {
                if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
-                       return(rc);
+                       return rc;
        }
        portp->flags |= ASYNC_NORMAL_ACTIVE;
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
 
 static void stli_close(struct tty_struct *tty, struct file *filp)
 {
-       stlibrd_t       *brdp;
-       stliport_t      *portp;
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk("stli_close(tty=%x,filp=%x)\n", (int) tty, (int) filp);
-#endif
+       stlibrd_t *brdp;
+       stliport_t *portp;
+       unsigned long flags;
 
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&stli_lock, flags);
        if (tty_hung_up_p(filp)) {
-               restore_flags(flags);
+               spin_unlock_irqrestore(&stli_lock, flags);
                return;
        }
        if ((tty->count == 1) && (portp->refcount != 1))
                portp->refcount = 1;
        if (portp->refcount-- > 1) {
-               restore_flags(flags);
+               spin_unlock_irqrestore(&stli_lock, flags);
                return;
        }
 
@@ -1134,6 +1090,8 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        if (tty == stli_txcooktty)
                stli_flushchars(tty);
        tty->closing = 1;
+       spin_unlock_irqrestore(&stli_lock, flags);
+
        if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
                tty_wait_until_sent(tty, portp->closing_wait);
 
@@ -1157,7 +1115,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        stli_flushbuffer(tty);
 
        tty->closing = 0;
-       portp->tty = (struct tty_struct *) NULL;
+       portp->tty = NULL;
 
        if (portp->openwaitcnt) {
                if (portp->close_delay)
@@ -1167,7 +1125,6 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
 
        portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
        wake_up_interruptible(&portp->close_wait);
-       restore_flags(flags);
 }
 
 /*****************************************************************************/
@@ -1182,45 +1139,41 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
 
 static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
 {
-       struct tty_struct       *tty;
-       asynotify_t             nt;
-       asyport_t               aport;
-       int                     rc;
-
-#ifdef DEBUG
-       printk("stli_initopen(brdp=%x,portp=%x)\n", (int) brdp, (int) portp);
-#endif
+       struct tty_struct *tty;
+       asynotify_t nt;
+       asyport_t aport;
+       int rc;
 
        if ((rc = stli_rawopen(brdp, portp, 0, 1)) < 0)
-               return(rc);
+               return rc;
 
        memset(&nt, 0, sizeof(asynotify_t));
        nt.data = (DT_TXLOW | DT_TXEMPTY | DT_RXBUSY | DT_RXBREAK);
        nt.signal = SG_DCD;
        if ((rc = stli_cmdwait(brdp, portp, A_SETNOTIFY, &nt,
            sizeof(asynotify_t), 0)) < 0)
-               return(rc);
+               return rc;
 
        tty = portp->tty;
-       if (tty == (struct tty_struct *) NULL)
-               return(-ENODEV);
+       if (tty == NULL)
+               return -ENODEV;
        stli_mkasyport(portp, &aport, tty->termios);
        if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
            sizeof(asyport_t), 0)) < 0)
-               return(rc);
+               return rc;
 
        set_bit(ST_GETSIGS, &portp->state);
        if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig,
            sizeof(asysigs_t), 1)) < 0)
-               return(rc);
+               return rc;
        if (test_and_clear_bit(ST_GETSIGS, &portp->state))
                portp->sigs = stli_mktiocm(portp->asig.sigvalue);
        stli_mkasysigs(&portp->asig, 1, 1);
        if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
            sizeof(asysigs_t), 0)) < 0)
-               return(rc);
+               return rc;
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -1234,22 +1187,15 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
 
 static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile cdkctrl_t      *cp;
-       volatile unsigned char  *bits;
-       unsigned long           flags;
-       int                     rc;
-
-#ifdef DEBUG
-       printk("stli_rawopen(brdp=%x,portp=%x,arg=%x,wait=%d)\n",
-               (int) brdp, (int) portp, (int) arg, wait);
-#endif
+       cdkhdr_t __iomem *hdrp;
+       cdkctrl_t __iomem *cp;
+       unsigned char __iomem *bits;
+       unsigned long flags;
+       int rc;
 
 /*
  *     Send a message to the slave to open this port.
  */
-       save_flags(flags);
-       cli();
 
 /*
  *     Slave is already closing this port. This can happen if a hangup
@@ -1260,7 +1206,6 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_CLOSING, &portp->state));
        if (signal_pending(current)) {
-               restore_flags(flags);
                return -ERESTARTSYS;
        }
 
@@ -1269,19 +1214,20 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
  *     memory. Once the message is in set the service bits to say that
  *     this port wants service.
  */
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
-       cp->openarg = arg;
-       cp->open = 1;
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+       writel(arg, &cp->openarg);
+       writeb(1, &cp->open);
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) | portp->portbit, bits);
        EBRDDISABLE(brdp);
 
        if (wait == 0) {
-               restore_flags(flags);
-               return(0);
+               spin_unlock_irqrestore(&brd_lock, flags);
+               return 0;
        }
 
 /*
@@ -1290,15 +1236,16 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
  */
        rc = 0;
        set_bit(ST_OPENING, &portp->state);
+       spin_unlock_irqrestore(&brd_lock, flags);
+
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_OPENING, &portp->state));
        if (signal_pending(current))
                rc = -ERESTARTSYS;
-       restore_flags(flags);
 
        if ((rc == 0) && (portp->rc != 0))
                rc = -EIO;
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -1311,19 +1258,11 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
 
 static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile cdkctrl_t      *cp;
-       volatile unsigned char  *bits;
-       unsigned long           flags;
-       int                     rc;
-
-#ifdef DEBUG
-       printk("stli_rawclose(brdp=%x,portp=%x,arg=%x,wait=%d)\n",
-               (int) brdp, (int) portp, (int) arg, wait);
-#endif
-
-       save_flags(flags);
-       cli();
+       cdkhdr_t __iomem *hdrp;
+       cdkctrl_t __iomem *cp;
+       unsigned char __iomem *bits;
+       unsigned long flags;
+       int rc;
 
 /*
  *     Slave is already closing this port. This can happen if a hangup
@@ -1333,7 +1272,6 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
                wait_event_interruptible(portp->raw_wait,
                                !test_bit(ST_CLOSING, &portp->state));
                if (signal_pending(current)) {
-                       restore_flags(flags);
                        return -ERESTARTSYS;
                }
        }
@@ -1341,21 +1279,22 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
 /*
  *     Write the close command into shared memory.
  */
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
-       cp->closearg = arg;
-       cp->close = 1;
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+       writel(arg, &cp->closearg);
+       writeb(1, &cp->close);
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) |portp->portbit, bits);
        EBRDDISABLE(brdp);
 
        set_bit(ST_CLOSING, &portp->state);
-       if (wait == 0) {
-               restore_flags(flags);
-               return(0);
-       }
+       spin_unlock_irqrestore(&brd_lock, flags);
+
+       if (wait == 0)
+               return 0;
 
 /*
  *     Slave is in action, so now we must wait for the open acknowledgment
@@ -1366,11 +1305,10 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
                        !test_bit(ST_CLOSING, &portp->state));
        if (signal_pending(current))
                rc = -ERESTARTSYS;
-       restore_flags(flags);
 
        if ((rc == 0) && (portp->rc != 0))
                rc = -EIO;
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -1384,36 +1322,21 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
 
 static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
 {
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk("stli_cmdwait(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"
-               "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,
-               (int) arg, size, copyback);
-#endif
-
-       save_flags(flags);
-       cli();
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_CMDING, &portp->state));
-       if (signal_pending(current)) {
-               restore_flags(flags);
+       if (signal_pending(current))
                return -ERESTARTSYS;
-       }
 
        stli_sendcmd(brdp, portp, cmd, arg, size, copyback);
 
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_CMDING, &portp->state));
-       if (signal_pending(current)) {
-               restore_flags(flags);
+       if (signal_pending(current))
                return -ERESTARTSYS;
-       }
-       restore_flags(flags);
 
        if (portp->rc != 0)
-               return(-EIO);
-       return(0);
+               return -EIO;
+       return 0;
 }
 
 /*****************************************************************************/
@@ -1425,22 +1348,18 @@ static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, v
 
 static int stli_setport(stliport_t *portp)
 {
-       stlibrd_t       *brdp;
-       asyport_t       aport;
-
-#ifdef DEBUG
-       printk("stli_setport(portp=%x)\n", (int) portp);
-#endif
+       stlibrd_t *brdp;
+       asyport_t aport;
 
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
-       if (portp->tty == (struct tty_struct *) NULL)
-               return(-ENODEV);
-       if ((portp->brdnr < 0) && (portp->brdnr >= stli_nrbrds))
-               return(-ENODEV);
+       if (portp == NULL)
+               return -ENODEV;
+       if (portp->tty == NULL)
+               return -ENODEV;
+       if (portp->brdnr < 0 && portp->brdnr >= stli_nrbrds)
+               return -ENODEV;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
 
        stli_mkasyport(portp, &aport, portp->tty->termios);
        return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
@@ -1455,13 +1374,8 @@ static int stli_setport(stliport_t *portp)
 
 static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp)
 {
-       unsigned long   flags;
-       int             rc, doclocal;
-
-#ifdef DEBUG
-       printk("stli_waitcarrier(brdp=%x,portp=%x,filp=%x)\n",
-               (int) brdp, (int) portp, (int) filp);
-#endif
+       unsigned long flags;
+       int rc, doclocal;
 
        rc = 0;
        doclocal = 0;
@@ -1469,11 +1383,11 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
        if (portp->tty->termios->c_cflag & CLOCAL)
                doclocal++;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&stli_lock, flags);
        portp->openwaitcnt++;
        if (! tty_hung_up_p(filp))
                portp->refcount--;
+       spin_unlock_irqrestore(&stli_lock, flags);
 
        for (;;) {
                stli_mkasysigs(&portp->asig, 1, 1);
@@ -1499,12 +1413,13 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
                interruptible_sleep_on(&portp->open_wait);
        }
 
+       spin_lock_irqsave(&stli_lock, flags);
        if (! tty_hung_up_p(filp))
                portp->refcount++;
        portp->openwaitcnt--;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&stli_lock, flags);
 
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -1517,46 +1432,38 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
 
 static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-       volatile cdkasy_t       *ap;
-       volatile cdkhdr_t       *hdrp;
-       volatile unsigned char  *bits;
-       unsigned char           *shbuf, *chbuf;
-       stliport_t              *portp;
-       stlibrd_t               *brdp;
-       unsigned int            len, stlen, head, tail, size;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk("stli_write(tty=%x,buf=%x,count=%d)\n",
-               (int) tty, (int) buf, count);
-#endif
+       cdkasy_t __iomem *ap;
+       cdkhdr_t __iomem *hdrp;
+       unsigned char __iomem *bits;
+       unsigned char __iomem *shbuf;
+       unsigned char *chbuf;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int len, stlen, head, tail, size;
+       unsigned long flags;
 
-       if ((tty == (struct tty_struct *) NULL) ||
-           (stli_tmpwritebuf == (char *) NULL))
-               return(0);
        if (tty == stli_txcooktty)
                stli_flushchars(tty);
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return(0);
+       if (portp == NULL)
+               return 0;
        if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
        chbuf = (unsigned char *) buf;
 
 /*
  *     All data is now local, shove as much as possible into shared memory.
  */
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-       head = (unsigned int) ap->txq.head;
-       tail = (unsigned int) ap->txq.tail;
-       if (tail != ((unsigned int) ap->txq.tail))
-               tail = (unsigned int) ap->txq.tail;
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+       head = (unsigned int) readw(&ap->txq.head);
+       tail = (unsigned int) readw(&ap->txq.tail);
+       if (tail != ((unsigned int) readw(&ap->txq.tail)))
+               tail = (unsigned int) readw(&ap->txq.tail);
        size = portp->txsize;
        if (head >= tail) {
                len = size - (head - tail) - 1;
@@ -1568,11 +1475,11 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
 
        len = MIN(len, count);
        count = 0;
-       shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset);
+       shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->txoffset);
 
        while (len > 0) {
                stlen = MIN(len, stlen);
-               memcpy((shbuf + head), chbuf, stlen);
+               memcpy_toio(shbuf + head, chbuf, stlen);
                chbuf += stlen;
                len -= stlen;
                count += stlen;
@@ -1583,20 +1490,19 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
                }
        }
 
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-       ap->txq.head = head;
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+       writew(head, &ap->txq.head);
        if (test_bit(ST_TXBUSY, &portp->state)) {
-               if (ap->changed.data & DT_TXEMPTY)
-                       ap->changed.data &= ~DT_TXEMPTY;
+               if (readl(&ap->changed.data) & DT_TXEMPTY)
+                       writel(readl(&ap->changed.data) & ~DT_TXEMPTY, &ap->changed.data);
        }
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) | portp->portbit, bits);
        set_bit(ST_TXBUSY, &portp->state);
        EBRDDISABLE(brdp);
-
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        return(count);
 }
@@ -1613,14 +1519,8 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
 
 static void stli_putchar(struct tty_struct *tty, unsigned char ch)
 {
-#ifdef DEBUG
-       printk("stli_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
        if (tty != stli_txcooktty) {
-               if (stli_txcooktty != (struct tty_struct *) NULL)
+               if (stli_txcooktty != NULL)
                        stli_flushchars(stli_txcooktty);
                stli_txcooktty = tty;
        }
@@ -1640,29 +1540,26 @@ static void stli_putchar(struct tty_struct *tty, unsigned char ch)
 
 static void stli_flushchars(struct tty_struct *tty)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile unsigned char  *bits;
-       volatile cdkasy_t       *ap;
-       struct tty_struct       *cooktty;
-       stliport_t              *portp;
-       stlibrd_t               *brdp;
-       unsigned int            len, stlen, head, tail, size, count, cooksize;
-       unsigned char           *buf, *shbuf;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk("stli_flushchars(tty=%x)\n", (int) tty);
-#endif
+       cdkhdr_t __iomem *hdrp;
+       unsigned char __iomem *bits;
+       cdkasy_t __iomem *ap;
+       struct tty_struct *cooktty;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int len, stlen, head, tail, size, count, cooksize;
+       unsigned char *buf;
+       unsigned char __iomem *shbuf;
+       unsigned long flags;
 
        cooksize = stli_txcooksize;
        cooktty = stli_txcooktty;
        stli_txcooksize = 0;
        stli_txcookrealsize = 0;
-       stli_txcooktty = (struct tty_struct *) NULL;
+       stli_txcooktty = NULL;
 
-       if (tty == (struct tty_struct *) NULL)
+       if (tty == NULL)
                return;
-       if (cooktty == (struct tty_struct *) NULL)
+       if (cooktty == NULL)
                return;
        if (tty != cooktty)
                tty = cooktty;
@@ -1670,23 +1567,22 @@ static void stli_flushchars(struct tty_struct *tty)
                return;
 
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
        if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
 
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-       head = (unsigned int) ap->txq.head;
-       tail = (unsigned int) ap->txq.tail;
-       if (tail != ((unsigned int) ap->txq.tail))
-               tail = (unsigned int) ap->txq.tail;
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+       head = (unsigned int) readw(&ap->txq.head);
+       tail = (unsigned int) readw(&ap->txq.tail);
+       if (tail != ((unsigned int) readw(&ap->txq.tail)))
+               tail = (unsigned int) readw(&ap->txq.tail);
        size = portp->txsize;
        if (head >= tail) {
                len = size - (head - tail) - 1;
@@ -1703,7 +1599,7 @@ static void stli_flushchars(struct tty_struct *tty)
 
        while (len > 0) {
                stlen = MIN(len, stlen);
-               memcpy((shbuf + head), buf, stlen);
+               memcpy_toio(shbuf + head, buf, stlen);
                buf += stlen;
                len -= stlen;
                count += stlen;
@@ -1714,73 +1610,66 @@ static void stli_flushchars(struct tty_struct *tty)
                }
        }
 
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-       ap->txq.head = head;
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+       writew(head, &ap->txq.head);
 
        if (test_bit(ST_TXBUSY, &portp->state)) {
-               if (ap->changed.data & DT_TXEMPTY)
-                       ap->changed.data &= ~DT_TXEMPTY;
+               if (readl(&ap->changed.data) & DT_TXEMPTY)
+                       writel(readl(&ap->changed.data) & ~DT_TXEMPTY, &ap->changed.data);
        }
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) | portp->portbit, bits);
        set_bit(ST_TXBUSY, &portp->state);
 
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
 
 static int stli_writeroom(struct tty_struct *tty)
 {
-       volatile cdkasyrq_t     *rp;
-       stliport_t              *portp;
-       stlibrd_t               *brdp;
-       unsigned int            head, tail, len;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk("stli_writeroom(tty=%x)\n", (int) tty);
-#endif
+       cdkasyrq_t __iomem *rp;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int head, tail, len;
+       unsigned long flags;
 
-       if (tty == (struct tty_struct *) NULL)
-               return(0);
        if (tty == stli_txcooktty) {
                if (stli_txcookrealsize != 0) {
                        len = stli_txcookrealsize - stli_txcooksize;
-                       return(len);
+                       return len;
                }
        }
 
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return(0);
+       if (portp == NULL)
+               return 0;
        if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
-       head = (unsigned int) rp->head;
-       tail = (unsigned int) rp->tail;
-       if (tail != ((unsigned int) rp->tail))
-               tail = (unsigned int) rp->tail;
+       rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
+       head = (unsigned int) readw(&rp->head);
+       tail = (unsigned int) readw(&rp->tail);
+       if (tail != ((unsigned int) readw(&rp->tail)))
+               tail = (unsigned int) readw(&rp->tail);
        len = (head >= tail) ? (portp->txsize - (head - tail)) : (tail - head);
        len--;
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        if (tty == stli_txcooktty) {
                stli_txcookrealsize = len;
                len -= stli_txcooksize;
        }
-       return(len);
+       return len;
 }
 
 /*****************************************************************************/
@@ -1795,44 +1684,37 @@ static int stli_writeroom(struct tty_struct *tty)
 
 static int stli_charsinbuffer(struct tty_struct *tty)
 {
-       volatile cdkasyrq_t     *rp;
-       stliport_t              *portp;
-       stlibrd_t               *brdp;
-       unsigned int            head, tail, len;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk("stli_charsinbuffer(tty=%x)\n", (int) tty);
-#endif
+       cdkasyrq_t __iomem *rp;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int head, tail, len;
+       unsigned long flags;
 
-       if (tty == (struct tty_struct *) NULL)
-               return(0);
        if (tty == stli_txcooktty)
                stli_flushchars(tty);
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return(0);
+       if (portp == NULL)
+               return 0;
        if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
-       head = (unsigned int) rp->head;
-       tail = (unsigned int) rp->tail;
-       if (tail != ((unsigned int) rp->tail))
-               tail = (unsigned int) rp->tail;
+       rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
+       head = (unsigned int) readw(&rp->head);
+       tail = (unsigned int) readw(&rp->tail);
+       if (tail != ((unsigned int) readw(&rp->tail)))
+               tail = (unsigned int) readw(&rp->tail);
        len = (head >= tail) ? (head - tail) : (portp->txsize - (tail - head));
        if ((len == 0) && test_bit(ST_TXBUSY, &portp->state))
                len = 1;
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
-       return(len);
+       return len;
 }
 
 /*****************************************************************************/
@@ -1843,12 +1725,8 @@ static int stli_charsinbuffer(struct tty_struct *tty)
 
 static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
 {
-       struct serial_struct    sio;
-       stlibrd_t               *brdp;
-
-#ifdef DEBUG
-       printk("stli_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
-#endif
+       struct serial_struct sio;
+       stlibrd_t *brdp;
 
        memset(&sio, 0, sizeof(struct serial_struct));
        sio.type = PORT_UNKNOWN;
@@ -1863,7 +1741,7 @@ static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
        sio.hub6 = 0;
 
        brdp = stli_brds[portp->brdnr];
-       if (brdp != (stlibrd_t *) NULL)
+       if (brdp != NULL)
                sio.port = brdp->iobase;
                
        return copy_to_user(sp, &sio, sizeof(struct serial_struct)) ?
@@ -1880,12 +1758,8 @@ static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
 
 static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
 {
-       struct serial_struct    sio;
-       int                     rc;
-
-#ifdef DEBUG
-       printk("stli_setserial(portp=%p,sp=%p)\n", portp, sp);
-#endif
+       struct serial_struct sio;
+       int rc;
 
        if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
                return -EFAULT;
@@ -1894,7 +1768,7 @@ static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
                    (sio.close_delay != portp->close_delay) ||
                    ((sio.flags & ~ASYNC_USR_MASK) !=
                    (portp->flags & ~ASYNC_USR_MASK)))
-                       return(-EPERM);
+                       return -EPERM;
        } 
 
        portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
@@ -1905,8 +1779,8 @@ static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
        portp->custom_divisor = sio.custom_divisor;
 
        if ((rc = stli_setport(portp)) < 0)
-               return(rc);
-       return(0);
+               return rc;
+       return 0;
 }
 
 /*****************************************************************************/
@@ -1917,19 +1791,19 @@ static int stli_tiocmget(struct tty_struct *tty, struct file *file)
        stlibrd_t *brdp;
        int rc;
 
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+       if (portp == NULL)
+               return -ENODEV;
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
        if (tty->flags & (1 << TTY_IO_ERROR))
-               return(-EIO);
+               return -EIO;
 
        if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS,
                               &portp->asig, sizeof(asysigs_t), 1)) < 0)
-               return(rc);
+               return rc;
 
        return stli_mktiocm(portp->asig.sigvalue);
 }
@@ -1941,15 +1815,15 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file,
        stlibrd_t *brdp;
        int rts = -1, dtr = -1;
 
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+       if (portp == NULL)
+               return -ENODEV;
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
        if (tty->flags & (1 << TTY_IO_ERROR))
-               return(-EIO);
+               return -EIO;
 
        if (set & TIOCM_RTS)
                rts = 1;
@@ -1968,32 +1842,25 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file,
 
 static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       unsigned int    ival;
-       int             rc;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int ival;
+       int rc;
        void __user *argp = (void __user *)arg;
 
-#ifdef DEBUG
-       printk("stli_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",
-               (int) tty, (int) file, cmd, (int) arg);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return(-ENODEV);
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+       if (portp == NULL)
+               return -ENODEV;
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
                if (tty->flags & (1 << TTY_IO_ERROR))
-                       return(-EIO);
+                       return -EIO;
        }
 
        rc = 0;
@@ -2040,7 +1907,7 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                break;
        }
 
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -2052,24 +1919,20 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
 
 static void stli_settermios(struct tty_struct *tty, struct termios *old)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       struct termios  *tiosp;
-       asyport_t       aport;
-
-#ifdef DEBUG
-       printk("stli_settermios(tty=%x,old=%x)\n", (int) tty, (int) old);
-#endif
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       struct termios *tiosp;
+       asyport_t aport;
 
-       if (tty == (struct tty_struct *) NULL)
+       if (tty == NULL)
                return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
        tiosp = tty->termios;
@@ -2102,18 +1965,9 @@ static void stli_settermios(struct tty_struct *tty, struct termios *old)
 
 static void stli_throttle(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-
-#ifdef DEBUG
-       printk("stli_throttle(tty=%x)\n", (int) tty);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
-       portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       stliport_t      *portp = tty->driver_data;
+       if (portp == NULL)
                return;
-
        set_bit(ST_RXSTOP, &portp->state);
 }
 
@@ -2127,88 +1981,30 @@ static void stli_throttle(struct tty_struct *tty)
 
 static void stli_unthrottle(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-
-#ifdef DEBUG
-       printk("stli_unthrottle(tty=%x)\n", (int) tty);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
+       stliport_t      *portp = tty->driver_data;
+       if (portp == NULL)
                return;
-       portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return;
-
        clear_bit(ST_RXSTOP, &portp->state);
 }
 
 /*****************************************************************************/
 
 /*
- *     Stop the transmitter. Basically to do this we will just turn TX
- *     interrupts off.
+ *     Stop the transmitter.
  */
 
 static void stli_stop(struct tty_struct *tty)
 {
-       stlibrd_t       *brdp;
-       stliport_t      *portp;
-       asyctrl_t       actrl;
-
-#ifdef DEBUG
-       printk("stli_stop(tty=%x)\n", (int) tty);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
-       portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return;
-       brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return;
-
-       memset(&actrl, 0, sizeof(asyctrl_t));
-       actrl.txctrl = CT_STOPFLOW;
-#if 0
-       stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
-#endif
 }
 
 /*****************************************************************************/
 
 /*
- *     Start the transmitter again. Just turn TX interrupts back on.
+ *     Start the transmitter again.
  */
 
 static void stli_start(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       asyctrl_t       actrl;
-
-#ifdef DEBUG
-       printk("stli_start(tty=%x)\n", (int) tty);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
-       portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return;
-       brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return;
-
-       memset(&actrl, 0, sizeof(asyctrl_t));
-       actrl.txctrl = CT_STARTFLOW;
-#if 0
-       stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
-#endif
 }
 
 /*****************************************************************************/
@@ -2224,22 +2020,9 @@ static void stli_start(struct tty_struct *tty)
 
 static void stli_dohangup(void *arg)
 {
-       stliport_t      *portp;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_dohangup(portp=%x)\n", (int) arg);
-#endif
-
-       /*
-        * FIXME: There's a module removal race here: tty_hangup
-        * calls schedule_work which will call into this
-        * driver later.
-        */
-       portp = (stliport_t *) arg;
-       if (portp != (stliport_t *) NULL) {
-               if (portp->tty != (struct tty_struct *) NULL) {
-                       tty_hangup(portp->tty);
-               }
+       stliport_t *portp = (stliport_t *) arg;
+       if (portp->tty != NULL) {
+               tty_hangup(portp->tty);
        }
 }
 
@@ -2254,31 +2037,25 @@ static void stli_dohangup(void *arg)
 
 static void stli_hangup(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_hangup(tty=%x)\n", (int) tty);
-#endif
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned long flags;
 
-       if (tty == (struct tty_struct *) NULL)
-               return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
        portp->flags &= ~ASYNC_INITIALIZED;
 
-       save_flags(flags);
-       cli();
-       if (! test_bit(ST_CLOSING, &portp->state))
+       if (!test_bit(ST_CLOSING, &portp->state))
                stli_rawclose(brdp, portp, 0, 0);
+
+       spin_lock_irqsave(&stli_lock, flags);
        if (tty->termios->c_cflag & HUPCL) {
                stli_mkasysigs(&portp->asig, 0, 0);
                if (test_bit(ST_CMDING, &portp->state)) {
@@ -2290,14 +2067,15 @@ static void stli_hangup(struct tty_struct *tty)
                                &portp->asig, sizeof(asysigs_t), 0);
                }
        }
-       restore_flags(flags);
 
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
        set_bit(TTY_IO_ERROR, &tty->flags);
-       portp->tty = (struct tty_struct *) NULL;
+       portp->tty = NULL;
        portp->flags &= ~ASYNC_NORMAL_ACTIVE;
        portp->refcount = 0;
+       spin_unlock_irqrestore(&stli_lock, flags);
+
        wake_up_interruptible(&portp->open_wait);
 }
 
@@ -2312,29 +2090,22 @@ static void stli_hangup(struct tty_struct *tty)
 
 static void stli_flushbuffer(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       unsigned long   ftype, flags;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_flushbuffer(tty=%x)\n", (int) tty);
-#endif
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned long ftype, flags;
 
-       if (tty == (struct tty_struct *) NULL)
-               return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        if (tty == stli_txcooktty) {
-               stli_txcooktty = (struct tty_struct *) NULL;
+               stli_txcooktty = NULL;
                stli_txcooksize = 0;
                stli_txcookrealsize = 0;
        }
@@ -2346,15 +2117,10 @@ static void stli_flushbuffer(struct tty_struct *tty)
                        ftype |= FLUSHRX;
                        clear_bit(ST_DOFLUSHRX, &portp->state);
                }
-               stli_sendcmd(brdp, portp, A_FLUSH, &ftype,
-                       sizeof(unsigned long), 0);
+               __stli_sendcmd(brdp, portp, A_FLUSH, &ftype, sizeof(u32), 0);
        }
-       restore_flags(flags);
-
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       spin_unlock_irqrestore(&brd_lock, flags);
+       tty_wakeup(tty);
 }
 
 /*****************************************************************************/
@@ -2364,55 +2130,31 @@ static void stli_breakctl(struct tty_struct *tty, int state)
        stlibrd_t       *brdp;
        stliport_t      *portp;
        long            arg;
-       /* long savestate, savetime; */
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_breakctl(tty=%x,state=%d)\n", (int) tty, state);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
-/*
- *     Due to a bug in the tty send_break() code we need to preserve
- *     the current process state and timeout...
-       savetime = current->timeout;
-       savestate = current->state;
- */
-
        arg = (state == -1) ? BREAKON : BREAKOFF;
        stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0);
-
-/*
- *
-       current->timeout = savetime;
-       current->state = savestate;
- */
 }
 
 /*****************************************************************************/
 
 static void stli_waituntilsent(struct tty_struct *tty, int timeout)
 {
-       stliport_t      *portp;
-       unsigned long   tend;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_waituntilsent(tty=%x,timeout=%x)\n", (int) tty, timeout);
-#endif
+       stliport_t *portp;
+       unsigned long tend;
 
-       if (tty == (struct tty_struct *) NULL)
+       if (tty == NULL)
                return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
 
        if (timeout == 0)
@@ -2436,19 +2178,13 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
        stliport_t      *portp;
        asyctrl_t       actrl;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
        memset(&actrl, 0, sizeof(asyctrl_t));
@@ -2460,7 +2196,6 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
                actrl.txctrl = CT_SENDCHR;
                actrl.tximdch = ch;
        }
-
        stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
 }
 
@@ -2476,17 +2211,17 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
 
 static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos)
 {
-       char    *sp, *uart;
-       int     rc, cnt;
+       char *sp, *uart;
+       int rc, cnt;
 
        rc = stli_portcmdstats(portp);
 
        uart = "UNKNOWN";
        if (brdp->state & BST_STARTED) {
                switch (stli_comstats.hwid) {
-               case 0:         uart = "2681"; break;
-               case 1:         uart = "SC26198"; break;
-               default:        uart = "CD1400"; break;
+               case 0: uart = "2681"; break;
+               case 1: uart = "SC26198"; break;
+               default:uart = "CD1400"; break;
                }
        }
 
@@ -2537,17 +2272,11 @@ static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *p
 
 static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-       stlibrd_t       *brdp;
-       stliport_t      *portp;
-       int             brdnr, portnr, totalport;
-       int             curoff, maxoff;
-       char            *pos;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x,"
-               "data=%x\n", (int) page, (int) start, (int) off, count,
-               (int) eof, (int) data);
-#endif
+       stlibrd_t *brdp;
+       stliport_t *portp;
+       int brdnr, portnr, totalport;
+       int curoff, maxoff;
+       char *pos;
 
        pos = page;
        totalport = 0;
@@ -2568,7 +2297,7 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
  */
        for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) {
                brdp = stli_brds[brdnr];
-               if (brdp == (stlibrd_t *) NULL)
+               if (brdp == NULL)
                        continue;
                if (brdp->state == 0)
                        continue;
@@ -2583,7 +2312,7 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
                for (portnr = 0; (portnr < brdp->nrports); portnr++,
                    totalport++) {
                        portp = brdp->ports[portnr];
-                       if (portp == (stliport_t *) NULL)
+                       if (portp == NULL)
                                continue;
                        if (off >= (curoff += MAXLINE))
                                continue;
@@ -2610,49 +2339,54 @@ stli_readdone:
  *     a poll routine that does not have user context. Therefore you cannot
  *     copy back directly into user space, or to the kernel stack of a
  *     process. This routine does not sleep, so can be called from anywhere.
+ *
+ *     The caller must hold the brd_lock (see also stli_sendcmd the usual
+ *     entry point)
  */
 
-static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile cdkctrl_t      *cp;
-       volatile unsigned char  *bits;
-       unsigned long           flags;
+       cdkhdr_t __iomem *hdrp;
+       cdkctrl_t __iomem *cp;
+       unsigned char __iomem *bits;
+       unsigned long flags;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"
-               "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,
-               (int) arg, size, copyback);
-#endif
-
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
 
        if (test_bit(ST_CMDING, &portp->state)) {
                printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n",
                                (int) cmd);
-               restore_flags(flags);
+               spin_unlock_irqrestore(&brd_lock, flags);
                return;
        }
 
        EBRDENABLE(brdp);
-       cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+       cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
        if (size > 0) {
-               memcpy((void *) &(cp->args[0]), arg, size);
+               memcpy_toio((void __iomem *) &(cp->args[0]), arg, size);
                if (copyback) {
                        portp->argp = arg;
                        portp->argsize = size;
                }
        }
-       cp->status = 0;
-       cp->cmd = cmd;
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       writel(0, &cp->status);
+       writel(cmd, &cp->cmd);
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) | portp->portbit, bits);
        set_bit(ST_CMDING, &portp->state);
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
+}
+
+static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+{
+       unsigned long           flags;
+
+       spin_lock_irqsave(&brd_lock, flags);
+       __stli_sendcmd(brdp, portp, cmd, arg, size, copyback);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -2667,28 +2401,23 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd,
 
 static void stli_read(stlibrd_t *brdp, stliport_t *portp)
 {
-       volatile cdkasyrq_t     *rp;
-       volatile char           *shbuf;
+       cdkasyrq_t __iomem *rp;
+       char __iomem *shbuf;
        struct tty_struct       *tty;
-       unsigned int            head, tail, size;
-       unsigned int            len, stlen;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_read(brdp=%x,portp=%d)\n",
-                       (int) brdp, (int) portp);
-#endif
+       unsigned int head, tail, size;
+       unsigned int len, stlen;
 
        if (test_bit(ST_RXSTOP, &portp->state))
                return;
        tty = portp->tty;
-       if (tty == (struct tty_struct *) NULL)
+       if (tty == NULL)
                return;
 
-       rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
-       head = (unsigned int) rp->head;
-       if (head != ((unsigned int) rp->head))
-               head = (unsigned int) rp->head;
-       tail = (unsigned int) rp->tail;
+       rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
+       head = (unsigned int) readw(&rp->head);
+       if (head != ((unsigned int) readw(&rp->head)))
+               head = (unsigned int) readw(&rp->head);
+       tail = (unsigned int) readw(&rp->tail);
        size = portp->rxsize;
        if (head >= tail) {
                len = head - tail;
@@ -2699,12 +2428,15 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
        }
 
        len = tty_buffer_request_room(tty, len);
-       /* FIXME : iomap ? */
-       shbuf = (volatile char *) EBRDGETMEMPTR(brdp, portp->rxoffset);
+
+       shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->rxoffset);
 
        while (len > 0) {
+               unsigned char *cptr;
+
                stlen = MIN(len, stlen);
-               tty_insert_flip_string(tty, (char *)(shbuf + tail), stlen);
+               tty_prepare_flip_string(tty, &cptr, stlen);
+               memcpy_fromio(cptr, shbuf + tail, stlen);
                len -= stlen;
                tail += stlen;
                if (tail >= size) {
@@ -2712,8 +2444,8 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
                        stlen = head;
                }
        }
-       rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
-       rp->tail = tail;
+       rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
+       writew(tail, &rp->tail);
 
        if (head != tail)
                set_bit(ST_RXING, &portp->state);
@@ -2729,9 +2461,9 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
  *     difficult to deal with them here.
  */
 
-static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
+static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp)
 {
-       int     cmd;
+       int cmd;
 
        if (test_bit(ST_DOSIGS, &portp->state)) {
                if (test_bit(ST_DOFLUSHTX, &portp->state) &&
@@ -2746,10 +2478,10 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
                clear_bit(ST_DOFLUSHTX, &portp->state);
                clear_bit(ST_DOFLUSHRX, &portp->state);
                clear_bit(ST_DOSIGS, &portp->state);
-               memcpy((void *) &(cp->args[0]), (void *) &portp->asig,
+               memcpy_toio((void __iomem *) &(cp->args[0]), (void *) &portp->asig,
                        sizeof(asysigs_t));
-               cp->status = 0;
-               cp->cmd = cmd;
+               writel(0, &cp->status);
+               writel(cmd, &cp->cmd);
                set_bit(ST_CMDING, &portp->state);
        } else if (test_bit(ST_DOFLUSHTX, &portp->state) ||
            test_bit(ST_DOFLUSHRX, &portp->state)) {
@@ -2757,9 +2489,9 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
                cmd |= ((test_bit(ST_DOFLUSHRX, &portp->state)) ? FLUSHRX : 0);
                clear_bit(ST_DOFLUSHTX, &portp->state);
                clear_bit(ST_DOFLUSHRX, &portp->state);
-               memcpy((void *) &(cp->args[0]), (void *) &cmd, sizeof(int));
-               cp->status = 0;
-               cp->cmd = A_FLUSH;
+               memcpy_toio((void __iomem *) &(cp->args[0]), (void *) &cmd, sizeof(int));
+               writel(0, &cp->status);
+               writel(A_FLUSH, &cp->cmd);
                set_bit(ST_CMDING, &portp->state);
        }
 }
@@ -2779,30 +2511,25 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
 
 static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
 {
-       volatile cdkasy_t       *ap;
-       volatile cdkctrl_t      *cp;
-       struct tty_struct       *tty;
-       asynotify_t             nt;
-       unsigned long           oldsigs;
-       int                     rc, donerx;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_hostcmd(brdp=%x,channr=%d)\n",
-                       (int) brdp, channr);
-#endif
-
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
+       cdkasy_t __iomem *ap;
+       cdkctrl_t __iomem *cp;
+       struct tty_struct *tty;
+       asynotify_t nt;
+       unsigned long oldsigs;
+       int rc, donerx;
+
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
        cp = &ap->ctrl;
 
 /*
  *     Check if we are waiting for an open completion message.
  */
        if (test_bit(ST_OPENING, &portp->state)) {
-               rc = (int) cp->openarg;
-               if ((cp->open == 0) && (rc != 0)) {
+               rc = readl(&cp->openarg);
+               if (readb(&cp->open) == 0 && rc != 0) {
                        if (rc > 0)
                                rc--;
-                       cp->openarg = 0;
+                       writel(0, &cp->openarg);
                        portp->rc = rc;
                        clear_bit(ST_OPENING, &portp->state);
                        wake_up_interruptible(&portp->raw_wait);
@@ -2813,11 +2540,11 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
  *     Check if we are waiting for a close completion message.
  */
        if (test_bit(ST_CLOSING, &portp->state)) {
-               rc = (int) cp->closearg;
-               if ((cp->close == 0) && (rc != 0)) {
+               rc = (int) readl(&cp->closearg);
+               if (readb(&cp->close) == 0 && rc != 0) {
                        if (rc > 0)
                                rc--;
-                       cp->closearg = 0;
+                       writel(0, &cp->closearg);
                        portp->rc = rc;
                        clear_bit(ST_CLOSING, &portp->state);
                        wake_up_interruptible(&portp->raw_wait);
@@ -2829,16 +2556,16 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
  *     need to copy out the command results associated with this command.
  */
        if (test_bit(ST_CMDING, &portp->state)) {
-               rc = cp->status;
-               if ((cp->cmd == 0) && (rc != 0)) {
+               rc = readl(&cp->status);
+               if (readl(&cp->cmd) == 0 && rc != 0) {
                        if (rc > 0)
                                rc--;
-                       if (portp->argp != (void *) NULL) {
-                               memcpy(portp->argp, (void *) &(cp->args[0]),
+                       if (portp->argp != NULL) {
+                               memcpy_fromio(portp->argp, (void __iomem *) &(cp->args[0]),
                                        portp->argsize);
-                               portp->argp = (void *) NULL;
+                               portp->argp = NULL;
                        }
-                       cp->status = 0;
+                       writel(0, &cp->status);
                        portp->rc = rc;
                        clear_bit(ST_CMDING, &portp->state);
                        stli_dodelaycmd(portp, cp);
@@ -2877,18 +2604,15 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
                if (nt.data & DT_TXEMPTY)
                        clear_bit(ST_TXBUSY, &portp->state);
                if (nt.data & (DT_TXEMPTY | DT_TXLOW)) {
-                       if (tty != (struct tty_struct *) NULL) {
-                               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                                   tty->ldisc.write_wakeup) {
-                                       (tty->ldisc.write_wakeup)(tty);
-                                       EBRDENABLE(brdp);
-                               }
+                       if (tty != NULL) {
+                               tty_wakeup(tty);
+                               EBRDENABLE(brdp);
                                wake_up_interruptible(&tty->write_wait);
                        }
                }
 
                if ((nt.data & DT_RXBREAK) && (portp->rxmarkmsk & BRKINT)) {
-                       if (tty != (struct tty_struct *) NULL) {
+                       if (tty != NULL) {
                                tty_insert_flip_char(tty, 0, TTY_BREAK);
                                if (portp->flags & ASYNC_SAK) {
                                        do_SAK(tty);
@@ -2932,14 +2656,14 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
  *     at the cdk header structure.
  */
 
-static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
+static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp)
 {
-       stliport_t      *portp;
-       unsigned char   hostbits[(STL_MAXCHANS / 8) + 1];
-       unsigned char   slavebits[(STL_MAXCHANS / 8) + 1];
-       unsigned char   *slavep;
-       int             bitpos, bitat, bitsize;
-       int             channr, nrdevs, slavebitchange;
+       stliport_t *portp;
+       unsigned char hostbits[(STL_MAXCHANS / 8) + 1];
+       unsigned char slavebits[(STL_MAXCHANS / 8) + 1];
+       unsigned char __iomem *slavep;
+       int bitpos, bitat, bitsize;
+       int channr, nrdevs, slavebitchange;
 
        bitsize = brdp->bitsize;
        nrdevs = brdp->nrdevs;
@@ -2951,7 +2675,7 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
  *     8 service bits at a time in the inner loop, so we can bypass
  *     the lot if none of them want service.
  */
-       memcpy(&hostbits[0], (((unsigned char *) hdrp) + brdp->hostoffset),
+       memcpy_fromio(&hostbits[0], (((unsigned char __iomem *) hdrp) + brdp->hostoffset),
                bitsize);
 
        memset(&slavebits[0], 0, bitsize);
@@ -2978,11 +2702,11 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
  *     service may initiate more slave requests.
  */
        if (slavebitchange) {
-               hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-               slavep = ((unsigned char *) hdrp) + brdp->slaveoffset;
+               hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+               slavep = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset;
                for (bitpos = 0; (bitpos < bitsize); bitpos++) {
-                       if (slavebits[bitpos])
-                               slavep[bitpos] &= ~slavebits[bitpos];
+                       if (readb(slavebits + bitpos))
+                               writeb(readb(slavep + bitpos) & ~slavebits[bitpos], slavebits + bitpos);
                }
        }
 }
@@ -3000,9 +2724,9 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
 
 static void stli_poll(unsigned long arg)
 {
-       volatile cdkhdr_t       *hdrp;
-       stlibrd_t               *brdp;
-       int                     brdnr;
+       cdkhdr_t __iomem *hdrp;
+       stlibrd_t *brdp;
+       int brdnr;
 
        stli_timerlist.expires = STLI_TIMEOUT;
        add_timer(&stli_timerlist);
@@ -3012,16 +2736,18 @@ static void stli_poll(unsigned long arg)
  */
        for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) {
                brdp = stli_brds[brdnr];
-               if (brdp == (stlibrd_t *) NULL)
+               if (brdp == NULL)
                        continue;
                if ((brdp->state & BST_STARTED) == 0)
                        continue;
 
+               spin_lock(&brd_lock);
                EBRDENABLE(brdp);
-               hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-               if (hdrp->hostreq)
+               hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+               if (readb(&hdrp->hostreq))
                        stli_brdpoll(brdp, hdrp);
                EBRDDISABLE(brdp);
+               spin_unlock(&brd_lock);
        }
 }
 
@@ -3034,11 +2760,6 @@ static void stli_poll(unsigned long arg)
 
 static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp)
 {
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_mkasyport(portp=%x,pp=%x,tiosp=%d)\n",
-               (int) portp, (int) pp, (int) tiosp);
-#endif
-
        memset(pp, 0, sizeof(asyport_t));
 
 /*
@@ -3157,11 +2878,6 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tio
 
 static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts)
 {
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_mkasysigs(sp=%x,dtr=%d,rts=%d)\n",
-                       (int) sp, dtr, rts);
-#endif
-
        memset(sp, 0, sizeof(asysigs_t));
        if (dtr >= 0) {
                sp->signal |= SG_DTR;
@@ -3182,13 +2898,7 @@ static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts)
 
 static long stli_mktiocm(unsigned long sigvalue)
 {
-       long    tiocm;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_mktiocm(sigvalue=%x)\n", (int) sigvalue);
-#endif
-
-       tiocm = 0;
+       long    tiocm = 0;
        tiocm |= ((sigvalue & SG_DCD) ? TIOCM_CD : 0);
        tiocm |= ((sigvalue & SG_CTS) ? TIOCM_CTS : 0);
        tiocm |= ((sigvalue & SG_RI) ? TIOCM_RI : 0);
@@ -3210,10 +2920,6 @@ static int stli_initports(stlibrd_t *brdp)
        stliport_t      *portp;
        int             i, panelnr, panelport;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initports(brdp=%x)\n", (int) brdp);
-#endif
-
        for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
                portp = kzalloc(sizeof(stliport_t), GFP_KERNEL);
                if (!portp) {
@@ -3240,7 +2946,7 @@ static int stli_initports(stlibrd_t *brdp)
                brdp->ports[i] = portp;
        }
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -3253,10 +2959,6 @@ static void stli_ecpinit(stlibrd_t *brdp)
 {
        unsigned long   memconf;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR));
        udelay(10);
        outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
@@ -3270,9 +2972,6 @@ static void stli_ecpinit(stlibrd_t *brdp)
 
 static void stli_ecpenable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpenable(brdp=%x)\n", (int) brdp);
-#endif
        outb(ECP_ATENABLE, (brdp->iobase + ECP_ATCONFR));
 }
 
@@ -3280,9 +2979,6 @@ static void stli_ecpenable(stlibrd_t *brdp)
 
 static void stli_ecpdisable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpdisable(brdp=%x)\n", (int) brdp);
-#endif
        outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
 }
 
@@ -3290,13 +2986,8 @@ static void stli_ecpdisable(stlibrd_t *brdp)
 
 static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void            *ptr;
-       unsigned char   val;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
-               (int) offset);
-#endif
+       void *ptr;
+       unsigned char val;
 
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3316,10 +3007,6 @@ static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 
 static void stli_ecpreset(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpreset(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR));
        udelay(10);
        outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
@@ -3330,9 +3017,6 @@ static void stli_ecpreset(stlibrd_t *brdp)
 
 static void stli_ecpintr(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpintr(brdp=%x)\n", (int) brdp);
-#endif
        outb(0x1, brdp->iobase);
 }
 
@@ -3346,10 +3030,6 @@ static void stli_ecpeiinit(stlibrd_t *brdp)
 {
        unsigned long   memconf;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpeiinit(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(0x1, (brdp->iobase + ECP_EIBRDENAB));
        outb(ECP_EISTOP, (brdp->iobase + ECP_EICONFR));
        udelay(10);
@@ -3383,11 +3063,6 @@ static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line
        void            *ptr;
        unsigned char   val;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpeigetmemptr(brdp=%x,offset=%x,line=%d)\n",
-               (int) brdp, (int) offset, line);
-#endif
-
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
@@ -3437,8 +3112,8 @@ static void stli_ecpmcdisable(stlibrd_t *brdp)
 
 static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void            *ptr;
-       unsigned char   val;
+       void *ptr;
+       unsigned char val;
 
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3472,10 +3147,6 @@ static void stli_ecpmcreset(stlibrd_t *brdp)
 
 static void stli_ecppciinit(stlibrd_t *brdp)
 {
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecppciinit(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR));
        udelay(10);
        outb(0, (brdp->iobase + ECP_PCICONFR));
@@ -3489,11 +3160,6 @@ static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int lin
        void            *ptr;
        unsigned char   val;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecppcigetmemptr(brdp=%x,offset=%x,line=%d)\n",
-               (int) brdp, (int) offset, line);
-#endif
-
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
                                "range at line=%d(%d), board=%d\n",
@@ -3528,10 +3194,6 @@ static void stli_onbinit(stlibrd_t *brdp)
 {
        unsigned long   memconf;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
        udelay(10);
        outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
@@ -3547,9 +3209,6 @@ static void stli_onbinit(stlibrd_t *brdp)
 
 static void stli_onbenable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbenable(brdp=%x)\n", (int) brdp);
-#endif
        outb((brdp->enabval | ONB_ATENABLE), (brdp->iobase + ONB_ATCONFR));
 }
 
@@ -3557,9 +3216,6 @@ static void stli_onbenable(stlibrd_t *brdp)
 
 static void stli_onbdisable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbdisable(brdp=%x)\n", (int) brdp);
-#endif
        outb((brdp->enabval | ONB_ATDISABLE), (brdp->iobase + ONB_ATCONFR));
 }
 
@@ -3569,11 +3225,6 @@ static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
        void    *ptr;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
-               (int) offset);
-#endif
-
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
@@ -3589,11 +3240,6 @@ static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 
 static void stli_onbreset(stlibrd_t *brdp)
 {      
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbreset(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
        udelay(10);
        outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
@@ -3610,10 +3256,6 @@ static void stli_onbeinit(stlibrd_t *brdp)
 {
        unsigned long   memconf;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbeinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(0x1, (brdp->iobase + ONB_EIBRDENAB));
        outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
        udelay(10);
@@ -3632,9 +3274,6 @@ static void stli_onbeinit(stlibrd_t *brdp)
 
 static void stli_onbeenable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbeenable(brdp=%x)\n", (int) brdp);
-#endif
        outb(ONB_EIENABLE, (brdp->iobase + ONB_EICONFR));
 }
 
@@ -3642,9 +3281,6 @@ static void stli_onbeenable(stlibrd_t *brdp)
 
 static void stli_onbedisable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbedisable(brdp=%x)\n", (int) brdp);
-#endif
        outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
 }
 
@@ -3652,13 +3288,8 @@ static void stli_onbedisable(stlibrd_t *brdp)
 
 static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void            *ptr;
-       unsigned char   val;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbegetmemptr(brdp=%x,offset=%x,line=%d)\n",
-               (int) brdp, (int) offset, line);
-#endif
+       void *ptr;
+       unsigned char val;
 
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3681,11 +3312,6 @@ static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 
 static void stli_onbereset(stlibrd_t *brdp)
 {      
-
-#ifdef DEBUG
-       printk(KERN_ERR "stli_onbereset(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
        udelay(10);
        outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
@@ -3700,11 +3326,6 @@ static void stli_onbereset(stlibrd_t *brdp)
 
 static void stli_bbyinit(stlibrd_t *brdp)
 {
-
-#ifdef DEBUG
-       printk(KERN_ERR "stli_bbyinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
        udelay(10);
        outb(0, (brdp->iobase + BBY_ATCONFR));
@@ -3717,24 +3338,13 @@ static void stli_bbyinit(stlibrd_t *brdp)
 
 static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void            *ptr;
-       unsigned char   val;
+       void *ptr;
+       unsigned char val;
 
-#ifdef DEBUG
-       printk(KERN_ERR "stli_bbygetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
-               (int) offset);
-#endif
+       BUG_ON(offset > brdp->memsize);
 
-       if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
-                               "range at line=%d(%d), brd=%d\n",
-                               (int) offset, line, __LINE__, brdp->brdnr);
-               ptr = NULL;
-               val = 0;
-       } else {
-               ptr = brdp->membase + (offset % BBY_PAGESIZE);
-               val = (unsigned char) (offset / BBY_PAGESIZE);
-       }
+       ptr = brdp->membase + (offset % BBY_PAGESIZE);
+       val = (unsigned char) (offset / BBY_PAGESIZE);
        outb(val, (brdp->iobase + BBY_ATCONFR));
        return(ptr);
 }
@@ -3743,11 +3353,6 @@ static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 
 static void stli_bbyreset(stlibrd_t *brdp)
 {      
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_bbyreset(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
        udelay(10);
        outb(0, (brdp->iobase + BBY_ATCONFR));
@@ -3762,11 +3367,6 @@ static void stli_bbyreset(stlibrd_t *brdp)
 
 static void stli_stalinit(stlibrd_t *brdp)
 {
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_stalinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(0x1, brdp->iobase);
        mdelay(1000);
 }
@@ -3775,36 +3375,18 @@ static void stli_stalinit(stlibrd_t *brdp)
 
 static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void    *ptr;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_stalgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
-               (int) offset);
-#endif
-
-       if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
-                               "range at line=%d(%d), brd=%d\n",
-                               (int) offset, line, __LINE__, brdp->brdnr);
-               ptr = NULL;
-       } else {
-               ptr = brdp->membase + (offset % STAL_PAGESIZE);
-       }
-       return(ptr);
+       BUG_ON(offset > brdp->memsize);
+       return brdp->membase + (offset % STAL_PAGESIZE);
 }
 
 /*****************************************************************************/
 
 static void stli_stalreset(stlibrd_t *brdp)
 {      
-       volatile unsigned long  *vecp;
+       u32 __iomem *vecp;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_stalreset(brdp=%x)\n", (int) brdp);
-#endif
-
-       vecp = (volatile unsigned long *) (brdp->membase + 0x30);
-       *vecp = 0xffff0000;
+       vecp = (u32 __iomem *) (brdp->membase + 0x30);
+       writel(0xffff0000, vecp);
        outb(0, brdp->iobase);
        mdelay(1000);
 }
@@ -3818,15 +3400,11 @@ static void stli_stalreset(stlibrd_t *brdp)
 
 static int stli_initecp(stlibrd_t *brdp)
 {
-       cdkecpsig_t     sig;
-       cdkecpsig_t     *sigsp;
-       unsigned int    status, nxtid;
-       char            *name;
-       int             panelnr, nrports;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initecp(brdp=%x)\n", (int) brdp);
-#endif
+       cdkecpsig_t sig;
+       cdkecpsig_t __iomem *sigsp;
+       unsigned int status, nxtid;
+       char *name;
+       int panelnr, nrports;
 
        if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
                return -EIO;
@@ -3834,7 +3412,7 @@ static int stli_initecp(stlibrd_t *brdp)
        if ((brdp->iobase == 0) || (brdp->memaddr == 0))
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENODEV);
+               return -ENODEV;
        }
 
        brdp->iosize = ECP_IOSIZE;
@@ -3903,7 +3481,7 @@ static int stli_initecp(stlibrd_t *brdp)
 
        default:
                release_region(brdp->iobase, brdp->iosize);
-               return(-EINVAL);
+               return -EINVAL;
        }
 
 /*
@@ -3915,10 +3493,10 @@ static int stli_initecp(stlibrd_t *brdp)
        EBRDINIT(brdp);
 
        brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
-       if (brdp->membase == (void *) NULL)
+       if (brdp->membase == NULL)
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENOMEM);
+               return -ENOMEM;
        }
 
 /*
@@ -3927,23 +3505,14 @@ static int stli_initecp(stlibrd_t *brdp)
  *     this is, and what it is connected to it.
  */
        EBRDENABLE(brdp);
-       sigsp = (cdkecpsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
+       sigsp = (cdkecpsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
        memcpy(&sig, sigsp, sizeof(cdkecpsig_t));
        EBRDDISABLE(brdp);
 
-#if 0
-       printk("%s(%d): sig-> magic=%x rom=%x panel=%x,%x,%x,%x,%x,%x,%x,%x\n",
-               __FILE__, __LINE__, (int) sig.magic, sig.romver, sig.panelid[0],
-               (int) sig.panelid[1], (int) sig.panelid[2],
-               (int) sig.panelid[3], (int) sig.panelid[4],
-               (int) sig.panelid[5], (int) sig.panelid[6],
-               (int) sig.panelid[7]);
-#endif
-
-       if (sig.magic != ECP_MAGIC)
+       if (sig.magic != cpu_to_le32(ECP_MAGIC))
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENODEV);
+               return -ENODEV;
        }
 
 /*
@@ -3967,7 +3536,7 @@ static int stli_initecp(stlibrd_t *brdp)
 
 
        brdp->state |= BST_FOUND;
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -3979,20 +3548,16 @@ static int stli_initecp(stlibrd_t *brdp)
 
 static int stli_initonb(stlibrd_t *brdp)
 {
-       cdkonbsig_t     sig;
-       cdkonbsig_t     *sigsp;
-       char            *name;
-       int             i;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initonb(brdp=%x)\n", (int) brdp);
-#endif
+       cdkonbsig_t sig;
+       cdkonbsig_t __iomem *sigsp;
+       char *name;
+       int i;
 
 /*
  *     Do a basic sanity check on the IO and memory addresses.
  */
-       if ((brdp->iobase == 0) || (brdp->memaddr == 0))
-               return(-ENODEV);
+       if (brdp->iobase == 0 || brdp->memaddr == 0)
+               return -ENODEV;
 
        brdp->iosize = ONB_IOSIZE;
        
@@ -4010,7 +3575,6 @@ static int stli_initonb(stlibrd_t *brdp)
        case BRD_ONBOARD2:
        case BRD_ONBOARD2_32:
        case BRD_ONBOARDRS:
-               brdp->membase = (void *) brdp->memaddr;
                brdp->memsize = ONB_MEMSIZE;
                brdp->pagesize = ONB_ATPAGESIZE;
                brdp->init = stli_onbinit;
@@ -4028,7 +3592,6 @@ static int stli_initonb(stlibrd_t *brdp)
                break;
 
        case BRD_ONBOARDE:
-               brdp->membase = (void *) brdp->memaddr;
                brdp->memsize = ONB_EIMEMSIZE;
                brdp->pagesize = ONB_EIPAGESIZE;
                brdp->init = stli_onbeinit;
@@ -4044,7 +3607,6 @@ static int stli_initonb(stlibrd_t *brdp)
        case BRD_BRUMBY4:
        case BRD_BRUMBY8:
        case BRD_BRUMBY16:
-               brdp->membase = (void *) brdp->memaddr;
                brdp->memsize = BBY_MEMSIZE;
                brdp->pagesize = BBY_PAGESIZE;
                brdp->init = stli_bbyinit;
@@ -4058,7 +3620,6 @@ static int stli_initonb(stlibrd_t *brdp)
                break;
 
        case BRD_STALLION:
-               brdp->membase = (void *) brdp->memaddr;
                brdp->memsize = STAL_MEMSIZE;
                brdp->pagesize = STAL_PAGESIZE;
                brdp->init = stli_stalinit;
@@ -4073,7 +3634,7 @@ static int stli_initonb(stlibrd_t *brdp)
 
        default:
                release_region(brdp->iobase, brdp->iosize);
-               return(-EINVAL);
+               return -EINVAL;
        }
 
 /*
@@ -4085,10 +3646,10 @@ static int stli_initonb(stlibrd_t *brdp)
        EBRDINIT(brdp);
 
        brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
-       if (brdp->membase == (void *) NULL)
+       if (brdp->membase == NULL)
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENOMEM);
+               return -ENOMEM;
        }
 
 /*
@@ -4097,21 +3658,17 @@ static int stli_initonb(stlibrd_t *brdp)
  *     this is, and how many ports.
  */
        EBRDENABLE(brdp);
-       sigsp = (cdkonbsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
-       memcpy(&sig, sigsp, sizeof(cdkonbsig_t));
+       sigsp = (cdkonbsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
+       memcpy_fromio(&sig, sigsp, sizeof(cdkonbsig_t));
        EBRDDISABLE(brdp);
 
-#if 0
-       printk("%s(%d): sig-> magic=%x:%x:%x:%x romver=%x amask=%x:%x:%x\n",
-               __FILE__, __LINE__, sig.magic0, sig.magic1, sig.magic2,
-               sig.magic3, sig.romver, sig.amask0, sig.amask1, sig.amask2);
-#endif
-
-       if ((sig.magic0 != ONB_MAGIC0) || (sig.magic1 != ONB_MAGIC1) ||
-           (sig.magic2 != ONB_MAGIC2) || (sig.magic3 != ONB_MAGIC3))
+       if (sig.magic0 != cpu_to_le16(ONB_MAGIC0) ||
+           sig.magic1 != cpu_to_le16(ONB_MAGIC1) ||
+           sig.magic2 != cpu_to_le16(ONB_MAGIC2) ||
+           sig.magic3 != cpu_to_le16(ONB_MAGIC3))
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENODEV);
+               return -ENODEV;
        }
 
 /*
@@ -4132,7 +3689,7 @@ static int stli_initonb(stlibrd_t *brdp)
 
 
        brdp->state |= BST_FOUND;
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4145,31 +3702,25 @@ static int stli_initonb(stlibrd_t *brdp)
 
 static int stli_startbrd(stlibrd_t *brdp)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile cdkmem_t       *memp;
-       volatile cdkasy_t       *ap;
-       unsigned long           flags;
-       stliport_t              *portp;
-       int                     portnr, nrdevs, i, rc;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_startbrd(brdp=%x)\n", (int) brdp);
-#endif
-
-       rc = 0;
-
-       save_flags(flags);
-       cli();
+       cdkhdr_t __iomem *hdrp;
+       cdkmem_t __iomem *memp;
+       cdkasy_t __iomem *ap;
+       unsigned long flags;
+       stliport_t *portp;
+       int portnr, nrdevs, i, rc = 0;
+       u32 memoff;
+
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
        nrdevs = hdrp->nrdevs;
 
 #if 0
        printk("%s(%d): CDK version %d.%d.%d --> "
                "nrdevs=%d memp=%x hostp=%x slavep=%x\n",
-                __FILE__, __LINE__, hdrp->ver_release, hdrp->ver_modification,
-                hdrp->ver_fix, nrdevs, (int) hdrp->memp, (int) hdrp->hostp,
-                (int) hdrp->slavep);
+                __FILE__, __LINE__, readb(&hdrp->ver_release), readb(&hdrp->ver_modification),
+                readb(&hdrp->ver_fix), nrdevs, (int) readl(&hdrp->memp), readl(&hdrp->hostp),
+                readl(&hdrp->slavep));
 #endif
 
        if (nrdevs < (brdp->nrports + 1)) {
@@ -4181,14 +3732,14 @@ static int stli_startbrd(stlibrd_t *brdp)
        brdp->hostoffset = hdrp->hostp - CDK_CDKADDR;
        brdp->slaveoffset = hdrp->slavep - CDK_CDKADDR;
        brdp->bitsize = (nrdevs + 7) / 8;
-       memp = (volatile cdkmem_t *) hdrp->memp;
-       if (((unsigned long) memp) > brdp->memsize) {
+       memoff = readl(&hdrp->memp);
+       if (memoff > brdp->memsize) {
                printk(KERN_ERR "STALLION: corrupted shared memory region?\n");
                rc = -EIO;
                goto stli_donestartup;
        }
-       memp = (volatile cdkmem_t *) EBRDGETMEMPTR(brdp, (unsigned long) memp);
-       if (memp->dtype != TYP_ASYNCTRL) {
+       memp = (cdkmem_t __iomem *) EBRDGETMEMPTR(brdp, memoff);
+       if (readw(&memp->dtype) != TYP_ASYNCTRL) {
                printk(KERN_ERR "STALLION: no slave control device found\n");
                goto stli_donestartup;
        }
@@ -4200,19 +3751,19 @@ static int stli_startbrd(stlibrd_t *brdp)
  *     change pages while reading memory map.
  */
        for (i = 1, portnr = 0; (i < nrdevs); i++, portnr++, memp++) {
-               if (memp->dtype != TYP_ASYNC)
+               if (readw(&memp->dtype) != TYP_ASYNC)
                        break;
                portp = brdp->ports[portnr];
-               if (portp == (stliport_t *) NULL)
+               if (portp == NULL)
                        break;
                portp->devnr = i;
-               portp->addr = memp->offset;
+               portp->addr = readl(&memp->offset);
                portp->reqbit = (unsigned char) (0x1 << (i * 8 / nrdevs));
                portp->portidx = (unsigned char) (i / 8);
                portp->portbit = (unsigned char) (0x1 << (i % 8));
        }
 
-       hdrp->slavereq = 0xff;
+       writeb(0xff, &hdrp->slavereq);
 
 /*
  *     For each port setup a local copy of the RX and TX buffer offsets
@@ -4221,22 +3772,22 @@ static int stli_startbrd(stlibrd_t *brdp)
  */
        for (i = 1, portnr = 0; (i < nrdevs); i++, portnr++) {
                portp = brdp->ports[portnr];
-               if (portp == (stliport_t *) NULL)
+               if (portp == NULL)
                        break;
                if (portp->addr == 0)
                        break;
-               ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-               if (ap != (volatile cdkasy_t *) NULL) {
-                       portp->rxsize = ap->rxq.size;
-                       portp->txsize = ap->txq.size;
-                       portp->rxoffset = ap->rxq.offset;
-                       portp->txoffset = ap->txq.offset;
+               ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+               if (ap != NULL) {
+                       portp->rxsize = readw(&ap->rxq.size);
+                       portp->txsize = readw(&ap->txq.size);
+                       portp->rxoffset = readl(&ap->rxq.offset);
+                       portp->txoffset = readl(&ap->txq.offset);
                }
        }
 
 stli_donestartup:
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        if (rc == 0)
                brdp->state |= BST_STARTED;
@@ -4247,7 +3798,7 @@ stli_donestartup:
                add_timer(&stli_timerlist);
        }
 
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -4258,10 +3809,6 @@ stli_donestartup:
 
 static int __init stli_brdinit(stlibrd_t *brdp)
 {
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_brdinit(brdp=%x)\n", (int) brdp);
-#endif
-
        stli_brds[brdp->brdnr] = brdp;
 
        switch (brdp->brdtype) {
@@ -4289,11 +3836,11 @@ static int __init stli_brdinit(stlibrd_t *brdp)
        case BRD_ECHPCI:
                printk(KERN_ERR "STALLION: %s board type not supported in "
                                "this driver\n", stli_brdnames[brdp->brdtype]);
-               return(ENODEV);
+               return -ENODEV;
        default:
                printk(KERN_ERR "STALLION: board=%d is unknown board "
                                "type=%d\n", brdp->brdnr, brdp->brdtype);
-               return(ENODEV);
+               return -ENODEV;
        }
 
        if ((brdp->state & BST_FOUND) == 0) {
@@ -4301,7 +3848,7 @@ static int __init stli_brdinit(stlibrd_t *brdp)
                                "io=%x mem=%x\n",
                        stli_brdnames[brdp->brdtype], brdp->brdnr,
                        brdp->iobase, (int) brdp->memaddr);
-               return(ENODEV);
+               return -ENODEV;
        }
 
        stli_initports(brdp);
@@ -4309,7 +3856,7 @@ static int __init stli_brdinit(stlibrd_t *brdp)
                "nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype],
                brdp->brdnr, brdp->iobase, (int) brdp->memaddr,
                brdp->nrpanels, brdp->nrports);
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4321,14 +3868,10 @@ static int __init stli_brdinit(stlibrd_t *brdp)
 
 static int stli_eisamemprobe(stlibrd_t *brdp)
 {
-       cdkecpsig_t     ecpsig, *ecpsigp;
-       cdkonbsig_t     onbsig, *onbsigp;
+       cdkecpsig_t     ecpsig, __iomem *ecpsigp;
+       cdkonbsig_t     onbsig, __iomem *onbsigp;
        int             i, foundit;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_eisamemprobe(brdp=%x)\n", (int) brdp);
-#endif
-
 /*
  *     First up we reset the board, to get it into a known state. There
  *     is only 2 board types here we need to worry about. Don;t use the
@@ -4352,7 +3895,7 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
                mdelay(1);
                stli_onbeenable(brdp);
        } else {
-               return(-ENODEV);
+               return -ENODEV;
        }
 
        foundit = 0;
@@ -4364,25 +3907,24 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
  */
        for (i = 0; (i < stli_eisamempsize); i++) {
                brdp->memaddr = stli_eisamemprobeaddrs[i];
-               brdp->membase = (void *) brdp->memaddr;
                brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
-               if (brdp->membase == (void *) NULL)
+               if (brdp->membase == NULL)
                        continue;
 
                if (brdp->brdtype == BRD_ECPE) {
-                       ecpsigp = (cdkecpsig_t *) stli_ecpeigetmemptr(brdp,
+                       ecpsigp = (cdkecpsig_t __iomem *) stli_ecpeigetmemptr(brdp,
                                CDK_SIGADDR, __LINE__);
-                       memcpy(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
-                       if (ecpsig.magic == ECP_MAGIC)
+                       memcpy_fromio(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
+                       if (ecpsig.magic == cpu_to_le32(ECP_MAGIC))
                                foundit = 1;
                } else {
-                       onbsigp = (cdkonbsig_t *) stli_onbegetmemptr(brdp,
+                       onbsigp = (cdkonbsig_t __iomem *) stli_onbegetmemptr(brdp,
                                CDK_SIGADDR, __LINE__);
-                       memcpy(&onbsig, onbsigp, sizeof(cdkonbsig_t));
-                       if ((onbsig.magic0 == ONB_MAGIC0) &&
-                           (onbsig.magic1 == ONB_MAGIC1) &&
-                           (onbsig.magic2 == ONB_MAGIC2) &&
-                           (onbsig.magic3 == ONB_MAGIC3))
+                       memcpy_fromio(&onbsig, onbsigp, sizeof(cdkonbsig_t));
+                       if ((onbsig.magic0 == cpu_to_le16(ONB_MAGIC0)) &&
+                           (onbsig.magic1 == cpu_to_le16(ONB_MAGIC1)) &&
+                           (onbsig.magic2 == cpu_to_le16(ONB_MAGIC2)) &&
+                           (onbsig.magic3 == cpu_to_le16(ONB_MAGIC3)))
                                foundit = 1;
                }
 
@@ -4406,9 +3948,9 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
                printk(KERN_ERR "STALLION: failed to probe shared memory "
                                "region for %s in EISA slot=%d\n",
                        stli_brdnames[brdp->brdtype], (brdp->iobase >> 12));
-               return(-ENODEV);
+               return -ENODEV;
        }
-       return(0);
+       return 0;
 }
 
 static int stli_getbrdnr(void)
@@ -4439,22 +3981,16 @@ static int stli_getbrdnr(void)
 
 static int stli_findeisabrds(void)
 {
-       stlibrd_t       *brdp;
-       unsigned int    iobase, eid;
-       int             i;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_findeisabrds()\n");
-#endif
+       stlibrd_t *brdp;
+       unsigned int iobase, eid;
+       int i;
 
 /*
- *     Firstly check if this is an EISA system. Do this by probing for
- *     the system board EISA ID. If this is not an EISA system then
+ *     Firstly check if this is an EISA system.  If this is not an EISA system then
  *     don't bother going any further!
  */
-       outb(0xff, 0xc80);
-       if (inb(0xc80) == 0xff)
-               return(0);
+       if (EISA_bus)
+               return 0;
 
 /*
  *     Looks like an EISA system, so go searching for EISA boards.
@@ -4472,7 +4008,7 @@ static int stli_findeisabrds(void)
  */
                for (i = 0; (i < STL_MAXBRDS); i++) {
                        brdp = stli_brds[i];
-                       if (brdp == (stlibrd_t *) NULL)
+                       if (brdp == NULL)
                                continue;
                        if (brdp->iobase == iobase)
                                break;
@@ -4484,10 +4020,10 @@ static int stli_findeisabrds(void)
  *             We have found a Stallion board and it is not configured already.
  *             Allocate a board structure and initialize it.
  */
-               if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
-                       return(-ENOMEM);
+               if ((brdp = stli_allocbrd()) == NULL)
+                       return -ENOMEM;
                if ((brdp->brdnr = stli_getbrdnr()) < 0)
-                       return(-ENOMEM);
+                       return -ENOMEM;
                eid = inb(iobase + 0xc82);
                if (eid == ECP_EISAID)
                        brdp->brdtype = BRD_ECPE;
@@ -4502,7 +4038,7 @@ static int stli_findeisabrds(void)
                stli_brdinit(brdp);
        }
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4523,32 +4059,18 @@ static int stli_findeisabrds(void)
 
 static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
 {
-       stlibrd_t       *brdp;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n",
-               brdtype, dev->bus->number, dev->devfn);
-#endif
+       stlibrd_t *brdp;
 
        if (pci_enable_device(devp))
-               return(-EIO);
-       if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
-               return(-ENOMEM);
+               return -EIO;
+       if ((brdp = stli_allocbrd()) == NULL)
+               return -ENOMEM;
        if ((brdp->brdnr = stli_getbrdnr()) < 0) {
                printk(KERN_INFO "STALLION: too many boards found, "
                        "maximum supported %d\n", STL_MAXBRDS);
-               return(0);
+               return 0;
        }
        brdp->brdtype = brdtype;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "%s(%d): BAR[]=%lx,%lx,%lx,%lx\n", __FILE__, __LINE__,
-               pci_resource_start(devp, 0),
-               pci_resource_start(devp, 1),
-               pci_resource_start(devp, 2),
-               pci_resource_start(devp, 3));
-#endif
-
 /*
  *     We have all resources from the board, so lets setup the actual
  *     board structure now.
@@ -4557,7 +4079,7 @@ static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
        brdp->memaddr = pci_resource_start(devp, 2);
        stli_brdinit(brdp);
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4569,20 +4091,12 @@ static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
 
 static int stli_findpcibrds(void)
 {
-       struct pci_dev  *dev = NULL;
-       int             rc;
-
-#ifdef DEBUG
-       printk("stli_findpcibrds()\n");
-#endif
+       struct pci_dev *dev = NULL;
 
-       while ((dev = pci_find_device(PCI_VENDOR_ID_STALLION,
-           PCI_DEVICE_ID_ECRA, dev))) {
-               if ((rc = stli_initpcibrd(BRD_ECPPCI, dev)))
-                       return(rc);
+       while ((dev = pci_get_device(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA, dev))) {
+               stli_initpcibrd(BRD_ECPPCI, dev);
        }
-
-       return(0);
+       return 0;
 }
 
 #endif
@@ -4595,17 +4109,16 @@ static int stli_findpcibrds(void)
 
 static stlibrd_t *stli_allocbrd(void)
 {
-       stlibrd_t       *brdp;
+       stlibrd_t *brdp;
 
        brdp = kzalloc(sizeof(stlibrd_t), GFP_KERNEL);
        if (!brdp) {
                printk(KERN_ERR "STALLION: failed to allocate memory "
-                               "(size=%d)\n", sizeof(stlibrd_t));
+                               "(size=%Zd)\n", sizeof(stlibrd_t));
                return NULL;
        }
-
        brdp->magic = STLI_BOARDMAGIC;
-       return(brdp);
+       return brdp;
 }
 
 /*****************************************************************************/
@@ -4617,13 +4130,9 @@ static stlibrd_t *stli_allocbrd(void)
 
 static int stli_initbrds(void)
 {
-       stlibrd_t       *brdp, *nxtbrdp;
-       stlconf_t       *confp;
-       int             i, j;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initbrds()\n");
-#endif
+       stlibrd_t *brdp, *nxtbrdp;
+       stlconf_t *confp;
+       int i, j;
 
        if (stli_nrbrds > STL_MAXBRDS) {
                printk(KERN_INFO "STALLION: too many boards in configuration "
@@ -4638,11 +4147,9 @@ static int stli_initbrds(void)
  */
        for (i = 0; (i < stli_nrbrds); i++) {
                confp = &stli_brdconf[i];
-#ifdef MODULE
                stli_parsebrd(confp, stli_brdsp[i]);
-#endif
-               if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
-                       return(-ENOMEM);
+               if ((brdp = stli_allocbrd()) == NULL)
+                       return -ENOMEM;
                brdp->brdnr = i;
                brdp->brdtype = confp->brdtype;
                brdp->iobase = confp->ioaddr1;
@@ -4654,9 +4161,7 @@ static int stli_initbrds(void)
  *     Static configuration table done, so now use dynamic methods to
  *     see if any more boards should be configured.
  */
-#ifdef MODULE
        stli_argbrds();
-#endif
        if (STLI_EISAPROBE)
                stli_findeisabrds();
 #ifdef CONFIG_PCI
@@ -4672,11 +4177,11 @@ static int stli_initbrds(void)
        if (stli_nrbrds > 1) {
                for (i = 0; (i < stli_nrbrds); i++) {
                        brdp = stli_brds[i];
-                       if (brdp == (stlibrd_t *) NULL)
+                       if (brdp == NULL)
                                continue;
                        for (j = i + 1; (j < stli_nrbrds); j++) {
                                nxtbrdp = stli_brds[j];
-                               if (nxtbrdp == (stlibrd_t *) NULL)
+                               if (nxtbrdp == NULL)
                                        continue;
                                if ((brdp->membase >= nxtbrdp->membase) &&
                                    (brdp->membase <= (nxtbrdp->membase +
@@ -4691,7 +4196,7 @@ static int stli_initbrds(void)
        if (stli_shared == 0) {
                for (i = 0; (i < stli_nrbrds); i++) {
                        brdp = stli_brds[i];
-                       if (brdp == (stlibrd_t *) NULL)
+                       if (brdp == NULL)
                                continue;
                        if (brdp->state & BST_FOUND) {
                                EBRDENABLE(brdp);
@@ -4701,7 +4206,7 @@ static int stli_initbrds(void)
                }
        }
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4714,48 +4219,55 @@ static int stli_initbrds(void)
 
 static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp)
 {
-       unsigned long   flags;
-       void            *memptr;
-       stlibrd_t       *brdp;
-       int             brdnr, size, n;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_memread(fp=%x,buf=%x,count=%x,offp=%x)\n",
-                       (int) fp, (int) buf, count, (int) offp);
-#endif
+       unsigned long flags;
+       void *memptr;
+       stlibrd_t *brdp;
+       int brdnr, size, n;
+       void *p;
+       loff_t off = *offp;
 
        brdnr = iminor(fp->f_dentry->d_inode);
        if (brdnr >= stli_nrbrds)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
        if (brdp->state == 0)
-               return(-ENODEV);
-       if (fp->f_pos >= brdp->memsize)
-               return(0);
+               return -ENODEV;
+       if (off >= brdp->memsize || off + count < off)
+               return 0;
 
-       size = MIN(count, (brdp->memsize - fp->f_pos));
+       size = MIN(count, (brdp->memsize - off));
+
+       /*
+        *      Copy the data a page at a time
+        */
+
+       p = (void *)__get_free_page(GFP_KERNEL);
+       if(p == NULL)
+               return -ENOMEM;
 
-       save_flags(flags);
-       cli();
-       EBRDENABLE(brdp);
        while (size > 0) {
-               memptr = (void *) EBRDGETMEMPTR(brdp, fp->f_pos);
-               n = MIN(size, (brdp->pagesize - (((unsigned long) fp->f_pos) % brdp->pagesize)));
-               if (copy_to_user(buf, memptr, n)) {
+               spin_lock_irqsave(&brd_lock, flags);
+               EBRDENABLE(brdp);
+               memptr = (void *) EBRDGETMEMPTR(brdp, off);
+               n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+               n = MIN(n, PAGE_SIZE);
+               memcpy_fromio(p, memptr, n);
+               EBRDDISABLE(brdp);
+               spin_unlock_irqrestore(&brd_lock, flags);
+               if (copy_to_user(buf, p, n)) {
                        count = -EFAULT;
                        goto out;
                }
-               fp->f_pos += n;
+               off += n;
                buf += n;
                size -= n;
        }
 out:
-       EBRDDISABLE(brdp);
-       restore_flags(flags);
-
-       return(count);
+       *offp = off;
+       free_page((unsigned long)p);
+       return count;
 }
 
 /*****************************************************************************/
@@ -4764,54 +4276,65 @@ out:
  *     Code to handle an "staliomem" write operation. This device is the 
  *     contents of the board shared memory. It is used for down loading
  *     the slave image (and debugging :-)
+ *
+ *     FIXME: copy under lock
  */
 
 static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp)
 {
-       unsigned long   flags;
-       void            *memptr;
-       stlibrd_t       *brdp;
-       char            __user *chbuf;
-       int             brdnr, size, n;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_memwrite(fp=%x,buf=%x,count=%x,offp=%x)\n",
-                       (int) fp, (int) buf, count, (int) offp);
-#endif
+       unsigned long flags;
+       void *memptr;
+       stlibrd_t *brdp;
+       char __user *chbuf;
+       int brdnr, size, n;
+       void *p;
+       loff_t off = *offp;
 
        brdnr = iminor(fp->f_dentry->d_inode);
+
        if (brdnr >= stli_nrbrds)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
        if (brdp->state == 0)
-               return(-ENODEV);
-       if (fp->f_pos >= brdp->memsize)
-               return(0);
+               return -ENODEV;
+       if (off >= brdp->memsize || off + count < off)
+               return 0;
 
        chbuf = (char __user *) buf;
-       size = MIN(count, (brdp->memsize - fp->f_pos));
+       size = MIN(count, (brdp->memsize - off));
+
+       /*
+        *      Copy the data a page at a time
+        */
+
+       p = (void *)__get_free_page(GFP_KERNEL);
+       if(p == NULL)
+               return -ENOMEM;
 
-       save_flags(flags);
-       cli();
-       EBRDENABLE(brdp);
        while (size > 0) {
-               memptr = (void *) EBRDGETMEMPTR(brdp, fp->f_pos);
-               n = MIN(size, (brdp->pagesize - (((unsigned long) fp->f_pos) % brdp->pagesize)));
-               if (copy_from_user(memptr, chbuf, n)) {
-                       count = -EFAULT;
+               n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+               n = MIN(n, PAGE_SIZE);
+               if (copy_from_user(p, chbuf, n)) {
+                       if (count == 0)
+                               count = -EFAULT;
                        goto out;
                }
-               fp->f_pos += n;
+               spin_lock_irqsave(&brd_lock, flags);
+               EBRDENABLE(brdp);
+               memptr = (void *) EBRDGETMEMPTR(brdp, off);
+               memcpy_toio(memptr, p, n);
+               EBRDDISABLE(brdp);
+               spin_unlock_irqrestore(&brd_lock, flags);
+               off += n;
                chbuf += n;
                size -= n;
        }
 out:
-       EBRDDISABLE(brdp);
-       restore_flags(flags);
-
-       return(count);
+       free_page((unsigned long) p);
+       *offp = off;
+       return count;
 }
 
 /*****************************************************************************/
@@ -4822,16 +4345,16 @@ out:
 
 static int stli_getbrdstats(combrd_t __user *bp)
 {
-       stlibrd_t       *brdp;
-       int             i;
+       stlibrd_t *brdp;
+       int i;
 
        if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t)))
                return -EFAULT;
        if (stli_brdstats.brd >= STL_MAXBRDS)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[stli_brdstats.brd];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
 
        memset(&stli_brdstats, 0, sizeof(combrd_t));
        stli_brdstats.brd = brdp->brdnr;
@@ -4850,7 +4373,7 @@ static int stli_getbrdstats(combrd_t __user *bp)
 
        if (copy_to_user(bp, &stli_brdstats, sizeof(combrd_t)))
                return -EFAULT;
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4861,19 +4384,19 @@ static int stli_getbrdstats(combrd_t __user *bp)
 
 static stliport_t *stli_getport(int brdnr, int panelnr, int portnr)
 {
-       stlibrd_t       *brdp;
-       int             i;
+       stlibrd_t *brdp;
+       int i;
 
-       if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
-               return((stliport_t *) NULL);
+       if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+               return NULL;
        brdp = stli_brds[brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return((stliport_t *) NULL);
+       if (brdp == NULL)
+               return NULL;
        for (i = 0; (i < panelnr); i++)
                portnr += brdp->panels[i];
        if ((portnr < 0) || (portnr >= brdp->nrports))
-               return((stliport_t *) NULL);
-       return(brdp->ports[portnr]);
+               return NULL;
+       return brdp->ports[portnr];
 }
 
 /*****************************************************************************/
@@ -4892,16 +4415,16 @@ static int stli_portcmdstats(stliport_t *portp)
 
        memset(&stli_comstats, 0, sizeof(comstats_t));
 
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
+       if (portp == NULL)
+               return -ENODEV;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
 
        if (brdp->state & BST_STARTED) {
                if ((rc = stli_cmdwait(brdp, portp, A_GETSTATS,
                    &stli_cdkstats, sizeof(asystats_t), 1)) < 0)
-                       return(rc);
+                       return rc;
        } else {
                memset(&stli_cdkstats, 0, sizeof(asystats_t));
        }
@@ -4912,13 +4435,12 @@ static int stli_portcmdstats(stliport_t *portp)
        stli_comstats.state = portp->state;
        stli_comstats.flags = portp->flags;
 
-       save_flags(flags);
-       cli();
-       if (portp->tty != (struct tty_struct *) NULL) {
+       spin_lock_irqsave(&brd_lock, flags);
+       if (portp->tty != NULL) {
                if (portp->tty->driver_data == portp) {
                        stli_comstats.ttystate = portp->tty->flags;
-                       stli_comstats.rxbuffered = -1 /*portp->tty->flip.count*/;
-                       if (portp->tty->termios != (struct termios *) NULL) {
+                       stli_comstats.rxbuffered = -1;
+                       if (portp->tty->termios != NULL) {
                                stli_comstats.cflags = portp->tty->termios->c_cflag;
                                stli_comstats.iflags = portp->tty->termios->c_iflag;
                                stli_comstats.oflags = portp->tty->termios->c_oflag;
@@ -4926,7 +4448,7 @@ static int stli_portcmdstats(stliport_t *portp)
                        }
                }
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        stli_comstats.txtotal = stli_cdkstats.txchars;
        stli_comstats.rxtotal = stli_cdkstats.rxchars + stli_cdkstats.ringover;
@@ -4948,7 +4470,7 @@ static int stli_portcmdstats(stliport_t *portp)
        stli_comstats.hwid = stli_cdkstats.hwid;
        stli_comstats.signals = stli_mktiocm(stli_cdkstats.signals);
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4961,8 +4483,8 @@ static int stli_portcmdstats(stliport_t *portp)
 
 static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
 {
-       stlibrd_t       *brdp;
-       int             rc;
+       stlibrd_t *brdp;
+       int rc;
 
        if (!portp) {
                if (copy_from_user(&stli_comstats, cp, sizeof(comstats_t)))
@@ -4992,8 +4514,8 @@ static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
 
 static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
 {
-       stlibrd_t       *brdp;
-       int             rc;
+       stlibrd_t *brdp;
+       int rc;
 
        if (!portp) {
                if (copy_from_user(&stli_comstats, cp, sizeof(comstats_t)))
@@ -5031,7 +4553,7 @@ static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
 
 static int stli_getportstruct(stliport_t __user *arg)
 {
-       stliport_t      *portp;
+       stliport_t *portp;
 
        if (copy_from_user(&stli_dummyport, arg, sizeof(stliport_t)))
                return -EFAULT;
@@ -5052,7 +4574,7 @@ static int stli_getportstruct(stliport_t __user *arg)
 
 static int stli_getbrdstruct(stlibrd_t __user *arg)
 {
-       stlibrd_t       *brdp;
+       stlibrd_t *brdp;
 
        if (copy_from_user(&stli_dummybrd, arg, sizeof(stlibrd_t)))
                return -EFAULT;
@@ -5076,15 +4598,10 @@ static int stli_getbrdstruct(stlibrd_t __user *arg)
 
 static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
 {
-       stlibrd_t       *brdp;
-       int             brdnr, rc, done;
+       stlibrd_t *brdp;
+       int brdnr, rc, done;
        void __user *argp = (void __user *)arg;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n",
-                       (int) ip, (int) fp, cmd, (int) arg);
-#endif
-
 /*
  *     First up handle the board independent ioctls.
  */
@@ -5115,7 +4632,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
        }
 
        if (done)
-               return(rc);
+               return rc;
 
 /*
  *     Now handle the board specific ioctls. These all depend on the
@@ -5123,12 +4640,12 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
  */
        brdnr = iminor(ip);
        if (brdnr >= STL_MAXBRDS)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[brdnr];
        if (!brdp)
-               return(-ENODEV);
+               return -ENODEV;
        if (brdp->state == 0)
-               return(-ENODEV);
+               return -ENODEV;
 
        switch (cmd) {
        case STL_BINTR:
@@ -5152,8 +4669,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
                rc = -ENOIOCTLCMD;
                break;
        }
-
-       return(rc);
+       return rc;
 }
 
 static struct tty_operations stli_ops = {
@@ -5187,6 +4703,9 @@ int __init stli_init(void)
        int i;
        printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
 
+       spin_lock_init(&stli_lock);
+       spin_lock_init(&brd_lock);
+
        stli_initbrds();
 
        stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
@@ -5196,10 +4715,6 @@ int __init stli_init(void)
 /*
  *     Allocate a temporary write buffer.
  */
-       stli_tmpwritebuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
-       if (!stli_tmpwritebuf)
-               printk(KERN_ERR "STALLION: failed to allocate memory "
-                               "(size=%d)\n", STLI_TXBUFSIZE);
        stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
        if (!stli_txcookbuf)
                printk(KERN_ERR "STALLION: failed to allocate memory "
@@ -5243,7 +4758,7 @@ int __init stli_init(void)
                printk(KERN_ERR "STALLION: failed to register serial driver\n");
                return -EBUSY;
        }
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
index f43c2e04eadd3878d57126b154afa2b4cbdc74aa..01247cccb89f26cbb0d52b7dee3757c36c43db64 100644 (file)
@@ -301,7 +301,7 @@ static struct tty_operations moxa_ops = {
        .tiocmset = moxa_tiocmset,
 };
 
-static spinlock_t moxa_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(moxa_lock);
 
 #ifdef CONFIG_PCI
 static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board)
index 645d9d713aec84452615d641cfb73603d4eef2b5..72cfd09091e0a63ce1587cabec737aeaeb41e127 100644 (file)
@@ -996,7 +996,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
 
        info->session = current->signal->session;
        info->pgrp = process_group(current);
-       clear_bit(TTY_DONT_FLIP, &tty->flags);
 
        /*
        status = mxser_get_msr(info->base, 0, info->port);
index b9371d5bf7906b48d4b340c5a8756c3fa132f516..603b9ade5eb089f16f041fc15e4876417a6c1505 100644 (file)
@@ -1132,7 +1132,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
  *     buffer, and once to drain the space from the (physical) beginning of
  *     the buffer to head pointer.
  *
- *     Called under the tty->atomic_read_lock sem and with TTY_DONT_FLIP set
+ *     Called under the tty->atomic_read_lock sem
  *
  */
  
@@ -1271,7 +1271,6 @@ do_it_again:
        }
 
        add_wait_queue(&tty->read_wait, &wait);
-       set_bit(TTY_DONT_FLIP, &tty->flags);
        while (nr) {
                /* First test for status change. */
                if (tty->packet && tty->link->ctrl_status) {
@@ -1315,9 +1314,7 @@ do_it_again:
                                break;
                        }
                        n_tty_set_room(tty);
-                       clear_bit(TTY_DONT_FLIP, &tty->flags);
                        timeout = schedule_timeout(timeout);
-                       set_bit(TTY_DONT_FLIP, &tty->flags);
                        continue;
                }
                __set_current_state(TASK_RUNNING);
@@ -1394,7 +1391,6 @@ do_it_again:
                if (time)
                        timeout = time;
        }
-       clear_bit(TTY_DONT_FLIP, &tty->flags);
        mutex_unlock(&tty->atomic_read_lock);
        remove_wait_queue(&tty->read_wait, &wait);
 
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
new file mode 100644 (file)
index 0000000..5b91e4e
--- /dev/null
@@ -0,0 +1,142 @@
+/* linux/drivers/char/nsc_gpio.c
+
+   National Semiconductor common GPIO device-file/VFS methods.
+   Allows a user space process to control the GPIO pins.
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+   Copyright (c) 2005      Jim Cromie <jim.cromie@gmail.com>
+*/
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/nsc_gpio.h>
+#include <linux/platform_device.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define NAME "nsc_gpio"
+
+void nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index)
+{
+       /* retrieve current config w/o changing it */
+       u32 config = amp->gpio_config(index, ~0, 0);
+
+       /* user requested via 'v' command, so its INFO */
+       dev_info(amp->dev, "io%02u: 0x%04x %s %s %s %s %s %s %s\tio:%d/%d\n",
+                index, config,
+                (config & 1) ? "OE" : "TS",      /* output-enabled/tristate */
+                (config & 2) ? "PP" : "OD",      /* push pull / open drain */
+                (config & 4) ? "PUE" : "PUD",    /* pull up enabled/disabled */
+                (config & 8) ? "LOCKED" : "",    /* locked / unlocked */
+                (config & 16) ? "LEVEL" : "EDGE",/* level/edge input */
+                (config & 32) ? "HI" : "LO",     /* trigger on rise/fall edge */
+                (config & 64) ? "DEBOUNCE" : "", /* debounce */
+
+                amp->gpio_get(index), amp->gpio_current(index));
+}
+
+ssize_t nsc_gpio_write(struct file *file, const char __user *data,
+                      size_t len, loff_t *ppos)
+{
+       unsigned m = iminor(file->f_dentry->d_inode);
+       struct nsc_gpio_ops *amp = file->private_data;
+       struct device *dev = amp->dev;
+       size_t i;
+       int err = 0;
+
+       for (i = 0; i < len; ++i) {
+               char c;
+               if (get_user(c, data + i))
+                       return -EFAULT;
+               switch (c) {
+               case '0':
+                       amp->gpio_set(m, 0);
+                       break;
+               case '1':
+                       amp->gpio_set(m, 1);
+                       break;
+               case 'O':
+                       dev_dbg(dev, "GPIO%d output enabled\n", m);
+                       amp->gpio_config(m, ~1, 1);
+                       break;
+               case 'o':
+                       dev_dbg(dev, "GPIO%d output disabled\n", m);
+                       amp->gpio_config(m, ~1, 0);
+                       break;
+               case 'T':
+                       dev_dbg(dev, "GPIO%d output is push pull\n",
+                              m);
+                       amp->gpio_config(m, ~2, 2);
+                       break;
+               case 't':
+                       dev_dbg(dev, "GPIO%d output is open drain\n",
+                              m);
+                       amp->gpio_config(m, ~2, 0);
+                       break;
+               case 'P':
+                       dev_dbg(dev, "GPIO%d pull up enabled\n", m);
+                       amp->gpio_config(m, ~4, 4);
+                       break;
+               case 'p':
+                       dev_dbg(dev, "GPIO%d pull up disabled\n", m);
+                       amp->gpio_config(m, ~4, 0);
+                       break;
+               case 'v':
+                       /* View Current pin settings */
+                       amp->gpio_dump(amp, m);
+                       break;
+               case '\n':
+                       /* end of settings string, do nothing */
+                       break;
+               default:
+                       dev_err(dev, "io%2d bad setting: chr<0x%2x>\n",
+                               m, (int)c);
+                       err++;
+               }
+       }
+       if (err)
+               return -EINVAL; /* full string handled, report error */
+
+       return len;
+}
+
+ssize_t nsc_gpio_read(struct file *file, char __user * buf,
+                     size_t len, loff_t * ppos)
+{
+       unsigned m = iminor(file->f_dentry->d_inode);
+       int value;
+       struct nsc_gpio_ops *amp = file->private_data;
+
+       value = amp->gpio_get(m);
+       if (put_user(value ? '1' : '0', buf))
+               return -EFAULT;
+
+       return 1;
+}
+
+/* common file-ops routines for both scx200_gpio and pc87360_gpio */
+EXPORT_SYMBOL(nsc_gpio_write);
+EXPORT_SYMBOL(nsc_gpio_read);
+EXPORT_SYMBOL(nsc_gpio_dump);
+
+static int __init nsc_gpio_init(void)
+{
+       printk(KERN_DEBUG NAME " initializing\n");
+       return 0;
+}
+
+static void __exit nsc_gpio_cleanup(void)
+{
+       printk(KERN_DEBUG NAME " cleanup\n");
+}
+
+module_init(nsc_gpio_init);
+module_exit(nsc_gpio_cleanup);
+
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("NatSemi GPIO Common Methods");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
new file mode 100644 (file)
index 0000000..1c706cc
--- /dev/null
@@ -0,0 +1,340 @@
+/* linux/drivers/char/pc8736x_gpio.c
+
+   National Semiconductor PC8736x GPIO driver.  Allows a user space
+   process to play with the GPIO pins.
+
+   Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com>
+
+   adapted from linux/drivers/char/scx200_gpio.c
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>,
+*/
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/mutex.h>
+#include <linux/nsc_gpio.h>
+#include <linux/platform_device.h>
+#include <asm/uaccess.h>
+
+#define DEVNAME "pc8736x_gpio"
+
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("NatSemi PC-8736x GPIO Pin Driver");
+MODULE_LICENSE("GPL");
+
+static int major;              /* default to dynamic major */
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+
+static DEFINE_MUTEX(pc8736x_gpio_config_lock);
+static unsigned pc8736x_gpio_base;
+static u8 pc8736x_gpio_shadow[4];
+
+#define SIO_BASE1       0x2E   /* 1st command-reg to check */
+#define SIO_BASE2       0x4E   /* alt command-reg to check */
+#define SIO_BASE_OFFSET 0x20
+
+#define SIO_SID                0x20    /* SuperI/O ID Register */
+#define SIO_SID_VALUE  0xe9    /* Expected value in SuperI/O ID Register */
+
+#define SIO_CF1                0x21    /* chip config, bit0 is chip enable */
+
+#define PC8736X_GPIO_SIZE      16
+
+#define SIO_UNIT_SEL   0x7     /* unit select reg */
+#define SIO_UNIT_ACT   0x30    /* unit enable */
+#define SIO_GPIO_UNIT  0x7     /* unit number of GPIO */
+#define SIO_VLM_UNIT   0x0D
+#define SIO_TMS_UNIT   0x0E
+
+/* config-space addrs to read/write each unit's runtime addr */
+#define SIO_BASE_HADDR         0x60
+#define SIO_BASE_LADDR         0x61
+
+/* GPIO config-space pin-control addresses */
+#define SIO_GPIO_PIN_SELECT    0xF0
+#define SIO_GPIO_PIN_CONFIG     0xF1
+#define SIO_GPIO_PIN_EVENT      0xF2
+
+static unsigned char superio_cmd = 0;
+static unsigned char selected_device = 0xFF;   /* bogus start val */
+
+/* GPIO port runtime access, functionality */
+static int port_offset[] = { 0, 4, 8, 10 };    /* non-uniform offsets ! */
+/* static int event_capable[] = { 1, 1, 0, 0 };   ports 2,3 are hobbled */
+
+#define PORT_OUT       0
+#define PORT_IN                1
+#define PORT_EVT_EN    2
+#define PORT_EVT_STST  3
+
+static struct platform_device *pdev;  /* use in dev_*() */
+
+static inline void superio_outb(int addr, int val)
+{
+       outb_p(addr, superio_cmd);
+       outb_p(val, superio_cmd + 1);
+}
+
+static inline int superio_inb(int addr)
+{
+       outb_p(addr, superio_cmd);
+       return inb_p(superio_cmd + 1);
+}
+
+static int pc8736x_superio_present(void)
+{
+       /* try the 2 possible values, read a hardware reg to verify */
+       superio_cmd = SIO_BASE1;
+       if (superio_inb(SIO_SID) == SIO_SID_VALUE)
+               return superio_cmd;
+
+       superio_cmd = SIO_BASE2;
+       if (superio_inb(SIO_SID) == SIO_SID_VALUE)
+               return superio_cmd;
+
+       return 0;
+}
+
+static void device_select(unsigned devldn)
+{
+       superio_outb(SIO_UNIT_SEL, devldn);
+       selected_device = devldn;
+}
+
+static void select_pin(unsigned iminor)
+{
+       /* select GPIO port/pin from device minor number */
+       device_select(SIO_GPIO_UNIT);
+       superio_outb(SIO_GPIO_PIN_SELECT,
+                    ((iminor << 1) & 0xF0) | (iminor & 0x7));
+}
+
+static inline u32 pc8736x_gpio_configure_fn(unsigned index, u32 mask, u32 bits,
+                                           u32 func_slct)
+{
+       u32 config, new_config;
+
+       mutex_lock(&pc8736x_gpio_config_lock);
+
+       device_select(SIO_GPIO_UNIT);
+       select_pin(index);
+
+       /* read current config value */
+       config = superio_inb(func_slct);
+
+       /* set new config */
+       new_config = (config & mask) | bits;
+       superio_outb(func_slct, new_config);
+
+       mutex_unlock(&pc8736x_gpio_config_lock);
+
+       return config;
+}
+
+static u32 pc8736x_gpio_configure(unsigned index, u32 mask, u32 bits)
+{
+       return pc8736x_gpio_configure_fn(index, mask, bits,
+                                        SIO_GPIO_PIN_CONFIG);
+}
+
+static int pc8736x_gpio_get(unsigned minor)
+{
+       int port, bit, val;
+
+       port = minor >> 3;
+       bit = minor & 7;
+       val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN);
+       val >>= bit;
+       val &= 1;
+
+       dev_dbg(&pdev->dev, "_gpio_get(%d from %x bit %d) == val %d\n",
+               minor, pc8736x_gpio_base + port_offset[port] + PORT_IN, bit,
+               val);
+
+       return val;
+}
+
+static void pc8736x_gpio_set(unsigned minor, int val)
+{
+       int port, bit, curval;
+
+       minor &= 0x1f;
+       port = minor >> 3;
+       bit = minor & 7;
+       curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+
+       dev_dbg(&pdev->dev, "addr:%x cur:%x bit-pos:%d cur-bit:%x + new:%d -> bit-new:%d\n",
+               pc8736x_gpio_base + port_offset[port] + PORT_OUT,
+               curval, bit, (curval & ~(1 << bit)), val, (val << bit));
+
+       val = (curval & ~(1 << bit)) | (val << bit);
+
+       dev_dbg(&pdev->dev, "gpio_set(minor:%d port:%d bit:%d)"
+               " %2x -> %2x\n", minor, port, bit, curval, val);
+
+       outb_p(val, pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+
+       curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+       val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN);
+
+       dev_dbg(&pdev->dev, "wrote %x, read: %x\n", curval, val);
+       pc8736x_gpio_shadow[port] = val;
+}
+
+static void pc8736x_gpio_set_high(unsigned index)
+{
+       pc8736x_gpio_set(index, 1);
+}
+
+static void pc8736x_gpio_set_low(unsigned index)
+{
+       pc8736x_gpio_set(index, 0);
+}
+
+static int pc8736x_gpio_current(unsigned minor)
+{
+       int port, bit;
+       minor &= 0x1f;
+       port = minor >> 3;
+       bit = minor & 7;
+       return ((pc8736x_gpio_shadow[port] >> bit) & 0x01);
+}
+
+static void pc8736x_gpio_change(unsigned index)
+{
+       pc8736x_gpio_set(index, !pc8736x_gpio_current(index));
+}
+
+static struct nsc_gpio_ops pc8736x_access = {
+       .owner          = THIS_MODULE,
+       .gpio_config    = pc8736x_gpio_configure,
+       .gpio_dump      = nsc_gpio_dump,
+       .gpio_get       = pc8736x_gpio_get,
+       .gpio_set       = pc8736x_gpio_set,
+       .gpio_set_high  = pc8736x_gpio_set_high,
+       .gpio_set_low   = pc8736x_gpio_set_low,
+       .gpio_change    = pc8736x_gpio_change,
+       .gpio_current   = pc8736x_gpio_current
+};
+
+static int pc8736x_gpio_open(struct inode *inode, struct file *file)
+{
+       unsigned m = iminor(inode);
+       file->private_data = &pc8736x_access;
+
+       dev_dbg(&pdev->dev, "open %d\n", m);
+
+       if (m > 63)
+               return -EINVAL;
+       return nonseekable_open(inode, file);
+}
+
+static struct file_operations pc8736x_gpio_fops = {
+       .owner  = THIS_MODULE,
+       .open   = pc8736x_gpio_open,
+       .write  = nsc_gpio_write,
+       .read   = nsc_gpio_read,
+};
+
+static void __init pc8736x_init_shadow(void)
+{
+       int port;
+
+       /* read the current values driven on the GPIO signals */
+       for (port = 0; port < 4; ++port)
+               pc8736x_gpio_shadow[port]
+                   = inb_p(pc8736x_gpio_base + port_offset[port]
+                           + PORT_OUT);
+
+}
+
+static int __init pc8736x_gpio_init(void)
+{
+       int rc = 0;
+
+       pdev = platform_device_alloc(DEVNAME, 0);
+       if (!pdev)
+               return -ENOMEM;
+
+       rc = platform_device_add(pdev);
+       if (rc) {
+               rc = -ENODEV;
+               goto undo_platform_dev_alloc;
+       }
+       dev_info(&pdev->dev, "NatSemi pc8736x GPIO Driver Initializing\n");
+
+       if (!pc8736x_superio_present()) {
+               rc = -ENODEV;
+               dev_err(&pdev->dev, "no device found\n");
+               goto undo_platform_dev_add;
+       }
+       pc8736x_access.dev = &pdev->dev;
+
+       /* Verify that chip and it's GPIO unit are both enabled.
+          My BIOS does this, so I take minimum action here
+        */
+       rc = superio_inb(SIO_CF1);
+       if (!(rc & 0x01)) {
+               rc = -ENODEV;
+               dev_err(&pdev->dev, "device not enabled\n");
+               goto undo_platform_dev_add;
+       }
+       device_select(SIO_GPIO_UNIT);
+       if (!superio_inb(SIO_UNIT_ACT)) {
+               rc = -ENODEV;
+               dev_err(&pdev->dev, "GPIO unit not enabled\n");
+               goto undo_platform_dev_add;
+       }
+
+       /* read the GPIO unit base addr that chip responds to */
+       pc8736x_gpio_base = (superio_inb(SIO_BASE_HADDR) << 8
+                            | superio_inb(SIO_BASE_LADDR));
+
+       if (!request_region(pc8736x_gpio_base, 16, DEVNAME)) {
+               rc = -ENODEV;
+               dev_err(&pdev->dev, "GPIO ioport %x busy\n",
+                       pc8736x_gpio_base);
+               goto undo_platform_dev_add;
+       }
+       dev_info(&pdev->dev, "GPIO ioport %x reserved\n", pc8736x_gpio_base);
+
+       rc = register_chrdev(major, DEVNAME, &pc8736x_gpio_fops);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc);
+               goto undo_platform_dev_add;
+       }
+       if (!major) {
+               major = rc;
+               dev_dbg(&pdev->dev, "got dynamic major %d\n", major);
+       }
+
+       pc8736x_init_shadow();
+       return 0;
+
+undo_platform_dev_add:
+       platform_device_put(pdev);
+undo_platform_dev_alloc:
+       kfree(pdev);
+       return rc;
+}
+
+static void __exit pc8736x_gpio_cleanup(void)
+{
+       dev_dbg(&pdev->dev, " cleanup\n");
+
+       release_region(pc8736x_gpio_base, 16);
+
+       unregister_chrdev(major, DEVNAME);
+}
+
+EXPORT_SYMBOL(pc8736x_access);
+
+module_init(pc8736x_gpio_init);
+module_exit(pc8736x_gpio_cleanup);
index 9b5a2c0e7008c82183649e6006784088ceabd220..0c17f61549b432b5d395aa39ee9b1d6e3036d26a 100644 (file)
@@ -101,7 +101,7 @@ static void pty_unthrottle(struct tty_struct * tty)
  *
  * FIXME: Our pty_write method is called with our ldisc lock held but
  * not our partners. We can't just take the other one blindly without
- * risking deadlocks.  There is also the small matter of TTY_DONT_FLIP
+ * risking deadlocks.
  */
 static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
 {
index 664a6e97eb1a8012475625af6383825a3d885e20..5a280a330401f76924b57d4031457439670f504e 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/drivers/char/scx200_gpio.c 
+/* linux/drivers/char/scx200_gpio.c
 
    National Semiconductor SCx200 GPIO driver.  Allows a user space
    process to play with the GPIO pins.
@@ -6,17 +6,26 @@
    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
 
 #include <linux/config.h>
+#include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+#include <linux/types.h>
+#include <linux/cdev.h>
+
 #include <linux/scx200_gpio.h>
+#include <linux/nsc_gpio.h>
 
 #define NAME "scx200_gpio"
+#define DEVNAME NAME
+
+static struct platform_device *pdev;
 
 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
 MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
@@ -26,70 +35,23 @@ static int major = 0;               /* default to dynamic major */
 module_param(major, int, 0);
 MODULE_PARM_DESC(major, "Major device number");
 
-static ssize_t scx200_gpio_write(struct file *file, const char __user *data, 
-                                size_t len, loff_t *ppos)
-{
-       unsigned m = iminor(file->f_dentry->d_inode);
-       size_t i;
-
-       for (i = 0; i < len; ++i) {
-               char c;
-               if (get_user(c, data+i))
-                       return -EFAULT;
-               switch (c)
-               {
-               case '0': 
-                       scx200_gpio_set(m, 0); 
-                       break;
-               case '1': 
-                       scx200_gpio_set(m, 1); 
-                       break;
-               case 'O':
-                       printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
-                       scx200_gpio_configure(m, ~1, 1);
-                       break;
-               case 'o':
-                       printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
-                       scx200_gpio_configure(m, ~1, 0);
-                       break;
-               case 'T':
-                       printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
-                       scx200_gpio_configure(m, ~2, 2);
-                       break;
-               case 't':
-                       printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
-                       scx200_gpio_configure(m, ~2, 0);
-                       break;
-               case 'P':
-                       printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
-                       scx200_gpio_configure(m, ~4, 4);
-                       break;
-               case 'p':
-                       printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
-                       scx200_gpio_configure(m, ~4, 0);
-                       break;
-               }
-       }
-
-       return len;
-}
-
-static ssize_t scx200_gpio_read(struct file *file, char __user *buf,
-                               size_t len, loff_t *ppos)
-{
-       unsigned m = iminor(file->f_dentry->d_inode);
-       int value;
-
-       value = scx200_gpio_get(m);
-       if (put_user(value ? '1' : '0', buf))
-               return -EFAULT;
-       
-       return 1;
-}
+struct nsc_gpio_ops scx200_access = {
+       .owner          = THIS_MODULE,
+       .gpio_config    = scx200_gpio_configure,
+       .gpio_dump      = nsc_gpio_dump,
+       .gpio_get       = scx200_gpio_get,
+       .gpio_set       = scx200_gpio_set,
+       .gpio_set_high  = scx200_gpio_set_high,
+       .gpio_set_low   = scx200_gpio_set_low,
+       .gpio_change    = scx200_gpio_change,
+       .gpio_current   = scx200_gpio_current
+};
 
 static int scx200_gpio_open(struct inode *inode, struct file *file)
 {
        unsigned m = iminor(inode);
+       file->private_data = &scx200_access;
+
        if (m > 63)
                return -EINVAL;
        return nonseekable_open(inode, file);
@@ -103,47 +65,81 @@ static int scx200_gpio_release(struct inode *inode, struct file *file)
 
 static struct file_operations scx200_gpio_fops = {
        .owner   = THIS_MODULE,
-       .write   = scx200_gpio_write,
-       .read    = scx200_gpio_read,
+       .write   = nsc_gpio_write,
+       .read    = nsc_gpio_read,
        .open    = scx200_gpio_open,
        .release = scx200_gpio_release,
 };
 
+struct cdev *scx200_devices;
+static int num_pins = 32;
+
 static int __init scx200_gpio_init(void)
 {
-       int r;
-
-       printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
+       int rc, i;
+       dev_t dev = MKDEV(major, 0);
 
        if (!scx200_gpio_present()) {
-               printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+               printk(KERN_ERR NAME ": no SCx200 gpio present\n");
                return -ENODEV;
        }
 
-       r = register_chrdev(major, NAME, &scx200_gpio_fops);
-       if (r < 0) {
-               printk(KERN_ERR NAME ": unable to register character device\n");
-               return r;
+       /* support dev_dbg() with pdev->dev */
+       pdev = platform_device_alloc(DEVNAME, 0);
+       if (!pdev)
+               return -ENOMEM;
+
+       rc = platform_device_add(pdev);
+       if (rc)
+               goto undo_malloc;
+
+       /* nsc_gpio uses dev_dbg(), so needs this */
+       scx200_access.dev = &pdev->dev;
+
+       if (major)
+               rc = register_chrdev_region(dev, num_pins, "scx200_gpio");
+       else {
+               rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio");
+               major = MAJOR(dev);
        }
-       if (!major) {
-               major = r;
-               printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc);
+               goto undo_platform_device_add;
+       }
+       scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL);
+       if (!scx200_devices) {
+               rc = -ENOMEM;
+               goto undo_chrdev_region;
+       }
+       for (i = 0; i < num_pins; i++) {
+               struct cdev *cdev = &scx200_devices[i];
+               cdev_init(cdev, &scx200_gpio_fops);
+               cdev->owner = THIS_MODULE;
+               rc = cdev_add(cdev, MKDEV(major, i), 1);
+               /* tolerate 'minor' errors */
+               if (rc)
+                       dev_err(&pdev->dev, "Error %d on minor %d", rc, i);
        }
 
-       return 0;
+       return 0; /* succeed */
+
+undo_chrdev_region:
+       unregister_chrdev_region(dev, num_pins);
+undo_platform_device_add:
+       platform_device_put(pdev);
+undo_malloc:
+       kfree(pdev);
+       return rc;
 }
 
 static void __exit scx200_gpio_cleanup(void)
 {
-       unregister_chrdev(major, NAME);
+       kfree(scx200_devices);
+       unregister_chrdev_region(MKDEV(major, 0), num_pins);
+       platform_device_put(pdev);
+       platform_device_unregister(pdev);
+       /* kfree(pdev); */
 }
 
 module_init(scx200_gpio_init);
 module_exit(scx200_gpio_cleanup);
-
-/*
-    Local variables:
-        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
-        c-basic-offset: 8
-    End:
-*/
index 1b5330299e30fa965086eae13d601a1e80e29be3..d2d6b01dcd05a1168dbd7795ebd13d5c5be32dc9 100644 (file)
@@ -2477,7 +2477,7 @@ static int __init specialix_init(void)
 #endif
 
        for (i = 0; i < SX_NBOARD; i++)
-               sx_board[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&sx_board[i].lock);
 
        if (sx_init_drivers()) {
                func_exit();
index a9c5a7230f8958b5d8ee1338fa88c40cddf79a58..00b4a2187164ce408ebac2e3e5b3e7f3ef3291ed 100644 (file)
@@ -140,15 +140,6 @@ static char        *stl_drvversion = "5.6.0";
 
 static struct tty_driver       *stl_serial;
 
-/*
- *     We will need to allocate a temporary write buffer for chars that
- *     come direct from user space. The problem is that a copy from user
- *     space might cause a page fault (typically on a system that is
- *     swapping!). All ports will share one buffer - since if the system
- *     is already swapping a shared buffer won't make things any worse.
- */
-static char                    *stl_tmpwritebuf;
-
 /*
  *     Define a local default termios struct. All ports will be created
  *     with this termios initially. Basically all it defines is a raw port
@@ -362,6 +353,14 @@ static unsigned char       stl_vecmap[] = {
        0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03
 };
 
+/*
+ *     Lock ordering is that you may not take stallion_lock holding
+ *     brd_lock.
+ */
+
+static spinlock_t brd_lock;            /* Guard the board mapping */
+static spinlock_t stallion_lock;       /* Guard the tty driver */
+
 /*
  *     Set up enable and disable macros for the ECH boards. They require
  *     the secondary io address space to be activated and deactivated.
@@ -725,17 +724,7 @@ static struct class *stallion_class;
 
 static int __init stallion_module_init(void)
 {
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk("init_module()\n");
-#endif
-
-       save_flags(flags);
-       cli();
        stl_init();
-       restore_flags(flags);
-
        return 0;
 }
 
@@ -746,7 +735,6 @@ static void __exit stallion_module_exit(void)
        stlbrd_t        *brdp;
        stlpanel_t      *panelp;
        stlport_t       *portp;
-       unsigned long   flags;
        int             i, j, k;
 
 #ifdef DEBUG
@@ -756,9 +744,6 @@ static void __exit stallion_module_exit(void)
        printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
                stl_drvversion);
 
-       save_flags(flags);
-       cli();
-
 /*
  *     Free up all allocated resources used by the ports. This includes
  *     memory and interrupts. As part of this process we will also do
@@ -770,7 +755,6 @@ static void __exit stallion_module_exit(void)
        if (i) {
                printk("STALLION: failed to un-register tty driver, "
                        "errno=%d\n", -i);
-               restore_flags(flags);
                return;
        }
        for (i = 0; i < 4; i++) {
@@ -783,8 +767,6 @@ static void __exit stallion_module_exit(void)
                        "errno=%d\n", -i);
        class_destroy(stallion_class);
 
-       kfree(stl_tmpwritebuf);
-
        for (i = 0; (i < stl_nrbrds); i++) {
                if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
                        continue;
@@ -814,8 +796,6 @@ static void __exit stallion_module_exit(void)
                kfree(brdp);
                stl_brds[i] = (stlbrd_t *) NULL;
        }
-
-       restore_flags(flags);
 }
 
 module_init(stallion_module_init);
@@ -948,7 +928,7 @@ static stlbrd_t *stl_allocbrd(void)
 
        brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL);
        if (!brdp) {
-               printk("STALLION: failed to allocate memory (size=%d)\n",
+               printk("STALLION: failed to allocate memory (size=%Zd)\n",
                        sizeof(stlbrd_t));
                return NULL;
        }
@@ -1066,16 +1046,17 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
        rc = 0;
        doclocal = 0;
 
+       spin_lock_irqsave(&stallion_lock, flags);
+
        if (portp->tty->termios->c_cflag & CLOCAL)
                doclocal++;
 
-       save_flags(flags);
-       cli();
        portp->openwaitcnt++;
        if (! tty_hung_up_p(filp))
                portp->refcount--;
 
        for (;;) {
+               /* Takes brd_lock internally */
                stl_setsignals(portp, 1, 1);
                if (tty_hung_up_p(filp) ||
                    ((portp->flags & ASYNC_INITIALIZED) == 0)) {
@@ -1093,13 +1074,14 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
                        rc = -ERESTARTSYS;
                        break;
                }
+               /* FIXME */
                interruptible_sleep_on(&portp->open_wait);
        }
 
        if (! tty_hung_up_p(filp))
                portp->refcount++;
        portp->openwaitcnt--;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&stallion_lock, flags);
 
        return rc;
 }
@@ -1119,16 +1101,15 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
        if (portp == (stlport_t *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&stallion_lock, flags);
        if (tty_hung_up_p(filp)) {
-               restore_flags(flags);
+               spin_unlock_irqrestore(&stallion_lock, flags);
                return;
        }
        if ((tty->count == 1) && (portp->refcount != 1))
                portp->refcount = 1;
        if (portp->refcount-- > 1) {
-               restore_flags(flags);
+               spin_unlock_irqrestore(&stallion_lock, flags);
                return;
        }
 
@@ -1142,11 +1123,18 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
  *     (The sc26198 has no "end-of-data" interrupt only empty FIFO)
  */
        tty->closing = 1;
+
+       spin_unlock_irqrestore(&stallion_lock, flags);
+
        if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
                tty_wait_until_sent(tty, portp->closing_wait);
        stl_waituntilsent(tty, (HZ / 2));
 
+
+       spin_lock_irqsave(&stallion_lock, flags);
        portp->flags &= ~ASYNC_INITIALIZED;
+       spin_unlock_irqrestore(&stallion_lock, flags);
+
        stl_disableintrs(portp);
        if (tty->termios->c_cflag & HUPCL)
                stl_setsignals(portp, 0, 0);
@@ -1173,7 +1161,6 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
 
        portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
        wake_up_interruptible(&portp->close_wait);
-       restore_flags(flags);
 }
 
 /*****************************************************************************/
@@ -1195,9 +1182,6 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count
                (int) tty, (int) buf, count);
 #endif
 
-       if ((tty == (struct tty_struct *) NULL) ||
-           (stl_tmpwritebuf == (char *) NULL))
-               return 0;
        portp = tty->driver_data;
        if (portp == (stlport_t *) NULL)
                return 0;
@@ -1302,11 +1286,6 @@ static void stl_flushchars(struct tty_struct *tty)
        if (portp->tx.buf == (char *) NULL)
                return;
 
-#if 0
-       if (tty->stopped || tty->hw_stopped ||
-           (portp->tx.head == portp->tx.tail))
-               return;
-#endif
        stl_startrxtx(portp, -1, 1);
 }
 
@@ -1977,12 +1956,14 @@ static int stl_eiointr(stlbrd_t *brdp)
        unsigned int    iobase;
        int             handled = 0;
 
+       spin_lock(&brd_lock);
        panelp = brdp->panels[0];
        iobase = panelp->iobase;
        while (inb(brdp->iostatus) & EIO_INTRPEND) {
                handled = 1;
                (* panelp->isr)(panelp, iobase);
        }
+       spin_unlock(&brd_lock);
        return handled;
 }
 
@@ -2168,7 +2149,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
                portp = kzalloc(sizeof(stlport_t), GFP_KERNEL);
                if (!portp) {
                        printk("STALLION: failed to allocate memory "
-                               "(size=%d)\n", sizeof(stlport_t));
+                               "(size=%Zd)\n", sizeof(stlport_t));
                        break;
                }
 
@@ -2304,7 +2285,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
        panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
        if (!panelp) {
                printk(KERN_WARNING "STALLION: failed to allocate memory "
-                       "(size=%d)\n", sizeof(stlpanel_t));
+                       "(size=%Zd)\n", sizeof(stlpanel_t));
                return -ENOMEM;
        }
 
@@ -2478,7 +2459,7 @@ static inline int stl_initech(stlbrd_t *brdp)
                panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
                if (!panelp) {
                        printk("STALLION: failed to allocate memory "
-                               "(size=%d)\n", sizeof(stlpanel_t));
+                               "(size=%Zd)\n", sizeof(stlpanel_t));
                        break;
                }
                panelp->magic = STL_PANELMAGIC;
@@ -2879,8 +2860,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
        portp->stats.lflags = 0;
        portp->stats.rxbuffered = 0;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&stallion_lock, flags);
        if (portp->tty != (struct tty_struct *) NULL) {
                if (portp->tty->driver_data == portp) {
                        portp->stats.ttystate = portp->tty->flags;
@@ -2894,7 +2874,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
                        }
                }
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&stallion_lock, flags);
 
        head = portp->tx.head;
        tail = portp->tx.tail;
@@ -3049,20 +3029,15 @@ static int __init stl_init(void)
        int i;
        printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
 
+       spin_lock_init(&stallion_lock);
+       spin_lock_init(&brd_lock);
+
        stl_initbrds();
 
        stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
        if (!stl_serial)
                return -1;
 
-/*
- *     Allocate a temporary write buffer.
- */
-       stl_tmpwritebuf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
-       if (!stl_tmpwritebuf)
-               printk("STALLION: failed to allocate memory (size=%d)\n",
-                       STL_TXBUFSIZE);
-
 /*
  *     Set up a character driver for per board stuff. This is mainly used
  *     to do stats ioctls on the ports.
@@ -3147,11 +3122,13 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
        unsigned int    gfrcr;
        int             chipmask, i, j;
        int             nrchips, uartaddr, ioaddr;
+       unsigned long   flags;
 
 #ifdef DEBUG
        printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
 #endif
 
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(panelp->brdnr, panelp->pagenr);
 
 /*
@@ -3189,6 +3166,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
        }
 
        BRDDISABLE(panelp->brdnr);
+       spin_unlock_irqrestore(&brd_lock, flags);
        return chipmask;
 }
 
@@ -3200,6 +3178,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
 
 static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
 {
+       unsigned long flags;
 #ifdef DEBUG
        printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n",
                (int) brdp, (int) panelp, (int) portp);
@@ -3209,6 +3188,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po
            (portp == (stlport_t *) NULL))
                return;
 
+       spin_lock_irqsave(&brd_lock, flags);
        portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) ||
                (portp->portnr < 8)) ? 0 : EREG_BANKSIZE);
        portp->uartaddr = (portp->portnr & 0x04) << 5;
@@ -3219,6 +3199,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po
        stl_cd1400setreg(portp, LIVR, (portp->portnr << 3));
        portp->hwid = stl_cd1400getreg(portp, GFRCR);
        BRDDISABLE(portp->brdnr);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3428,8 +3409,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
                tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3));
        srer = stl_cd1400getreg(portp, SRER);
@@ -3466,7 +3446,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
                portp->sigs &= ~TIOCM_CD;
        stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron));
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3492,8 +3472,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
        if (rts > 0)
                msvr2 = MSVR2_RTS;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        if (rts >= 0)
@@ -3501,7 +3480,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
        if (dtr >= 0)
                stl_cd1400setreg(portp, MSVR1, msvr1);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3520,14 +3499,13 @@ static int stl_cd1400getsignals(stlport_t *portp)
        printk("stl_cd1400getsignals(portp=%x)\n", (int) portp);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        msvr1 = stl_cd1400getreg(portp, MSVR1);
        msvr2 = stl_cd1400getreg(portp, MSVR2);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        sigs = 0;
        sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
@@ -3569,15 +3547,14 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx)
        else if (rx > 0)
                ccr |= CCR_RXENABLE;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400ccrwait(portp);
        stl_cd1400setreg(portp, CCR, ccr);
        stl_cd1400ccrwait(portp);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3609,8 +3586,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
        else if (rx > 0)
                sreron |= SRER_RXDATA;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400setreg(portp, SRER,
@@ -3618,7 +3594,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
        BRDDISABLE(portp->brdnr);
        if (tx > 0)
                set_bit(ASYI_TXBUSY, &portp->istate);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3634,13 +3610,12 @@ static void stl_cd1400disableintrs(stlport_t *portp)
 #ifdef DEBUG
        printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp);
 #endif
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400setreg(portp, SRER, 0);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3653,8 +3628,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len)
        printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400setreg(portp, SRER,
@@ -3664,7 +3638,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len)
        portp->brklen = len;
        if (len == 1)
                portp->stats.txbreaks++;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3688,8 +3662,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state)
        if (tty == (struct tty_struct *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
 
@@ -3729,7 +3702,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state)
        }
 
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3753,8 +3726,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state)
        if (tty == (struct tty_struct *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        if (state) {
@@ -3769,7 +3741,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state)
                stl_cd1400ccrwait(portp);
        }
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3785,8 +3757,7 @@ static void stl_cd1400flush(stlport_t *portp)
        if (portp == (stlport_t *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400ccrwait(portp);
@@ -3794,7 +3765,7 @@ static void stl_cd1400flush(stlport_t *portp)
        stl_cd1400ccrwait(portp);
        portp->tx.tail = portp->tx.head;
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3833,6 +3804,7 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
                (int) panelp, iobase);
 #endif
 
+       spin_lock(&brd_lock);
        outb(SVRR, iobase);
        svrtype = inb(iobase + EREG_DATA);
        if (panelp->nrports > 4) {
@@ -3846,6 +3818,8 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
                stl_cd1400txisr(panelp, iobase);
        else if (svrtype & SVRR_MDM)
                stl_cd1400mdmisr(panelp, iobase);
+
+       spin_unlock(&brd_lock);
 }
 
 /*****************************************************************************/
@@ -4433,8 +4407,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
                tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, IMR, 0);
        stl_sc26198updatereg(portp, MR0, mr0);
@@ -4461,7 +4434,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
        portp->imr = (portp->imr & ~imroff) | imron;
        stl_sc26198setreg(portp, IMR, portp->imr);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4491,13 +4464,12 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts)
        else if (rts > 0)
                iopioron |= IPR_RTS;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, IOPIOR,
                ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron));
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4516,12 +4488,11 @@ static int stl_sc26198getsignals(stlport_t *portp)
        printk("stl_sc26198getsignals(portp=%x)\n", (int) portp);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        ipr = stl_sc26198getreg(portp, IPR);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        sigs = 0;
        sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD;
@@ -4558,13 +4529,12 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx)
        else if (rx > 0)
                ccr |= CR_RXENABLE;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, SCCR, ccr);
        BRDDISABLE(portp->brdnr);
        portp->crenable = ccr;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4593,15 +4563,14 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx)
        else if (rx > 0)
                imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, IMR, imr);
        BRDDISABLE(portp->brdnr);
        portp->imr = imr;
        if (tx > 0)
                set_bit(ASYI_TXBUSY, &portp->istate);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4618,13 +4587,12 @@ static void stl_sc26198disableintrs(stlport_t *portp)
        printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        portp->imr = 0;
        stl_sc26198setreg(portp, IMR, 0);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4637,8 +4605,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len)
        printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        if (len == 1) {
                stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
@@ -4647,7 +4614,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len)
                stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
        }
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4672,8 +4639,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state)
        if (tty == (struct tty_struct *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
 
        if (state) {
@@ -4719,7 +4685,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state)
        }
 
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4744,8 +4710,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state)
        if (tty == (struct tty_struct *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        if (state) {
                mr0 = stl_sc26198getreg(portp, MR0);
@@ -4765,7 +4730,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state)
                stl_sc26198setreg(portp, MR0, mr0);
        }
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4781,14 +4746,13 @@ static void stl_sc26198flush(stlport_t *portp)
        if (portp == (stlport_t *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, SCCR, CR_TXRESET);
        stl_sc26198setreg(portp, SCCR, portp->crenable);
        BRDDISABLE(portp->brdnr);
        portp->tx.tail = portp->tx.head;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4815,12 +4779,11 @@ static int stl_sc26198datastate(stlport_t *portp)
        if (test_bit(ASYI_TXBUSY, &portp->istate))
                return 1;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        sr = stl_sc26198getreg(portp, SR);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        return (sr & SR_TXEMPTY) ? 0 : 1;
 }
@@ -4878,6 +4841,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
        stlport_t       *portp;
        unsigned int    iack;
 
+       spin_lock(&brd_lock);
+
 /* 
  *     Work around bug in sc26198 chip... Cannot have A6 address
  *     line of UART high, else iack will be returned as 0.
@@ -4893,6 +4858,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
                stl_sc26198txisr(portp);
        else
                stl_sc26198otherisr(portp, iack);
+
+       spin_unlock(&brd_lock);
 }
 
 /*****************************************************************************/
index 3b4747230270a3dc38fbdcc12fab013ee5a23439..76b9107f7f814b53bda55814e3d5e8d890b02b44 100644 (file)
@@ -2320,7 +2320,7 @@ static int sx_init_portstructs (int nboards, int nports)
 #ifdef NEW_WRITE_LOCKING
                        port->gs.port_write_mutex = MUTEX;
 #endif
-                       port->gs.driver_lock = SPIN_LOCK_UNLOCKED;
+                       spin_lock_init(&port->gs.driver_lock);
                        /*
                         * Initializing wait queue
                         */
index 8b2a5996986819b62eccb4ffdb436d1d3903521a..8d19f7281f0b4b1bab12b801b8ff141e349bd495 100644 (file)
@@ -267,7 +267,6 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
        p->used = 0;
        p->size = size;
        p->next = NULL;
-       p->active = 0;
        p->commit = 0;
        p->read = 0;
        p->char_buf_ptr = (char *)(p->data);
@@ -327,10 +326,9 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
        /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
           remove this conditional if its worth it. This would be invisible
           to the callers */
-       if ((b = tty->buf.tail) != NULL) {
+       if ((b = tty->buf.tail) != NULL)
                left = b->size - b->used;
-               b->active = 1;
-       } else
+       else
                left = 0;
 
        if (left < size) {
@@ -338,12 +336,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
                if ((n = tty_buffer_find(tty, size)) != NULL) {
                        if (b != NULL) {
                                b->next = n;
-                               b->active = 0;
                                b->commit = b->used;
                        } else
                                tty->buf.head = n;
                        tty->buf.tail = n;
-                       n->active = 1;
                } else
                        size = left;
        }
@@ -404,10 +400,8 @@ void tty_schedule_flip(struct tty_struct *tty)
 {
        unsigned long flags;
        spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL) {
-               tty->buf.tail->active = 0;
+       if (tty->buf.tail != NULL)
                tty->buf.tail->commit = tty->buf.tail->used;
-       }
        spin_unlock_irqrestore(&tty->buf.lock, flags);
        schedule_delayed_work(&tty->buf.work, 1);
 }
@@ -784,11 +778,8 @@ restart:
        }
 
        clear_bit(TTY_LDISC, &tty->flags);
-       clear_bit(TTY_DONT_FLIP, &tty->flags);
-       if (o_tty) {
+       if (o_tty)
                clear_bit(TTY_LDISC, &o_tty->flags);
-               clear_bit(TTY_DONT_FLIP, &o_tty->flags);
-       }
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 
        /*
@@ -1955,7 +1946,6 @@ static void release_dev(struct file * filp)
         * race with the set_ldisc code path.
         */
        clear_bit(TTY_LDISC, &tty->flags);
-       clear_bit(TTY_DONT_FLIP, &tty->flags);
        cancel_delayed_work(&tty->buf.work);
 
        /*
@@ -2621,10 +2611,9 @@ int tty_ioctl(struct inode * inode, struct file * file,
                        tty->driver->break_ctl(tty, 0);
                        return 0;
                case TCSBRK:   /* SVID version: non-zero arg --> no break */
-                       /*
-                        * XXX is the above comment correct, or the
-                        * code below correct?  Is this ioctl used at
-                        * all by anyone?
+                       /* non-zero arg means wait for all output data
+                        * to be sent (performed above) but don't send break.
+                        * This is used by the tcdrain() termios function.
                         */
                        if (!arg)
                                return send_break(tty, 250);
@@ -2776,8 +2765,7 @@ static void flush_to_ldisc(void *private_)
        struct tty_struct *tty = (struct tty_struct *) private_;
        unsigned long   flags;
        struct tty_ldisc *disc;
-       struct tty_buffer *tbuf;
-       int count;
+       struct tty_buffer *tbuf, *head;
        char *char_buf;
        unsigned char *flag_buf;
 
@@ -2785,32 +2773,37 @@ static void flush_to_ldisc(void *private_)
        if (disc == NULL)       /*  !TTY_LDISC */
                return;
 
-       if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-               /*
-                * Do it after the next timer tick:
-                */
-               schedule_delayed_work(&tty->buf.work, 1);
-               goto out;
-       }
        spin_lock_irqsave(&tty->buf.lock, flags);
-       while((tbuf = tty->buf.head) != NULL) {
-               while ((count = tbuf->commit - tbuf->read) != 0) {
-                       char_buf = tbuf->char_buf_ptr + tbuf->read;
-                       flag_buf = tbuf->flag_buf_ptr + tbuf->read;
-                       tbuf->read += count;
+       head = tty->buf.head;
+       if (head != NULL) {
+               tty->buf.head = NULL;
+               for (;;) {
+                       int count = head->commit - head->read;
+                       if (!count) {
+                               if (head->next == NULL)
+                                       break;
+                               tbuf = head;
+                               head = head->next;
+                               tty_buffer_free(tty, tbuf);
+                               continue;
+                       }
+                       if (!tty->receive_room) {
+                               schedule_delayed_work(&tty->buf.work, 1);
+                               break;
+                       }
+                       if (count > tty->receive_room)
+                               count = tty->receive_room;
+                       char_buf = head->char_buf_ptr + head->read;
+                       flag_buf = head->flag_buf_ptr + head->read;
+                       head->read += count;
                        spin_unlock_irqrestore(&tty->buf.lock, flags);
                        disc->receive_buf(tty, char_buf, flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
                }
-               if (tbuf->active)
-                       break;
-               tty->buf.head = tbuf->next;
-               if (tty->buf.head == NULL)
-                       tty->buf.tail = NULL;
-               tty_buffer_free(tty, tbuf);
+               tty->buf.head = head;
        }
        spin_unlock_irqrestore(&tty->buf.lock, flags);
-out:
+
        tty_ldisc_deref(disc);
 }
 
@@ -2903,10 +2896,8 @@ void tty_flip_buffer_push(struct tty_struct *tty)
 {
        unsigned long flags;
        spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL) {
-               tty->buf.tail->active = 0;
+       if (tty->buf.tail != NULL)
                tty->buf.tail->commit = tty->buf.tail->used;
-       }
        spin_unlock_irqrestore(&tty->buf.lock, flags);
 
        if (tty->low_latency)
index 05e6e814d86fd64d4670dccd38fe8e1eb7132138..073da48c092e0ae804cc6354b9c897c668b6033c 100644 (file)
@@ -689,9 +689,9 @@ static int __devinit giu_probe(struct platform_device *dev)
 
        for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
                if (i < GIU_IRQ(GIUINT_HIGH_OFFSET))
-                       irq_desc[i].handler = &giuint_low_irq_type;
+                       irq_desc[i].chip = &giuint_low_irq_type;
                else
-                       irq_desc[i].handler = &giuint_high_irq_type;
+                       irq_desc[i].chip = &giuint_high_irq_type;
        }
 
        return cascade_irq(GIUINT_IRQ, giu_get_irq);
index ac83bc4b019adabb47c21081e7b2b1ca2b485ca6..00080655533d338ae6438b8b3d37c4707f125fff 100644 (file)
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
 
-#define WDT_DEFAULT_TIME       5       /* seconds */
-#define WDT_MAX_TIME           256     /* 256 seconds */
+#define WDT_DEFAULT_TIME       5       /* seconds */
+#define WDT_MAX_TIME           256     /* seconds */
 
 static int wdt_time = WDT_DEFAULT_TIME;
 static int nowayout = WATCHDOG_NOWAYOUT;
@@ -32,8 +33,10 @@ static int nowayout = WATCHDOG_NOWAYOUT;
 module_param(wdt_time, int, 0);
 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+#endif
 
 
 static unsigned long at91wdt_busy;
@@ -138,7 +141,7 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file,
                case WDIOC_SETTIMEOUT:
                        if (get_user(new_value, p))
                                return -EFAULT;
-                               
+
                        if (at91_wdt_settimeout(new_value))
                                return -EINVAL;
 
@@ -196,27 +199,84 @@ static struct miscdevice at91wdt_miscdev = {
        .fops           = &at91wdt_fops,
 };
 
-static int __init at91_wdt_init(void)
+static int __init at91wdt_probe(struct platform_device *pdev)
 {
        int res;
 
-       /* Check that the heartbeat value is within range; if not reset to the default */
-       if (at91_wdt_settimeout(wdt_time)) {
-               at91_wdt_settimeout(WDT_DEFAULT_TIME);
-               printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
-       }
+       if (at91wdt_miscdev.dev)
+               return -EBUSY;
+       at91wdt_miscdev.dev = &pdev->dev;
 
        res = misc_register(&at91wdt_miscdev);
        if (res)
                return res;
 
-       printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout);
+       printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
        return 0;
 }
 
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+       int res;
+
+       res = misc_deregister(&at91wdt_miscdev);
+       if (!res)
+               at91wdt_miscdev.dev = NULL;
+
+       return res;
+}
+
+static void at91wdt_shutdown(struct platform_device *pdev)
+{
+       at91_wdt_stop();
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+       at91_wdt_stop();
+       return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+       if (at91wdt_busy)
+               at91_wdt_start();
+               return 0;
+}
+
+#else
+#define at91wdt_suspend NULL
+#define at91wdt_resume NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+       .probe          = at91wdt_probe,
+       .remove         = __exit_p(at91wdt_remove),
+       .shutdown       = at91wdt_shutdown,
+       .suspend        = at91wdt_suspend,
+       .resume         = at91wdt_resume,
+       .driver         = {
+               .name   = "at91_wdt",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init at91_wdt_init(void)
+{
+       /* Check that the heartbeat value is within range; if not reset to the default */
+       if (at91_wdt_settimeout(wdt_time)) {
+               at91_wdt_settimeout(WDT_DEFAULT_TIME);
+               pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
+       }
+
+       return platform_driver_register(&at91wdt_driver);
+}
+
 static void __exit at91_wdt_exit(void)
 {
-       misc_deregister(&at91wdt_miscdev);
+       platform_driver_unregister(&at91wdt_driver);
 }
 
 module_init(at91_wdt_init);
index fa2ba9ebe42aacf3478212143547c460d877402e..bfbdbbf3c2f279a6fa2027e9837bbb4d539e6818 100644 (file)
@@ -205,6 +205,23 @@ static int tco_timer_set_heartbeat (int t)
        return 0;
 }
 
+static int tco_timer_get_timeleft (int *time_left)
+{
+       unsigned char val;
+
+       spin_lock(&tco_lock);
+
+       /* read the TCO Timer */
+       val = inb (TCO1_RLD);
+       val &= 0x3f;
+
+       spin_unlock(&tco_lock);
+
+       *time_left = (int)((val * 6) / 10);
+
+       return 0;
+}
+
 /*
  *     /dev/watchdog handling
  */
@@ -272,6 +289,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
 {
        int new_options, retval = -EINVAL;
        int new_heartbeat;
+       int time_left;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
        static struct watchdog_info ident = {
@@ -320,7 +338,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
                                return -EFAULT;
 
                        if (tco_timer_set_heartbeat(new_heartbeat))
-                           return -EINVAL;
+                               return -EINVAL;
 
                        tco_timer_keepalive ();
                        /* Fall */
@@ -329,6 +347,14 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
                case WDIOC_GETTIMEOUT:
                        return put_user(heartbeat, p);
 
+               case WDIOC_GETTIMELEFT:
+               {
+                       if (tco_timer_get_timeleft(&time_left))
+                               return -EINVAL;
+
+                       return put_user(time_left, p);
+               }
+
                default:
                        return -ENOIOCTLCMD;
        }
index 2451edbefece8ab448a5ece121a1a35ee70f87fc..1f40ecefbf7260c020c6117118975a0facfadff6 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 /*
- *     A bells and whistles driver is available from: 
+ *     A bells and whistles driver is available from:
  *     http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/
  *
  *     More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
@@ -390,6 +390,24 @@ static int pcipcwd_get_temperature(int *temperature)
        return 0;
 }
 
+static int pcipcwd_get_timeleft(int *time_left)
+{
+       int msb;
+       int lsb;
+
+       /* Read the time that's left before rebooting */
+       /* Note: if the board is not yet armed then we will read 0xFFFF */
+       send_command(CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
+
+       *time_left = (msb << 8) + lsb;
+
+       if (debug >= VERBOSE)
+               printk(KERN_DEBUG PFX "Time left before next reboot: %d\n",
+                      *time_left);
+
+       return 0;
+}
+
 /*
  *     /dev/watchdog handling
  */
@@ -512,6 +530,16 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
                case WDIOC_GETTIMEOUT:
                        return put_user(heartbeat, p);
 
+               case WDIOC_GETTIMELEFT:
+               {
+                       int time_left;
+
+                       if (pcipcwd_get_timeleft(&time_left))
+                               return -EFAULT;
+
+                       return put_user(time_left, p);
+               }
+
                default:
                        return -ENOIOCTLCMD;
        }
index 3fdfda9324fae46a3429f3191354ee4ffec4c2cf..0d072bed501dfd744796e62a58d7468060e78f55 100644 (file)
@@ -317,6 +317,19 @@ static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temp
        return 0;
 }
 
+static int usb_pcwd_get_timeleft(struct usb_pcwd_private *usb_pcwd, int *time_left)
+{
+       unsigned char msb, lsb;
+
+       /* Read the time that's left before rebooting */
+       /* Note: if the board is not yet armed then we will read 0xFFFF */
+       usb_pcwd_send_command(usb_pcwd, CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
+
+       *time_left = (msb << 8) + lsb;
+
+       return 0;
+}
+
 /*
  *     /dev/watchdog handling
  */
@@ -422,6 +435,16 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
                case WDIOC_GETTIMEOUT:
                        return put_user(heartbeat, p);
 
+               case WDIOC_GETTIMELEFT:
+               {
+                       int time_left;
+
+                       if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left))
+                               return -EFAULT;
+
+                       return put_user(time_left, p);
+               }
+
                default:
                        return -ENOIOCTLCMD;
        }
index 44d1eca83a7250748bf27c637998c3c2973f9657..35e0b9ceecf7faa90f9ab34784112533e7d48ec7 100644 (file)
@@ -1497,6 +1497,7 @@ int cpufreq_update_policy(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 
+#ifdef CONFIG_HOTPLUG_CPU
 static int cpufreq_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
@@ -1532,10 +1533,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpufreq_cpu_notifier =
+static struct notifier_block __cpuinitdata cpufreq_cpu_notifier =
 {
     .notifier_call = cpufreq_cpu_callback,
 };
+#endif /* CONFIG_HOTPLUG_CPU */
 
 /*********************************************************************
  *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
@@ -1596,7 +1598,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
        }
 
        if (!ret) {
-               register_cpu_notifier(&cpufreq_cpu_notifier);
+               register_hotcpu_notifier(&cpufreq_cpu_notifier);
                dprintk("driver %s up and running\n", driver_data->name);
                cpufreq_debug_enable_ratelimit();
        }
@@ -1628,7 +1630,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
        dprintk("unregistering driver %s\n", driver->name);
 
        sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
-       unregister_cpu_notifier(&cpufreq_cpu_notifier);
+       unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        cpufreq_driver = NULL;
index c576c0b3f452629560fd2567a1bc5735011daf92..145061b8472a814b96e1075e51876ecbb5f3f246 100644 (file)
@@ -350,7 +350,7 @@ __init cpufreq_stats_init(void)
                return ret;
        }
 
-       register_cpu_notifier(&cpufreq_stat_cpu_notifier);
+       register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        lock_cpu_hotplug();
        for_each_online_cpu(cpu) {
                cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE,
@@ -368,7 +368,7 @@ __exit cpufreq_stats_exit(void)
                        CPUFREQ_POLICY_NOTIFIER);
        cpufreq_unregister_notifier(&notifier_trans_block,
                        CPUFREQ_TRANSITION_NOTIFIER);
-       unregister_cpu_notifier(&cpufreq_stat_cpu_notifier);
+       unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        lock_cpu_hotplug();
        for_each_online_cpu(cpu) {
                cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD,
index 3e0d04d5a800b574579bbd2cecf06c6b24fc66a5..8b46ef7d9ff8365b9fda3dc8bc439a6654c90dca 100644 (file)
@@ -488,7 +488,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
                dev_err(&dev->dev, "SMBus base address uninitialized, "
                        "upgrade BIOS\n");
                err = -ENODEV;
-               goto exit_disable;
+               goto exit;
        }
 
        err = pci_request_region(dev, SMBBAR, i801_driver.name);
@@ -496,7 +496,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
                dev_err(&dev->dev, "Failed to request SMBus region "
                        "0x%lx-0x%lx\n", i801_smba,
                        pci_resource_end(dev, SMBBAR));
-               goto exit_disable;
+               goto exit;
        }
 
        pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
@@ -520,11 +520,12 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
        err = i2c_add_adapter(&i801_adapter);
        if (err) {
                dev_err(&dev->dev, "Failed to add SMBus adapter\n");
-               goto exit_disable;
+               goto exit_release;
        }
+       return 0;
 
-exit_disable:
-       pci_disable_device(dev);
+exit_release:
+       pci_release_region(dev, SMBBAR);
 exit:
        return err;
 }
@@ -533,7 +534,10 @@ static void __devexit i801_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&i801_adapter);
        pci_release_region(dev, SMBBAR);
-       pci_disable_device(dev);
+       /*
+        * do not call pci_disable_device(dev) since it can cause hard hangs on
+        * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
+        */
 }
 
 static struct pci_driver i801_driver = {
index 935cb2583770fa567c7c531dbda03d5d0f935985..26ceab1e90bb5d94f71100e6239349343cd849cc 100644 (file)
@@ -505,7 +505,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
                }
        }
 
-       if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+       if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ && hwif->err_stops_fifo == 0)
                try_to_flush_leftover_data(drive);
 
        if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
index 97a49e77a8f1f5d30d906847f202ad85ea2f08c8..32117f0ec5c00727f41fde8e0765d85449a4652b 100644 (file)
@@ -597,6 +597,10 @@ u8 eighty_ninty_three (ide_drive_t *drive)
 {
        if(HWIF(drive)->udma_four == 0)
                return 0;
+
+       /* Check for SATA but only if we are ATA5 or higher */
+       if (drive->id->hw_config == 0 && (drive->id->major_rev_num & 0x7FE0))
+               return 1;
        if (!(drive->id->hw_config & 0x6000))
                return 0;
 #ifndef CONFIG_IDEDMA_IVB
index c743e68c33aadca3894017ed2ba1c82cde5cff52..3edd7060510fa6e668e46cc6deb1000fe4c4fc69 100644 (file)
@@ -22,7 +22,7 @@ struct chipset_bus_clock_list_entry {
        u8 ultra_settings;
 };
 
-static struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
        {       XFER_UDMA_6,    0x31,   0x07    },
        {       XFER_UDMA_5,    0x31,   0x06    },
        {       XFER_UDMA_4,    0x31,   0x05    },
@@ -42,7 +42,7 @@ static struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
        {       0,              0x00,   0x00    }
 };
 
-static struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
        {       XFER_UDMA_6,    0x41,   0x06    },
        {       XFER_UDMA_5,    0x41,   0x05    },
        {       XFER_UDMA_4,    0x41,   0x04    },
@@ -254,7 +254,8 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
 
        if (dev->resource[PCI_ROM_RESOURCE].start) {
                pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
        }
 
        if (bus_speed <= 33)
@@ -425,12 +426,12 @@ static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_devi
        return d->init_setup(dev, d);
 }
 
-static struct pci_device_id aec62xx_pci_tbl[] = {
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+static const struct pci_device_id aec62xx_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
index 6e9dbf4d80775b4ab8ebfdeb018b7a0509b7865a..85007cb12c52356eaf7cab09b8d972e3441f5a8c 100644 (file)
@@ -75,6 +75,7 @@ static struct amd_ide_chip {
        { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,        0x50, AMD_UDMA_133 },
        { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE,        0x50, AMD_UDMA_133 },
        { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE,        0x50, AMD_UDMA_133 },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE,        0x50, AMD_UDMA_133 },
        { PCI_DEVICE_ID_AMD_CS5536_IDE,                 0x40, AMD_UDMA_100 },
        { 0 }
 };
@@ -490,7 +491,8 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
        /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
        /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
        /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"),
-       /* 18 */ DECLARE_AMD_DEV("AMD5536"),
+       /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"),
+       /* 19 */ DECLARE_AMD_DEV("AMD5536"),
 };
 
 static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -528,7 +530,8 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
-       { PCI_VENDOR_ID_AMD,    PCI_DEVICE_ID_AMD_CS5536_IDE,           PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
+       { PCI_VENDOR_ID_AMD,    PCI_DEVICE_ID_AMD_CS5536_IDE,           PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
index 3d9c7afc86950ad1660852bba5eb680199cde1b2..92b7b1549b1668249b6cdea1bfdac4083a418527 100644 (file)
@@ -189,14 +189,6 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
 
 #endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-/*
- * Registers and masks for easy access by drive index:
- */
-#if 0
-static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-#endif
-
 /*
  * This routine writes the prepared setup/active/recovery counts
  * for a drive into the cmd646 chipset registers to active them.
@@ -606,13 +598,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
        class_rev &= 0xff;
 
-#ifdef __i386__
-       if (dev->resource[PCI_ROM_RESOURCE].start) {
-               pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-       }
-#endif
-
        switch(dev->device) {
                case PCI_DEVICE_ID_CMD_643:
                        break;
index be334da7a7549b4fb44f82e59000450875c1abfb..7da550281cf23a112d61b6cc68d946ad0e540d19 100644 (file)
@@ -176,7 +176,7 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
                        pci_write_config_dword(dev, PCI_ROM_ADDRESS,
                                dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
                        printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
-                               dev->resource[PCI_ROM_RESOURCE].start);
+                               (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
                }
                pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
        } else {
index acd63173199bbf17acd1a306da2160cda563c511..5a8334d134fbda2d1caebb0ab0ea4e93444f80e9 100644 (file)
@@ -313,8 +313,8 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
        if (dev->resource[PCI_ROM_RESOURCE].start) {
                pci_write_config_dword(dev, PCI_ROM_ADDRESS,
                        dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
-                       name, dev->resource[PCI_ROM_RESOURCE].start);
+               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
        }
 
 #ifdef CONFIG_PPC_PMAC
@@ -338,6 +338,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
        hwif->ultra_mask = 0x7f;
        hwif->mwdma_mask = 0x07;
 
+       hwif->err_stops_fifo = 1;
+
        hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
        hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
        hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
index 22d17548ecdbd273628c19c303cc914f8c5b25d3..1e209d8f9437f4e04199bc8b4365d4c48bd0f298 100644 (file)
@@ -101,31 +101,6 @@ static const char *pdc_quirk_drives[] = {
 #define        MC1             0x02    /* DMA"C" timing */
 #define        MC0             0x01    /* DMA"C" timing */
 
-#if 0
-       unsigned long bibma  = pci_resource_start(dev, 4);
-       u8 hi = 0, lo = 0;
-
-       u8 sc1c = inb_p((u16)bibma + 0x1c); 
-       u8 sc1e = inb_p((u16)bibma + 0x1e);
-       u8 sc1f = inb_p((u16)bibma + 0x1f);
-
-       p += sprintf(p, "Host Mode                            : %s\n",
-               (sc1f & 0x08) ? "Tri-Stated" : "Normal");
-       p += sprintf(p, "Bus Clocking                         : %s\n",
-               ((sc1f & 0xC0) == 0xC0) ? "100 External" :
-               ((sc1f & 0x80) == 0x80) ? "66 External" :
-               ((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
-       p += sprintf(p, "IO pad select                        : %s mA\n",
-               ((sc1c & 0x03) == 0x03) ? "10" :
-               ((sc1c & 0x02) == 0x02) ? "8" :
-               ((sc1c & 0x01) == 0x01) ? "6" :
-               ((sc1c & 0x00) == 0x00) ? "4" : "??");
-       hi = sc1e >> 4;
-       lo = sc1e & 0xf;
-       p += sprintf(p, "Status Polling Period                : %d\n", hi);
-       p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
-#endif
-
 static u8 pdc202xx_ratemask (ide_drive_t *drive)
 {
        u8 mode;
@@ -505,73 +480,20 @@ static void pdc202xx_reset (ide_drive_t *drive)
        
        pdc202xx_reset_host(hwif);
        pdc202xx_reset_host(mate);
-#if 0
-       /*
-        * FIXME: Have to kick all the drives again :-/
-        * What a pain in the ACE!
-        */
-       if (hwif->present) {
-               u16 hunit = 0;
-               for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
-                       ide_drive_t *hdrive = &hwif->drives[hunit];
-                       if (hdrive->present) {
-                               if (hwif->ide_dma_check)
-                                       hwif->ide_dma_check(hdrive);
-                               else
-                                       hwif->tuneproc(hdrive, 5);
-                       }
-               }
-       }
-       if (mate->present) {
-               u16 munit = 0;
-               for (munit = 0; munit < MAX_DRIVES; ++munit) {
-                       ide_drive_t *mdrive = &mate->drives[munit];
-                       if (mdrive->present) {
-                               if (mate->ide_dma_check) 
-                                       mate->ide_dma_check(mdrive);
-                               else
-                                       mate->tuneproc(mdrive, 5);
-                       }
-               }
-       }
-#else
        hwif->tuneproc(drive, 5);
-#endif
 }
 
-static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
+                                                       const char *name)
 {
+       /* This doesn't appear needed */
        if (dev->resource[PCI_ROM_RESOURCE].start) {
                pci_write_config_dword(dev, PCI_ROM_ADDRESS,
                        dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
-                       name, dev->resource[PCI_ROM_RESOURCE].start);
-       }
-
-       /*
-        * software reset -  this is required because the bios
-        * will set UDMA timing on if the hdd supports it. The
-        * user may want to turn udma off. A bug in the pdc20262
-        * is that it cannot handle a downgrade in timing from
-        * UDMA to DMA. Disk accesses after issuing a set
-        * feature command will result in errors. A software
-        * reset leaves the timing registers intact,
-        * but resets the drives.
-        */
-#if 0
-       if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
-           (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
-           (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
-           (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
-               unsigned long high_16   = pci_resource_start(dev, 4);
-               byte udma_speed_flag    = inb(high_16 + 0x001f);
-               outb(udma_speed_flag | 0x10, high_16 + 0x001f);
-               mdelay(100);
-               outb(udma_speed_flag & ~0x10, high_16 + 0x001f);
-               mdelay(2000);   /* 2 seconds ?! */
+               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
        }
 
-#endif
        return dev->irq;
 }
 
@@ -599,6 +521,8 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
 
+       hwif->err_stops_fifo = 1;
+
        hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
        hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
        hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
@@ -687,19 +611,6 @@ static int __devinit init_setup_pdc202ata4(struct pci_dev *dev,
                                "mirror fixed.\n", d->name);
                }
        }
-
-#if 0
-        if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
-        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
-             (tmp & e->mask) != e->val))
-
-        if (d->enablebits[0].reg != d->enablebits[1].reg) {
-                d->enablebits[0].reg    = d->enablebits[1].reg;
-                d->enablebits[0].mask   = d->enablebits[1].mask;
-                d->enablebits[0].val    = d->enablebits[1].val;
-        }
-#endif
-
        return ide_setup_pci_device(dev, d);
 }
 
@@ -714,22 +625,6 @@ static int __devinit init_setup_pdc20265(struct pci_dev *dev,
                        "attached to I2O RAID controller.\n");
                return -ENODEV;
        }
-
-#if 0
-        {
-                u8 pri = 0, sec = 0;
-
-        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
-             (tmp & e->mask) != e->val))
-
-        if (d->enablebits[0].reg != d->enablebits[1].reg) {
-                d->enablebits[0].reg    = d->enablebits[1].reg;
-                d->enablebits[0].mask   = d->enablebits[1].mask;
-                d->enablebits[0].val    = d->enablebits[1].val;
-        }
-        }
-#endif
-
        return ide_setup_pci_device(dev, d);
 }
 
index 24e21b2838c15028bd4f72c4a2305ddf0b7b54a3..778b82ae964de770e81acef1c00eb18e20f5f8b6 100644 (file)
@@ -395,7 +395,6 @@ static int sc1200_resume (struct pci_dev *dev)
 {
        ide_hwif_t      *hwif = NULL;
 
-printk("SC1200: resume\n");
        pci_set_power_state(dev, PCI_D0);       // bring chip back from sleep state
        dev->current_state = PM_EVENT_ON;
        pci_enable_device(dev);
@@ -405,7 +404,6 @@ printk("SC1200: resume\n");
        while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
                unsigned int            basereg, r, d, format;
                sc1200_saved_state_t    *ss = (sc1200_saved_state_t *)hwif->config_data;
-printk("%s: SC1200: resume\n", hwif->name);
 
                //
                // Restore timing registers:  this may be unnecessary if BIOS also does it
@@ -493,7 +491,7 @@ static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_devic
 }
 
 static struct pci_device_id sc1200_pci_tbl[] = {
-       { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
index 0d3073f4eab4e3d8e55f6c34af0fadd9f262e659..5100b827a935213dcd737703d928b150d96f6033 100644 (file)
@@ -123,11 +123,11 @@ static u8 svwks_csb_check (struct pci_dev *dev)
 }
 static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
-       u8 udma_modes[]         = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-       u8 dma_modes[]          = { 0x77, 0x21, 0x20 };
-       u8 pio_modes[]          = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-       u8 drive_pci[]          = { 0x41, 0x40, 0x43, 0x42 };
-       u8 drive_pci2[]         = { 0x45, 0x44, 0x47, 0x46 };
+       static const u8 udma_modes[]            = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+       static const u8 dma_modes[]             = { 0x77, 0x21, 0x20 };
+       static const u8 pio_modes[]             = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+       static const u8 drive_pci[]             = { 0x41, 0x40, 0x43, 0x42 };
+       static const u8 drive_pci2[]            = { 0x45, 0x44, 0x47, 0x46 };
 
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -392,16 +392,6 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
                        }
                        outb_p(0x06, 0x0c00);
                        dev->irq = inb_p(0x0c01);
-#if 0
-                       printk("%s: device class (0x%04x)\n",
-                               name, dev->class);
-                       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
-                               dev->class &= ~0x000F0F00;
-               //              dev->class |= ~0x00000400;
-                               dev->class |= ~0x00010100;
-                               /**/
-                       }
-#endif
                } else {
                        struct pci_dev * findev = NULL;
                        u8 reg41 = 0;
@@ -452,7 +442,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
                pci_write_config_byte(dev, 0x5A, btr);
        }
 
-       return (dev->irq) ? dev->irq : 0;
+       return dev->irq;
 }
 
 static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
@@ -500,11 +490,6 @@ static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
 
-       /* Per Specified Design by OEM, and ASIC Architect */
-       if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
-           (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
-               return 1;
-
        /* Server Works */
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
                return ata66_svwks_svwks (hwif);
@@ -517,10 +502,14 @@ static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
                return ata66_svwks_cobalt (hwif);
 
+       /* Per Specified Design by OEM, and ASIC Architect */
+       if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+           (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+               return 1;
+
        return 0;
 }
 
-#undef CAN_SW_DMA
 static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 {
        u8 dma_stat = 0;
@@ -537,9 +526,6 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
                hwif->ultra_mask = 0x3f;
 
        hwif->mwdma_mask = 0x07;
-#ifdef CAN_SW_DMA
-       hwif->swdma_mask = 0x07;
-#endif /* CAN_SW_DMA */
 
        hwif->autodma = 0;
 
@@ -562,8 +548,6 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
        hwif->drives[1].autodma = (dma_stat & 0x40);
        hwif->drives[0].autotune = (!(dma_stat & 0x20));
        hwif->drives[1].autotune = (!(dma_stat & 0x40));
-//     hwif->drives[0].autodma = hwif->autodma;
-//     hwif->drives[1].autodma = hwif->autodma;
 }
 
 /*
@@ -593,11 +577,6 @@ static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
                if (dev->resource[0].start == 0x01f1)
                        d->bootable = ON_BOARD;
        }
-#if 0
-       if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
-             (!(PCI_FUNC(dev->devfn) & 1)))
-               d->autodma = AUTODMA;
-#endif
 
        d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
                        dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
@@ -671,11 +650,11 @@ static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device
 }
 
 static struct pci_device_id svwks_pci_tbl[] = {
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 1},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 3},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
index f1ca154dd52ca088f25ec0c0ac28845a47a59e18..72dade14c725996acc24af25143df12eb7449c63 100644 (file)
@@ -38,9 +38,6 @@
 
 #include <asm/io.h>
 
-#undef SIIMAGE_VIRTUAL_DMAPIO
-#undef SIIMAGE_LARGE_DMA
-
 /**
  *     pdev_is_sata            -       check if device is SATA
  *     @pdev:  PCI device to check
@@ -461,36 +458,6 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
        return 0;
 }
 
-#if 0
-/**
- *     siimage_mmio_ide_dma_count      -       DMA bytes done
- *     @drive
- *
- *     If we are doing VDMA the CMD680 requires a little bit
- *     of more careful handling and we have to read the counts
- *     off ourselves. For non VDMA life is normal.
- */
-static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
-{
-#ifdef SIIMAGE_VIRTUAL_DMAPIO
-       struct request *rq      = HWGROUP(drive)->rq;
-       ide_hwif_t *hwif        = HWIF(drive);
-       u32 count               = (rq->nr_sectors * SECTOR_SIZE);
-       u32 rcount              = 0;
-       unsigned long addr      = siimage_selreg(hwif, 0x1C);
-
-       hwif->OUTL(count, addr);
-       rcount = hwif->INL(addr);
-
-       printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
-               drive->name, count, rcount, rq->nr_sectors);
-
-#endif /* SIIMAGE_VIRTUAL_DMAPIO */
-       return __ide_dma_count(drive);
-}
-#endif
-
 /**
  *     siimage_mmio_ide_dma_test_irq   -       check we caused an IRQ
  *     @drive: drive we are testing
@@ -512,12 +479,10 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
                        u32 sata_error = hwif->INL(SATA_ERROR_REG);
                        hwif->OUTL(sata_error, SATA_ERROR_REG);
                        watchdog = (sata_error & 0x00680000) ? 1 : 0;
-#if 1
                        printk(KERN_WARNING "%s: sata_error = 0x%08x, "
                                "watchdog = %d, %s\n",
                                drive->name, sata_error, watchdog,
                                __FUNCTION__);
-#endif
 
                } else {
                        watchdog = (ext_stat & 0x8000) ? 1 : 0;
@@ -863,7 +828,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch
  *     time.
  *
  *     The hardware supports buffered taskfiles and also some rather nice
- *     extended PRD tables. Unfortunately right now we don't.
+ *     extended PRD tables. For better SI3112 support use the libata driver
  */
 
 static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
@@ -900,9 +865,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
         *      so we can't currently use it sanely since we want to
         *      use LBA48 mode.
         */     
-//     base += 0x10;
-//     hwif->no_lba48 = 1;
-
        hw.io_ports[IDE_DATA_OFFSET]    = base;
        hw.io_ports[IDE_ERROR_OFFSET]   = base + 1;
        hw.io_ports[IDE_NSECTOR_OFFSET] = base + 2;
@@ -936,15 +898,8 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
 
                base = (unsigned long) addr;
 
-#ifdef SIIMAGE_LARGE_DMA
-/* Watch the brackets - even Ken and Dennis get some language design wrong */
-       hwif->dma_base                  = base + (ch ? 0x18 : 0x10);
-       hwif->dma_base2                 = base + (ch ? 0x08 : 0x00);
-       hwif->dma_prdtable              = hwif->dma_base2 + 4;
-#else /* ! SIIMAGE_LARGE_DMA */
        hwif->dma_base                  = base + (ch ? 0x08 : 0x00);
        hwif->dma_base2                 = base + (ch ? 0x18 : 0x10);
-#endif /* SIIMAGE_LARGE_DMA */
        hwif->mmio                      = 2;
 }
 
@@ -1052,9 +1007,16 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
        hwif->reset_poll = &siimage_reset_poll;
        hwif->pre_reset = &siimage_pre_reset;
 
-       if(is_sata(hwif))
+       if(is_sata(hwif)) {
+               static int first = 1;
+
                hwif->busproc   = &siimage_busproc;
 
+               if (first) {
+                       printk(KERN_INFO "siimage: For full SATA support you should use the libata sata_sil module.\n");
+                       first = 0;
+               }
+       }
        if (!hwif->dma_base) {
                hwif->drives[0].autotune = 1;
                hwif->drives[1].autotune = 1;
@@ -1121,10 +1083,10 @@ static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_devi
 }
 
 static struct pci_device_id siimage_pci_tbl[] = {
-       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), 0},
 #ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112), 1},
+       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA), 2},
 #endif
        { 0, },
 };
index 8a5c7b286b2b86dbf5d0e9c9c00ed8ef134541d4..900301e43818bee500a9884870be937a6e9d1f16 100644 (file)
@@ -447,7 +447,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
                printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
                       hwif->name, rev);
        } else {
-#ifdef CONFIG_BLK_DEV_IDEDMA
                dma_state |= 0x60;
 
                hwif->atapi_dma = 1;
@@ -468,7 +467,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 
                if (hwif->mate)
                        hwif->serialized = hwif->mate->serialized = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
        }
        hwif->OUTB(dma_state, hwif->dma_base + 2);
 }
@@ -489,7 +487,7 @@ static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_dev
 }
 
 static struct pci_device_id sl82c105_pci_tbl[] = {
-       { PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
index 5112c726633bafde6685d326b29a0f38c870b97b..0968f6bc669a5684b7ba3f3e0205a2e03e250400 100644 (file)
@@ -72,7 +72,8 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
        u16 master_data;
        u8 slave_data;
                                 /* ISP  RTC */
-       u8 timings[][2] = { { 0, 0 },
+       static const u8 timings[][2]= {
+                                   { 0, 0 },
                                    { 0, 0 },
                                    { 1, 0 },
                                    { 2, 1 },
@@ -119,7 +120,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        pci_read_config_word(dev, 0x4a, &reg4a);
 
        switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
                case XFER_UDMA_4:       u_speed = 4 << (drive->dn * 4); break;
                case XFER_UDMA_3:       u_speed = 3 << (drive->dn * 4); break;
                case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
@@ -128,7 +128,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
                case XFER_MW_DMA_2:
                case XFER_MW_DMA_1:
                case XFER_SW_DMA_2:     break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
                case XFER_PIO_4:
                case XFER_PIO_3:
                case XFER_PIO_2:
@@ -156,7 +155,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        return (ide_config_drive_speed(drive, speed));
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
 static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
 {
        u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
@@ -194,7 +192,6 @@ fast_ata_pio:
        /* IORDY not supported */
        return 0;
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
 {
@@ -222,7 +219,6 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA 
        if (!(hwif->udma_four))
                /* bit[0(1)]: 0:80, 1:40 */
                hwif->udma_four = (reg47 & mask) ? 0 : 1;
@@ -232,7 +228,6 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
                hwif->autodma = 1;
        hwif->drives[0].autodma = hwif->autodma;
        hwif->drives[1].autodma = hwif->autodma;
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
 }
 
 static ide_pci_device_t slc90e66_chipset __devinitdata = {
@@ -250,7 +245,7 @@ static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_dev
 }
 
 static struct pci_device_id slc90e66_pci_tbl[] = {
-       { PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
index 3d278412e1ca07f46b9e69887864d1d076c91a26..800c8d5184302b0195f5ab1f34783d718523e192 100644 (file)
@@ -590,11 +590,11 @@ static void ohci_initialize(struct ti_ohci *ohci)
        buf = reg_read(ohci, OHCI1394_Version);
        sprintf (irq_buf, "%d", ohci->dev->irq);
        PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%s]  "
-             "MMIO=[%lx-%lx]  Max Packet=[%d]  IR/IT contexts=[%d/%d]",
+             "MMIO=[%llx-%llx]  Max Packet=[%d]  IR/IT contexts=[%d/%d]",
              ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
              ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), irq_buf,
-             pci_resource_start(ohci->dev, 0),
-             pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
+             (unsigned long long)pci_resource_start(ohci->dev, 0),
+             (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
              ohci->max_packet_size,
              ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx);
 
@@ -3217,7 +3217,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
 {
        struct hpsb_host *host;
        struct ti_ohci *ohci;   /* shortcut to currently handled device */
-       unsigned long ohci_base;
+       resource_size_t ohci_base;
 
         if (pci_enable_device(dev))
                FAIL(-ENXIO, "Failed to enable OHCI hardware");
@@ -3270,15 +3270,16 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
         * clearly says it's 2kb, so this shouldn't be a problem. */
        ohci_base = pci_resource_start(dev, 0);
        if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE)
-               PRINT(KERN_WARNING, "PCI resource length of %lx too small!",
-                     pci_resource_len(dev, 0));
+               PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
+                     (unsigned long long)pci_resource_len(dev, 0));
 
        /* Seems PCMCIA handles this internally. Not sure why. Seems
         * pretty bogus to force a driver to special case this.  */
 #ifndef PCMCIA
        if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
-               FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable",
-                    ohci_base, ohci_base + OHCI1394_REGISTER_SIZE);
+               FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable",
+                       (unsigned long long)ohci_base,
+                       (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
 #endif
        ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
 
index dddcdae736ac89151d659a65e8521e98523890fb..e4b897fa569a5e945841fee575e1db1706f4ecd4 100644 (file)
@@ -460,10 +460,10 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
        for (j = 0; j < 6; j++) {
                if (!pdev->resource[j].start)
                        continue;
-               ipath_cdbg(VERBOSE, "BAR %d start %lx, end %lx, len %lx\n",
-                          j, pdev->resource[j].start,
-                          pdev->resource[j].end,
-                          pci_resource_len(pdev, j));
+               ipath_cdbg(VERBOSE, "BAR %d start %llx, end %llx, len %llx\n",
+                          j, (unsigned long long)pdev->resource[j].start,
+                          (unsigned long long)pdev->resource[j].end,
+                          (unsigned long long)pci_resource_len(pdev, j));
        }
 
        if (!addr) {
index 9b9ff7bff357a2ea8a4d9ab8d6747eea373ade95..465fd220569c651a1cb7499daa1f970b5241811a 100644 (file)
@@ -172,8 +172,9 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim
 
        if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) {
                mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than "
-                         "PCI resource 2 size of 0x%lx, aborting.\n",
-                         dev_lim->uar_size, pci_resource_len(mdev->pdev, 2));
+                         "PCI resource 2 size of 0x%llx, aborting.\n",
+                         dev_lim->uar_size,
+                         (unsigned long long)pci_resource_len(mdev->pdev, 2));
                return -ENODEV;
        }
 
index 6f31f054d1bb9b144f5edd05c925dbac236795b9..5080e15c6d30c6dca5a1f40fc28c419843cbdf3b 100644 (file)
@@ -584,7 +584,7 @@ static struct db9 __init *db9_probe(int parport, int mode)
                goto err_out;
        }
 
-       if (db9_mode[mode].bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
+       if (db9_mode->bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
                printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
                err = -EINVAL;
                goto err_put_pp;
index ffde8f86e0fb0277435b2b81355b6a3e92e8ca1d..ce1f10e8984b064beede5a3ea934ecd4894e6ab2 100644 (file)
@@ -459,7 +459,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
                        }
 
                        input_regs(dev, regs);
-                       input_report_key(dev, keycode, value);
+                       input_event(dev, EV_KEY, keycode, value);
                        input_sync(dev);
 
                        if (value && add_release_event) {
index e4e5be111c960b67834e2742a9475bbd73b2d42f..ccf0faeee5c18390ea7ee3f84eb4c1617b00db62 100644 (file)
@@ -285,6 +285,15 @@ static struct key_entry keymap_fujitsu_n3510[] = {
        { KE_END, 0 }
 };
 
+static struct key_entry keymap_wistron_ms2111[] = {
+       { KE_KEY,  0x11, KEY_PROG1 },
+       { KE_KEY,  0x12, KEY_PROG2 },
+       { KE_KEY,  0x13, KEY_PROG3 },
+       { KE_KEY,  0x31, KEY_MAIL },
+       { KE_KEY,  0x36, KEY_WWW },
+       { KE_END,  0 }
+};
+
 static struct key_entry keymap_wistron_ms2141[] = {
        { KE_KEY,  0x11, KEY_PROG1 },
        { KE_KEY,  0x12, KEY_PROG2 },
@@ -326,6 +335,7 @@ static struct key_entry keymap_aopen_1559as[] = {
        { KE_WIFI, 0x30, 0 },
        { KE_KEY,  0x31, KEY_MAIL },
        { KE_KEY,  0x36, KEY_WWW },
+       { KE_END,  0 },
 };
 
 /*
@@ -388,6 +398,15 @@ static struct dmi_system_id dmi_ids[] = {
                },
                .driver_data = keymap_aopen_1559as
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Medion MD 9783",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
+               },
+               .driver_data = keymap_wistron_ms2111
+       },
        { NULL, }
 };
 
index 096b6a0b5ccad6598702233350322d71f28860a6..1ac739ef2ffa53a41053b5bd02218f9073c33281 100644 (file)
@@ -189,7 +189,7 @@ static int __devinit ct82c710_probe(struct platform_device *dev)
        strlcpy(ct82c710_port->name, "C&T 82c710 mouse port",
                sizeof(ct82c710_port->name));
        snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys),
-                "isa%04lx/serio0", CT82C710_DATA);
+                "isa%16llx/serio0", (unsigned long long)CT82C710_DATA);
 
        serio_register_port(ct82c710_port);
 
@@ -241,8 +241,8 @@ static int __init ct82c710_init(void)
 
        serio_register_port(ct82c710_port);
 
-       printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n",
-               CT82C710_DATA, CT82C710_IRQ);
+       printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
+               (unsigned long long)CT82C710_DATA, CT82C710_IRQ);
 
        return 0;
 
index acb7e2656780274cd32fc8f4e170f234c3357bc4..2a56bf33a6738ac47a31ecad684f2b9945aa06d7 100644 (file)
@@ -981,7 +981,7 @@ exit:
 EXPORT_SYMBOL_GPL(gigaset_stop);
 
 static LIST_HEAD(drivers);
-static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(driver_lock);
 
 struct cardstate *gigaset_get_cs_by_id(int id)
 {
index 91d25acb5ede07f39d8859204e5b6daa9f150315..3622720f05053a01cb37161ab27b2ce9a2fb6f0c 100644 (file)
@@ -1688,7 +1688,7 @@ setup_hfcpci(struct IsdnCard *card)
                                printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
                                return (0);
                        }
-                       cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->resource[ 1].start;
+                       cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
                        printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
                } else {
                        printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
index e2bb4fd8e25e7602e9c69fd0151edb739a119daa..e82ab2251b825089b9f0a28ad68b007c6dbfd0f9 100644 (file)
@@ -311,8 +311,9 @@ setup_telespci(struct IsdnCard *card)
                }
                cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0),
                        PAGE_SIZE);
-               printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
-                       pci_resource_start(dev_tel, 0), dev_tel->irq);
+               printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n",
+                       (unsigned long long)pci_resource_start(dev_tel, 0),
+                       dev_tel->irq);
        } else {
                printk(KERN_WARNING "TelesPCI: No PCI card found\n");
                return(0);
index 2ac90242d263714b7d6108a9005982ef660c02d7..433389daedb2ab9208b2f45b2bd3320ff18cf5ff 100644 (file)
@@ -82,7 +82,7 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
                                                int l = skb->len;
                                                unsigned char *dp = skb->data;
                                                while (--l) {
-                                                       if (*skb->data == DLE)
+                                                       if (*dp == DLE)
                                                                tty_insert_flip_char(tty, DLE, 0);
                                                        tty_insert_flip_char(tty, *dp++, 0);
                                                }
index 743ac4077f35b24b17af0b08fc5a23dce9b0733f..8b3efc243161a201fd8029d5d43900371c48b2b5 100644 (file)
@@ -208,7 +208,7 @@ static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb
  */
 static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
 {
-       struct sk_buff * skb = dev_alloc_skb(1);
+       struct sk_buff * skb;
        enum wan_states *state_p 
          = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
        IX25DEBUG( "isdn_x25iface_connect_ind %s \n"
@@ -220,6 +220,8 @@ static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
                return -1;
        }
        *state_p = WAN_CONNECTED;
+
+       skb = dev_alloc_skb(1);
        if( skb ){
                *( skb_put(skb, 1) ) = 0x01;
                skb->protocol = x25_type_trans(skb, cprot->net_dev);
index fe6541326c717fb996cb591aebb5a1bbc2107569..9b015f9af351e49526eb52ec0f0c09b4acb21e56 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/leds.h>
 #include "leds.h"
 
-rwlock_t leds_list_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(leds_list_lock);
 LIST_HEAD(leds_list);
 
 EXPORT_SYMBOL_GPL(leds_list);
index 5e2cd8be1191b99c44f3cb573d6bce3487b0155c..1b1ce6523960cb1676f342a718adf2e0962c42a6 100644 (file)
@@ -26,7 +26,7 @@
 /*
  * Nests outside led_cdev->trigger_lock
  */
-static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(triggers_list_lock);
 static LIST_HEAD(trigger_list);
 
 ssize_t led_trigger_store(struct class_device *dev, const char *buf,
index 431bd37225a13a05be8891b44de545e88b5802c1..c687ac703941f514af7c352ab456e72be2fc18e2 100644 (file)
@@ -428,10 +428,10 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
 
        /* 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",
+               sprintf(dev->ofdev.dev.bus_id, "%1d.%016llx:%.*s",
                        chip->lbus.index,
 #ifdef CONFIG_PCI
-                       pci_resource_start(chip->lbus.pdev, 0),
+                       (unsigned long long)pci_resource_start(chip->lbus.pdev, 0),
 #else
                        0, /* NuBus may want to do something better here */
 #endif
index f920e50ea124dfe9052288f8f526cb314b230249..837ec4eb3d604ce4e01023ccf87d0804ceef7f88 100644 (file)
@@ -2827,7 +2827,6 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
        struct stripe_head *sh;
        int pd_idx;
        int raid_disks = conf->raid_disks;
-       int data_disks = raid_disks - conf->max_degraded;
        sector_t max_sector = mddev->size << 1;
        int sync_blocks;
        int still_degraded = 0;
index e4290491fa9e15f4920317c65536f100f180164c..6d532f170ce5c8302b82975c4bb53c8a2dbeef1d 100644 (file)
@@ -445,6 +445,8 @@ endmenu # encoder / decoder chips
 menu "V4L USB devices"
        depends on USB && VIDEO_DEV
 
+source "drivers/media/video/pvrusb2/Kconfig"
+
 source "drivers/media/video/em28xx/Kconfig"
 
 config USB_DSBR
index 6c401b46398a11d8615fadd5641c88d0d6b76fbb..353d61cfac1b2150021762ed5529ae3ad81b089f 100644 (file)
@@ -47,6 +47,7 @@ obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
 obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
index 423e954948beb01153b17aafadaf694100996749..aa3203ae670c94a7333fd6c2ea4561179ab6c676 100644 (file)
@@ -4019,8 +4019,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        if (!request_mem_region(pci_resource_start(dev,0),
                                pci_resource_len(dev,0),
                                btv->c.name)) {
-               printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
-                      btv->c.nr, pci_resource_start(dev,0));
+               printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
+                      btv->c.nr,
+                      (unsigned long long)pci_resource_start(dev,0));
                return -EBUSY;
        }
        pci_set_master(dev);
@@ -4031,8 +4032,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
        printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
               bttv_num,btv->id, btv->revision, pci_name(dev));
-       printk("irq: %d, latency: %d, mmio: 0x%lx\n",
-              btv->c.pci->irq, lat, pci_resource_start(dev,0));
+       printk("irq: %d, latency: %d, mmio: 0x%llx\n",
+              btv->c.pci->irq, lat,
+              (unsigned long long)pci_resource_start(dev,0));
        schedule();
 
        btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
index 01b22eab572574827fc0de12c6e580f8a0c84061..65f00fc08fa961d5671ccfe5a3cf92aa38efb4ab 100644 (file)
@@ -601,7 +601,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
 }
 
 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
-                 struct v4l2_ext_controls *ctrls, int cmd)
+                 struct v4l2_ext_controls *ctrls, unsigned int cmd)
 {
        int err = 0;
        int i;
@@ -847,22 +847,22 @@ invalid:
        return "<invalid>";
 }
 
-void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
 {
        int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
 
        /* Stream */
-       printk(KERN_INFO "cx2341x-%d: Stream: %s\n",
-               card_id,
+       printk(KERN_INFO "%s: Stream: %s\n",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
 
        /* Video */
-       printk(KERN_INFO "cx2341x-%d: Video:  %dx%d, %d fps\n",
-               card_id,
+       printk(KERN_INFO "%s: Video:  %dx%d, %d fps\n",
+               prefix,
                p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
                p->is_50hz ? 25 : 30);
-       printk(KERN_INFO "cx2341x-%d: Video:  %s, %s, %s, %d",
-               card_id,
+       printk(KERN_INFO "%s: Video:  %s, %s, %s, %d",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
                cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
                cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
@@ -871,19 +871,19 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
                printk(", Peak %d", p->video_bitrate_peak);
        }
        printk("\n");
-       printk(KERN_INFO "cx2341x-%d: Video:  GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
-               card_id,
+       printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+               prefix,
                p->video_gop_size, p->video_b_frames,
                p->video_gop_closure ? "" : "No ",
                p->video_pulldown ? "" : "No ");
        if (p->video_temporal_decimation) {
-               printk(KERN_INFO "cx2341x-%d: Video: Temporal Decimation %d\n",
-                       card_id, p->video_temporal_decimation);
+               printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
+                       prefix, p->video_temporal_decimation);
        }
 
        /* Audio */
-       printk(KERN_INFO "cx2341x-%d: Audio:  %s, %s, %s, %s",
-               card_id,
+       printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
@@ -897,18 +897,18 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
 
        /* Encoding filters */
-       printk(KERN_INFO "cx2341x-%d: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
-               card_id,
+       printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
                p->video_spatial_filter);
-       printk(KERN_INFO "cx2341x-%d: Temporal Filter: %s, %d\n",
-               card_id,
+       printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
                p->video_temporal_filter);
-       printk(KERN_INFO "cx2341x-%d: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
-               card_id,
+       printk(KERN_INFO "%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
                p->video_luma_median_filter_bottom,
                p->video_luma_median_filter_top,
index 2194cbeca33b61b3c1eccf4864cbccbec44e4566..292a5e81eb75fab5ad9a855f3623dae38b80067b 100644 (file)
@@ -712,9 +712,9 @@ static int __devinit snd_cx88_create(struct snd_card *card,
        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,
+              "latency: %d, mmio: 0x%llx\n", core->name, devno,
               pci_name(pci), chip->pci_rev, pci->irq,
-              chip->pci_lat,pci_resource_start(pci,0));
+              chip->pci_lat,(unsigned long long)pci_resource_start(pci,0));
 
        chip->irq = pci->irq;
        synchronize_irq(chip->irq);
@@ -766,8 +766,8 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
 
        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));
+       sprintf(card->longname, "%s at %#llx",
+               card->shortname,(unsigned long long)pci_resource_start(pci, 0));
        strcpy (card->mixername, "CX88");
 
        dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
index 78df66671ea2f300ba78a07a65e443d7b84690a3..4ff81582ec56ee5f71b17ec2e402c51730ce4698 100644 (file)
@@ -853,6 +853,19 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
                               fh->mpegq.field);
                return 0;
        }
+       case VIDIOC_LOG_STATUS:
+       {
+               char name[32 + 2];
+
+               snprintf(name, sizeof(name), "%s/2", core->name);
+               printk("%s/2: ============  START LOG STATUS  ============\n",
+                      core->name);
+               cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, 0);
+               cx2341x_log_status(&dev->params, name);
+               printk("%s/2: =============  END LOG STATUS  =============\n",
+                      core->name);
+               return 0;
+       }
 
        default:
                return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
index 26f4c0fb8c36cab989a9f2ab7a8269f9e6f6f11c..973d3f39b2d540133c5398abd4e028956dee212b 100644 (file)
@@ -1031,8 +1031,8 @@ static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
                               pci_resource_len(pci,0),
                               core->name))
                return 0;
-       printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
-              core->name,pci_resource_start(pci,0));
+       printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+              core->name,(unsigned long long)pci_resource_start(pci,0));
        return -EBUSY;
 }
 
index a9d7795a8e143563ed155c109d474d725671012e..2c12aca1b6a3d69fdf8a2b1f5e91e7cac7856093 100644 (file)
@@ -420,9 +420,9 @@ int cx8802_init_common(struct cx8802_dev *dev)
        pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
        pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
-              "latency: %d, mmio: 0x%lx\n", dev->core->name,
+              "latency: %d, mmio: 0x%llx\n", dev->core->name,
               pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
-              dev->pci_lat,pci_resource_start(dev->pci,0));
+              dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0));
 
        /* initialize driver struct */
        spin_lock_init(&dev->slock);
index dcda5291b990e979c8490001ea18d7fedc053d6e..8d5cf474b68e817c9729d40ad3f5745092290d9c 100644 (file)
@@ -1847,9 +1847,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
-              "latency: %d, mmio: 0x%lx\n", core->name,
+              "latency: %d, mmio: 0x%llx\n", core->name,
               pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
-              dev->pci_lat,pci_resource_start(pci_dev,0));
+              dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
 
        pci_set_master(pci_dev);
        if (!pci_dma_supported(pci_dev,0xffffffff)) {
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
new file mode 100644 (file)
index 0000000..7e727fe
--- /dev/null
@@ -0,0 +1,62 @@
+config VIDEO_PVRUSB2
+       tristate "Hauppauge WinTV-PVR USB2 support"
+       depends on VIDEO_V4L2 && USB && I2C && EXPERIMENTAL
+       select FW_LOADER
+       select VIDEO_TUNER
+       select VIDEO_TVEEPROM
+       select VIDEO_CX2341X
+       select VIDEO_SAA711X
+       select VIDEO_MSP3400
+       ---help---
+         This is a video4linux driver for Conexant 23416 based
+         usb2 personal video recorder devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called pvrusb2
+
+config VIDEO_PVRUSB2_24XXX
+       bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
+       depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+       select VIDEO_CX25840
+       select VIDEO_WM8775
+       ---help---
+         This option enables inclusion of additional logic to operate
+         newer WinTV-PVR USB2 devices whose model number is of the
+         form "24xxx" (leading prefix of "24" followed by 3 digits).
+         To see if you may need this option, examine the white
+         sticker on the underside of your device.  Enabling this
+         option will not harm support for older devices, however it
+         is a separate option because of the experimental nature of
+         this new feature.
+
+         If you are in doubt, say N.
+
+         Note: This feature is _very_ experimental.  You have been
+         warned.
+
+config VIDEO_PVRUSB2_SYSFS
+       bool "pvrusb2 sysfs support (EXPERIMENTAL)"
+       default y
+       depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL
+       ---help---
+         This option enables the operation of a sysfs based
+         interface for query and control of the pvrusb2 driver.
+
+         This is not generally needed for v4l applications,
+         although certain applications are optimized to take
+         advantage of this feature.
+
+         If you are in doubt, say Y.
+
+         Note: This feature is experimental and subject to change.
+
+config VIDEO_PVRUSB2_DEBUGIFC
+       bool "pvrusb2 debug interface"
+       depends on VIDEO_PVRUSB2_SYSFS
+       ---help---
+         This option enables the inclusion of a debug interface
+         in the pvrusb2 driver, hosted through sysfs.
+
+         You do not need to select this option unless you plan
+         on debugging the driver or performing a manual firmware
+         extraction.
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
new file mode 100644 (file)
index 0000000..fed603a
--- /dev/null
@@ -0,0 +1,18 @@
+obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
+obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+
+obj-pvrusb2-24xxx-$(CONFIG_VIDEO_PVRUSB2_24XXX) := \
+                  pvrusb2-cx2584x-v4l.o \
+                  pvrusb2-wm8775.o
+
+pvrusb2-objs   := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
+                  pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
+                  pvrusb2-encoder.o pvrusb2-video-v4l.o \
+                  pvrusb2-eeprom.o pvrusb2-tuner.o pvrusb2-demod.o \
+                  pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
+                  pvrusb2-ctrl.o pvrusb2-std.o \
+                  pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
+                  $(obj-pvrusb2-24xxx-y) \
+                  $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
+
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
new file mode 100644 (file)
index 0000000..313d2dc
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-audio.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/msp3400.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_msp3400_handler {
+       struct pvr2_hdw *hdw;
+       struct pvr2_i2c_client *client;
+       struct pvr2_i2c_handler i2c_handler;
+       struct pvr2_audio_stat astat;
+       unsigned long stale_mask;
+};
+
+
+/* This function selects the correct audio input source */
+static void set_stereo(struct pvr2_msp3400_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       struct v4l2_routing route;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
+
+       if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
+               struct v4l2_tuner vt;
+               memset(&vt,0,sizeof(vt));
+               vt.audmode = hdw->audiomode_val;
+               pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
+       }
+
+       route.input = MSP_INPUT_DEFAULT;
+       route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+       switch (hdw->input_val) {
+       case PVR2_CVAL_INPUT_TV:
+               break;
+       case PVR2_CVAL_INPUT_RADIO:
+               /* Assume that msp34xx also handle FM decoding, in which case
+                  we're still using the tuner. */
+               /* HV: actually it is more likely to be the SCART2 input if
+                  the ivtv experience is any indication. */
+               route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+               break;
+       case PVR2_CVAL_INPUT_SVIDEO:
+       case PVR2_CVAL_INPUT_COMPOSITE:
+               /* SCART 1 input */
+               route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+               break;
+       }
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+
+static int check_stereo(struct pvr2_msp3400_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return (hdw->input_dirty ||
+               hdw->audiomode_dirty);
+}
+
+
+struct pvr2_msp3400_ops {
+       void (*update)(struct pvr2_msp3400_handler *);
+       int (*check)(struct pvr2_msp3400_handler *);
+};
+
+
+static const struct pvr2_msp3400_ops msp3400_ops[] = {
+       { .update = set_stereo, .check = check_stereo},
+};
+
+
+static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (ctxt->stale_mask & msk) continue;
+               if (msp3400_ops[idx].check(ctxt)) {
+                       ctxt->stale_mask |= msk;
+               }
+       }
+       return ctxt->stale_mask != 0;
+}
+
+
+static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (!(ctxt->stale_mask & msk)) continue;
+               ctxt->stale_mask &= ~msk;
+               msp3400_ops[idx].update(ctxt);
+       }
+}
+
+
+/* This reads back the current signal type */
+static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
+{
+       struct v4l2_tuner vt;
+       int stat;
+
+       memset(&vt,0,sizeof(vt));
+       stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+       if (stat < 0) return stat;
+
+       ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
+       ctxt->hdw->flag_bilingual =
+               (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
+       return 0;
+}
+
+
+static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
+{
+       ctxt->client->handler = 0;
+       ctxt->hdw->audio_stat = 0;
+       kfree(ctxt);
+}
+
+
+static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt,
+                                         char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-audio v4l2");
+}
+
+
+const static struct pvr2_i2c_handler_functions msp3400_funcs = {
+       .detach = (void (*)(void *))pvr2_msp3400_detach,
+       .check = (int (*)(void *))msp3400_check,
+       .update = (void (*)(void *))msp3400_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_msp3400_describe,
+};
+
+
+int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       struct pvr2_msp3400_handler *ctxt;
+       if (hdw->audio_stat) return 0;
+       if (cp->handler) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->i2c_handler.func_data = ctxt;
+       ctxt->i2c_handler.func_table = &msp3400_funcs;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       ctxt->astat.ctxt = ctxt;
+       ctxt->astat.status = (int (*)(void *))get_audio_status;
+       ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
+       ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
+                                 sizeof(msp3400_ops[0]))) - 1;
+       cp->handler = &ctxt->i2c_handler;
+       hdw->audio_stat = &ctxt->astat;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/video/pvrusb2/pvrusb2-audio.h
new file mode 100644 (file)
index 0000000..536339b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_AUDIO_H
+#define __PVRUSB2_AUDIO_H
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+#endif /* __PVRUSB2_AUDIO_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
new file mode 100644 (file)
index 0000000..40dc598
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-context.h"
+#include "pvrusb2-io.h"
+#include "pvrusb2-ioread.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+
+
+static void pvr2_context_destroy(struct pvr2_context *mp)
+{
+       if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
+       pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
+       flush_workqueue(mp->workqueue);
+       destroy_workqueue(mp->workqueue);
+       kfree(mp);
+}
+
+
+static void pvr2_context_trigger_poll(struct pvr2_context *mp)
+{
+       queue_work(mp->workqueue,&mp->workpoll);
+}
+
+
+static void pvr2_context_poll(struct pvr2_context *mp)
+{
+       pvr2_context_enter(mp); do {
+               pvr2_hdw_poll(mp->hdw);
+       } while (0); pvr2_context_exit(mp);
+}
+
+
+static void pvr2_context_setup(struct pvr2_context *mp)
+{
+       pvr2_context_enter(mp); do {
+               if (!pvr2_hdw_dev_ok(mp->hdw)) break;
+               pvr2_hdw_setup(mp->hdw);
+               pvr2_hdw_setup_poll_trigger(
+                       mp->hdw,
+                       (void (*)(void *))pvr2_context_trigger_poll,
+                       mp);
+               if (!pvr2_hdw_dev_ok(mp->hdw)) break;
+               if (!pvr2_hdw_init_ok(mp->hdw)) break;
+               mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
+               if (mp->setup_func) {
+                       mp->setup_func(mp);
+               }
+       } while (0); pvr2_context_exit(mp);
+}
+
+
+struct pvr2_context *pvr2_context_create(
+       struct usb_interface *intf,
+       const struct usb_device_id *devid,
+       void (*setup_func)(struct pvr2_context *))
+{
+       struct pvr2_context *mp = 0;
+       mp = kmalloc(sizeof(*mp),GFP_KERNEL);
+       if (!mp) goto done;
+       memset(mp,0,sizeof(*mp));
+       pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
+       mp->setup_func = setup_func;
+       mutex_init(&mp->mutex);
+       mp->hdw = pvr2_hdw_create(intf,devid);
+       if (!mp->hdw) {
+               pvr2_context_destroy(mp);
+               mp = 0;
+               goto done;
+       }
+
+       mp->workqueue = create_singlethread_workqueue("pvrusb2");
+       INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp);
+       INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp);
+       queue_work(mp->workqueue,&mp->workinit);
+ done:
+       return mp;
+}
+
+
+void pvr2_context_enter(struct pvr2_context *mp)
+{
+       mutex_lock(&mp->mutex);
+       pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp);
+}
+
+
+void pvr2_context_exit(struct pvr2_context *mp)
+{
+       int destroy_flag = 0;
+       if (!(mp->mc_first || !mp->disconnect_flag)) {
+               destroy_flag = !0;
+       }
+       pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp);
+       mutex_unlock(&mp->mutex);
+       if (destroy_flag) pvr2_context_destroy(mp);
+}
+
+
+static void pvr2_context_run_checks(struct pvr2_context *mp)
+{
+       struct pvr2_channel *ch1,*ch2;
+       for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
+               ch2 = ch1->mc_next;
+               if (ch1->check_func) {
+                       ch1->check_func(ch1);
+               }
+       }
+}
+
+
+void pvr2_context_disconnect(struct pvr2_context *mp)
+{
+       pvr2_context_enter(mp); do {
+               pvr2_hdw_disconnect(mp->hdw);
+               mp->disconnect_flag = !0;
+               pvr2_context_run_checks(mp);
+       } while (0); pvr2_context_exit(mp);
+}
+
+
+void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
+{
+       cp->hdw = mp->hdw;
+       cp->mc_head = mp;
+       cp->mc_next = 0;
+       cp->mc_prev = mp->mc_last;
+       if (mp->mc_last) {
+               mp->mc_last->mc_next = cp;
+       } else {
+               mp->mc_first = cp;
+       }
+       mp->mc_last = cp;
+}
+
+
+static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
+{
+       if (!cp->stream) return;
+       pvr2_stream_kill(cp->stream->stream);
+       cp->stream->user = 0;
+       cp->stream = 0;
+}
+
+
+void pvr2_channel_done(struct pvr2_channel *cp)
+{
+       struct pvr2_context *mp = cp->mc_head;
+       pvr2_channel_disclaim_stream(cp);
+       if (cp->mc_next) {
+               cp->mc_next->mc_prev = cp->mc_prev;
+       } else {
+               mp->mc_last = cp->mc_prev;
+       }
+       if (cp->mc_prev) {
+               cp->mc_prev->mc_next = cp->mc_next;
+       } else {
+               mp->mc_first = cp->mc_next;
+       }
+       cp->hdw = 0;
+}
+
+
+int pvr2_channel_claim_stream(struct pvr2_channel *cp,
+                             struct pvr2_context_stream *sp)
+{
+       int code = 0;
+       pvr2_context_enter(cp->mc_head); do {
+               if (sp == cp->stream) break;
+               if (sp->user) {
+                       code = -EBUSY;
+                       break;
+               }
+               pvr2_channel_disclaim_stream(cp);
+               if (!sp) break;
+               sp->user = cp;
+               cp->stream = sp;
+       } while (0); pvr2_context_exit(cp->mc_head);
+       return code;
+}
+
+
+// This is the marker for the real beginning of a legitimate mpeg2 stream.
+static char stream_sync_key[] = {
+       0x00, 0x00, 0x01, 0xba,
+};
+
+struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
+       struct pvr2_context_stream *sp)
+{
+       struct pvr2_ioread *cp;
+       cp = pvr2_ioread_create();
+       if (!cp) return 0;
+       pvr2_ioread_setup(cp,sp->stream);
+       pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
+       return cp;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
new file mode 100644 (file)
index 0000000..6327fa1
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_BASE_H
+#define __PVRUSB2_BASE_H
+
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+struct pvr2_hdw;     /* hardware interface - defined elsewhere */
+struct pvr2_stream;  /* stream interface - defined elsewhere */
+
+struct pvr2_context;        /* All central state */
+struct pvr2_channel;        /* One I/O pathway to a user */
+struct pvr2_context_stream; /* Wrapper for a stream */
+struct pvr2_crit_reg;       /* Critical region pointer */
+struct pvr2_ioread;         /* Low level stream structure */
+
+struct pvr2_context_stream {
+       struct pvr2_channel *user;
+       struct pvr2_stream *stream;
+};
+
+struct pvr2_context {
+       struct pvr2_channel *mc_first;
+       struct pvr2_channel *mc_last;
+       struct pvr2_hdw *hdw;
+       struct pvr2_context_stream video_stream;
+       struct mutex mutex;
+       int disconnect_flag;
+
+       /* Called after pvr2_context initialization is complete */
+       void (*setup_func)(struct pvr2_context *);
+
+       /* Work queue overhead for out-of-line processing */
+       struct workqueue_struct *workqueue;
+       struct work_struct workinit;
+       struct work_struct workpoll;
+};
+
+struct pvr2_channel {
+       struct pvr2_context *mc_head;
+       struct pvr2_channel *mc_next;
+       struct pvr2_channel *mc_prev;
+       struct pvr2_context_stream *stream;
+       struct pvr2_hdw *hdw;
+       void (*check_func)(struct pvr2_channel *);
+};
+
+void pvr2_context_enter(struct pvr2_context *);
+void pvr2_context_exit(struct pvr2_context *);
+
+struct pvr2_context *pvr2_context_create(struct usb_interface *intf,
+                                        const struct usb_device_id *devid,
+                                        void (*setup_func)(struct pvr2_context *));
+void pvr2_context_disconnect(struct pvr2_context *);
+
+void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *);
+void pvr2_channel_done(struct pvr2_channel *);
+int pvr2_channel_claim_stream(struct pvr2_channel *,
+                             struct pvr2_context_stream *);
+struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
+       struct pvr2_context_stream *);
+
+
+#endif /* __PVRUSB2_CONTEXT_H */
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
new file mode 100644 (file)
index 0000000..d5df9fb
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-ctrl.h"
+#include "pvrusb2-hdw-internal.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
+{
+       return pvr2_ctrl_set_mask_value(cptr,~0,val);
+}
+
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
+{
+       int ret = 0;
+       if (!cptr) return -EINVAL;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->set_value != 0) {
+                       if (cptr->info->type == pvr2_ctl_bitmask) {
+                               mask &= cptr->info->def.type_bitmask.valid_bits;
+                       } else if (cptr->info->type == pvr2_ctl_int) {
+                               if (val < cptr->info->def.type_int.min_value) {
+                                       break;
+                               }
+                               if (val > cptr->info->def.type_int.max_value) {
+                                       break;
+                               }
+                       } else if (cptr->info->type == pvr2_ctl_enum) {
+                               if (val >= cptr->info->def.type_enum.count) {
+                                       break;
+                               }
+                       } else if (cptr->info->type != pvr2_ctl_bool) {
+                               break;
+                       }
+                       ret = cptr->info->set_value(cptr,mask,val);
+               } else {
+                       ret = -EPERM;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr)
+{
+       int ret = 0;
+       if (!cptr) return -EINVAL;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               ret = cptr->info->get_value(cptr,valptr);
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return pvr2_ctl_int;
+       return cptr->info->type;
+}
+
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_int) {
+                       ret = cptr->info->def.type_int.max_value;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_int) {
+                       ret = cptr->info->def.type_int.min_value;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_int) {
+                       ret = cptr->info->default_value;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_enum) {
+                       ret = cptr->info->def.type_enum.count;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_bitmask) {
+                       ret = cptr->info->def.type_bitmask.valid_bits;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       return cptr->info->name;
+}
+
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       return cptr->info->desc;
+}
+
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
+                         char *bptr,unsigned int bmax,
+                         unsigned int *blen)
+{
+       int ret = -EINVAL;
+       if (!cptr) return 0;
+       *blen = 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_enum) {
+                       const char **names;
+                       names = cptr->info->def.type_enum.value_names;
+                       if ((val >= 0) &&
+                           (val < cptr->info->def.type_enum.count)) {
+                               if (names[val]) {
+                                       *blen = scnprintf(
+                                               bptr,bmax,"%s",
+                                               names[val]);
+                               } else {
+                                       *blen = 0;
+                               }
+                               ret = 0;
+                       }
+               } else if (cptr->info->type == pvr2_ctl_bitmask) {
+                       const char **names;
+                       unsigned int idx;
+                       int msk;
+                       names = cptr->info->def.type_bitmask.bit_names;
+                       val &= cptr->info->def.type_bitmask.valid_bits;
+                       for (idx = 0, msk = 1; val; idx++, msk <<= 1) {
+                               if (val & msk) {
+                                       *blen = scnprintf(bptr,bmax,"%s",
+                                                         names[idx]);
+                                       ret = 0;
+                                       break;
+                               }
+                       }
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Return V4L ID for this control or zero if none */
+int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       return cptr->info->v4l_id;
+}
+
+
+unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
+{
+       unsigned int flags = 0;
+
+       if (cptr->info->get_v4lflags) {
+               flags = cptr->info->get_v4lflags(cptr);
+       }
+
+       if (cptr->info->set_value) {
+               flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
+       } else {
+               flags |= V4L2_CTRL_FLAG_READ_ONLY;
+       }
+
+       return flags;
+}
+
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       return cptr->info->set_value != 0;
+}
+
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       if (!cptr->info->val_to_sym) return 0;
+       if (!cptr->info->sym_to_val) return 0;
+       return !0;
+}
+
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
+                                 int mask,int val,
+                                 char *buf,unsigned int maxlen,
+                                 unsigned int *len)
+{
+       if (!cptr) return -EINVAL;
+       if (!cptr->info->val_to_sym) return -EINVAL;
+       return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
+                                 const char *buf,unsigned int len,
+                                 int *maskptr,int *valptr)
+{
+       if (!cptr) return -EINVAL;
+       if (!cptr->info->sym_to_val) return -EINVAL;
+       return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
+}
+
+
+static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
+                                      const char **names,
+                                      char *ptr,unsigned int len)
+{
+       unsigned int idx;
+       long sm,um;
+       int spcFl;
+       unsigned int uc,cnt;
+       const char *idStr;
+
+       spcFl = 0;
+       uc = 0;
+       um = 0;
+       for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
+               if (sm & msk) {
+                       msk &= ~sm;
+                       idStr = names[idx];
+                       if (idStr) {
+                               cnt = scnprintf(ptr,len,"%s%s%s",
+                                               (spcFl ? " " : ""),
+                                               (msk_only ? "" :
+                                                ((val & sm) ? "+" : "-")),
+                                               idStr);
+                               ptr += cnt; len -= cnt; uc += cnt;
+                               spcFl = !0;
+                       } else {
+                               um |= sm;
+                       }
+               }
+       }
+       if (um) {
+               if (msk_only) {
+                       cnt = scnprintf(ptr,len,"%s0x%lx",
+                                       (spcFl ? " " : ""),
+                                       um);
+                       ptr += cnt; len -= cnt; uc += cnt;
+                       spcFl = !0;
+               } else if (um & val) {
+                       cnt = scnprintf(ptr,len,"%s+0x%lx",
+                                       (spcFl ? " " : ""),
+                                       um & val);
+                       ptr += cnt; len -= cnt; uc += cnt;
+                       spcFl = !0;
+               } else if (um & ~val) {
+                       cnt = scnprintf(ptr,len,"%s+0x%lx",
+                                       (spcFl ? " " : ""),
+                                       um & ~val);
+                       ptr += cnt; len -= cnt; uc += cnt;
+                       spcFl = !0;
+               }
+       }
+       return uc;
+}
+
+
+static const char *boolNames[] = {
+       "false",
+       "true",
+       "no",
+       "yes",
+};
+
+
+static int parse_token(const char *ptr,unsigned int len,
+                      int *valptr,
+                      const char **names,unsigned int namecnt)
+{
+       char buf[33];
+       unsigned int slen;
+       unsigned int idx;
+       int negfl;
+       char *p2;
+       *valptr = 0;
+       if (!names) namecnt = 0;
+       for (idx = 0; idx < namecnt; idx++) {
+               if (!names[idx]) continue;
+               slen = strlen(names[idx]);
+               if (slen != len) continue;
+               if (memcmp(names[idx],ptr,slen)) continue;
+               *valptr = idx;
+               return 0;
+       }
+       negfl = 0;
+       if ((*ptr == '-') || (*ptr == '+')) {
+               negfl = (*ptr == '-');
+               ptr++; len--;
+       }
+       if (len >= sizeof(buf)) return -EINVAL;
+       memcpy(buf,ptr,len);
+       buf[len] = 0;
+       *valptr = simple_strtol(buf,&p2,0);
+       if (negfl) *valptr = -(*valptr);
+       if (*p2) return -EINVAL;
+       return 1;
+}
+
+
+static int parse_mtoken(const char *ptr,unsigned int len,
+                       int *valptr,
+                       const char **names,int valid_bits)
+{
+       char buf[33];
+       unsigned int slen;
+       unsigned int idx;
+       char *p2;
+       int msk;
+       *valptr = 0;
+       for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
+               if (!msk & valid_bits) continue;
+               valid_bits &= ~msk;
+               if (!names[idx]) continue;
+               slen = strlen(names[idx]);
+               if (slen != len) continue;
+               if (memcmp(names[idx],ptr,slen)) continue;
+               *valptr = msk;
+               return 0;
+       }
+       if (len >= sizeof(buf)) return -EINVAL;
+       memcpy(buf,ptr,len);
+       buf[len] = 0;
+       *valptr = simple_strtol(buf,&p2,0);
+       if (*p2) return -EINVAL;
+       return 0;
+}
+
+
+static int parse_tlist(const char *ptr,unsigned int len,
+                      int *maskptr,int *valptr,
+                      const char **names,int valid_bits)
+{
+       unsigned int cnt;
+       int mask,val,kv,mode,ret;
+       mask = 0;
+       val = 0;
+       ret = 0;
+       while (len) {
+               cnt = 0;
+               while ((cnt < len) &&
+                      ((ptr[cnt] <= 32) ||
+                       (ptr[cnt] >= 127))) cnt++;
+               ptr += cnt;
+               len -= cnt;
+               mode = 0;
+               if ((*ptr == '-') || (*ptr == '+')) {
+                       mode = (*ptr == '-') ? -1 : 1;
+                       ptr++;
+                       len--;
+               }
+               cnt = 0;
+               while (cnt < len) {
+                       if (ptr[cnt] <= 32) break;
+                       if (ptr[cnt] >= 127) break;
+                       cnt++;
+               }
+               if (!cnt) break;
+               if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ptr += cnt;
+               len -= cnt;
+               switch (mode) {
+               case 0:
+                       mask = valid_bits;
+                       val |= kv;
+                       break;
+               case -1:
+                       mask |= kv;
+                       val &= ~kv;
+                       break;
+               case 1:
+                       mask |= kv;
+                       val |= kv;
+                       break;
+               default:
+                       break;
+               }
+       }
+       *maskptr = mask;
+       *valptr = val;
+       return ret;
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
+                          const char *ptr,unsigned int len,
+                          int *maskptr,int *valptr)
+{
+       int ret = -EINVAL;
+       unsigned int cnt;
+
+       *maskptr = 0;
+       *valptr = 0;
+
+       cnt = 0;
+       while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
+       len -= cnt; ptr += cnt;
+       cnt = 0;
+       while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
+                              (ptr[len-(cnt+1)] >= 127))) cnt++;
+       len -= cnt;
+
+       if (!len) return -EINVAL;
+
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_int) {
+                       ret = parse_token(ptr,len,valptr,0,0);
+                       if ((ret >= 0) &&
+                           ((*valptr < cptr->info->def.type_int.min_value) ||
+                            (*valptr > cptr->info->def.type_int.max_value))) {
+                               ret = -ERANGE;
+                       }
+                       if (maskptr) *maskptr = ~0;
+               } else if (cptr->info->type == pvr2_ctl_bool) {
+                       ret = parse_token(
+                               ptr,len,valptr,boolNames,
+                               sizeof(boolNames)/sizeof(boolNames[0]));
+                       if (ret == 1) {
+                               *valptr = *valptr ? !0 : 0;
+                       } else if (ret == 0) {
+                               *valptr = (*valptr & 1) ? !0 : 0;
+                       }
+                       if (maskptr) *maskptr = 1;
+               } else if (cptr->info->type == pvr2_ctl_enum) {
+                       ret = parse_token(
+                               ptr,len,valptr,
+                               cptr->info->def.type_enum.value_names,
+                               cptr->info->def.type_enum.count);
+                       if ((ret >= 0) &&
+                           ((*valptr < 0) ||
+                            (*valptr >= cptr->info->def.type_enum.count))) {
+                               ret = -ERANGE;
+                       }
+                       if (maskptr) *maskptr = ~0;
+               } else if (cptr->info->type == pvr2_ctl_bitmask) {
+                       ret = parse_tlist(
+                               ptr,len,maskptr,valptr,
+                               cptr->info->def.type_bitmask.bit_names,
+                               cptr->info->def.type_bitmask.valid_bits);
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
+                                   int mask,int val,
+                                   char *buf,unsigned int maxlen,
+                                   unsigned int *len)
+{
+       int ret = -EINVAL;
+
+       *len = 0;
+       if (cptr->info->type == pvr2_ctl_int) {
+               *len = scnprintf(buf,maxlen,"%d",val);
+               ret = 0;
+       } else if (cptr->info->type == pvr2_ctl_bool) {
+               *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
+               ret = 0;
+       } else if (cptr->info->type == pvr2_ctl_enum) {
+               const char **names;
+               names = cptr->info->def.type_enum.value_names;
+               if ((val >= 0) &&
+                   (val < cptr->info->def.type_enum.count)) {
+                       if (names[val]) {
+                               *len = scnprintf(
+                                       buf,maxlen,"%s",
+                                       names[val]);
+                       } else {
+                               *len = 0;
+                       }
+                       ret = 0;
+               }
+       } else if (cptr->info->type == pvr2_ctl_bitmask) {
+               *len = gen_bitmask_string(
+                       val & mask & cptr->info->def.type_bitmask.valid_bits,
+                       ~0,!0,
+                       cptr->info->def.type_bitmask.bit_names,
+                       buf,maxlen);
+       }
+       return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
+                          int mask,int val,
+                          char *buf,unsigned int maxlen,
+                          unsigned int *len)
+{
+       int ret;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
+                                                     buf,maxlen,len);
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
new file mode 100644 (file)
index 0000000..c168005
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_CTRL_H
+#define __PVRUSB2_CTRL_H
+
+struct pvr2_ctrl;
+
+enum pvr2_ctl_type {
+       pvr2_ctl_int = 0,
+       pvr2_ctl_enum = 1,
+       pvr2_ctl_bitmask = 2,
+       pvr2_ctl_bool = 3,
+};
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *,int val);
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *,int mask,int val);
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *,int *valptr);
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *);
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *);
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *);
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *);
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *);
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *);
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *);
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *);
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *,int,char *,unsigned int,
+                         unsigned int *);
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *);
+
+/* Return V4L flags value for control (or zero if there is no v4l control
+   actually under this control) */
+unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *);
+
+/* Return V4L ID for this control or zero if none */
+int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *);
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *);
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *,
+                                 int mask,int val,
+                                 char *buf,unsigned int maxlen,
+                                 unsigned int *len);
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *,
+                                 const char *buf,unsigned int len,
+                                 int *maskptr,int *valptr);
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *,
+                          int mask,int val,
+                          char *buf,unsigned int maxlen,
+                          unsigned int *len);
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *,
+                          const char *buf,unsigned int len,
+                          int *maskptr,int *valptr);
+
+/* Convert a given mask/val to a symbolic value - must already be
+   inside of critical region. */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *,
+                          int mask,int val,
+                          char *buf,unsigned int maxlen,
+                          unsigned int *len);
+
+#endif /* __PVRUSB2_CTRL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
new file mode 100644 (file)
index 0000000..27eadaf
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+
+   This source file is specifically designed to interface with the
+   cx2584x, in kernels 2.6.16 or newer.
+
+*/
+
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <media/cx25840.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_cx2584x {
+       struct pvr2_i2c_handler handler;
+       struct pvr2_decoder_ctrl ctrl;
+       struct pvr2_i2c_client *client;
+       struct pvr2_hdw *hdw;
+       unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_cx2584x *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       struct v4l2_routing route;
+       enum cx25840_video_input vid_input;
+       enum cx25840_audio_input aud_input;
+
+       memset(&route,0,sizeof(route));
+
+       switch(hdw->input_val) {
+       case PVR2_CVAL_INPUT_TV:
+               vid_input = CX25840_COMPOSITE7;
+               aud_input = CX25840_AUDIO8;
+               break;
+       case PVR2_CVAL_INPUT_COMPOSITE:
+               vid_input = CX25840_COMPOSITE3;
+               aud_input = CX25840_AUDIO_SERIAL;
+               break;
+       case PVR2_CVAL_INPUT_SVIDEO:
+               vid_input = CX25840_SVIDEO1;
+               aud_input = CX25840_AUDIO_SERIAL;
+               break;
+       case PVR2_CVAL_INPUT_RADIO:
+       default:
+               // Just set it to be composite input for now...
+               vid_input = CX25840_COMPOSITE3;
+               aud_input = CX25840_AUDIO_SERIAL;
+               break;
+       }
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
+                  vid_input,aud_input);
+       route.input = (u32)vid_input;
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+       route.input = (u32)aud_input;
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+
+static int check_input(struct pvr2_v4l_cx2584x *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->input_dirty != 0;
+}
+
+
+static void set_audio(struct pvr2_v4l_cx2584x *ctxt)
+{
+       u32 val;
+       struct pvr2_hdw *hdw = ctxt->hdw;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_audio %d",
+                  hdw->srate_val);
+       switch (hdw->srate_val) {
+       default:
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+               val = 48000;
+               break;
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+               val = 44100;
+               break;
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+               val = 32000;
+               break;
+       }
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+}
+
+
+static int check_audio(struct pvr2_v4l_cx2584x *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->srate_dirty != 0;
+}
+
+
+struct pvr2_v4l_cx2584x_ops {
+       void (*update)(struct pvr2_v4l_cx2584x *);
+       int (*check)(struct pvr2_v4l_cx2584x *);
+};
+
+
+static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
+       { .update = set_input, .check = check_input},
+       { .update = set_audio, .check = check_audio},
+};
+
+
+static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
+{
+       ctxt->client->handler = 0;
+       ctxt->hdw->decoder_ctrl = 0;
+       kfree(ctxt);
+}
+
+
+static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (ctxt->stale_mask & msk) continue;
+               if (decoder_ops[idx].check(ctxt)) {
+                       ctxt->stale_mask |= msk;
+               }
+       }
+       return ctxt->stale_mask != 0;
+}
+
+
+static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (!(ctxt->stale_mask & msk)) continue;
+               ctxt->stale_mask &= ~msk;
+               decoder_ops[idx].update(ctxt);
+       }
+}
+
+
+static void decoder_enable(struct pvr2_v4l_cx2584x *ctxt,int fl)
+{
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_enable(%d)",fl);
+       pvr2_v4l2_cmd_stream(ctxt->client,fl);
+}
+
+
+static int decoder_detect(struct pvr2_i2c_client *cp)
+{
+       int ret;
+       /* Attempt to query the decoder - let's see if it will answer */
+       struct v4l2_queryctrl qc;
+
+       memset(&qc,0,sizeof(qc));
+
+       qc.id = V4L2_CID_BRIGHTNESS;
+
+       ret = pvr2_i2c_client_cmd(cp,VIDIOC_QUERYCTRL,&qc);
+       return ret == 0; /* Return true if it answered */
+}
+
+
+static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
+{
+       struct v4l2_tuner vt;
+       int ret;
+
+       memset(&vt,0,sizeof(vt));
+       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+       if (ret < 0) return -EINVAL;
+       return vt.signal ? 1 : 0;
+}
+
+
+static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
+                                    char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-cx2584x-v4l");
+}
+
+
+static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
+{
+       int ret;
+       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0);
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+       .detach = (void (*)(void *))decoder_detach,
+       .check = (int (*)(void *))decoder_check,
+       .update = (void (*)(void *))decoder_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+};
+
+
+int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
+                              struct pvr2_i2c_client *cp)
+{
+       struct pvr2_v4l_cx2584x *ctxt;
+
+       if (hdw->decoder_ctrl) return 0;
+       if (cp->handler) return 0;
+       if (!decoder_detect(cp)) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->handler.func_data = ctxt;
+       ctxt->handler.func_table = &hfuncs;
+       ctxt->ctrl.ctxt = ctxt;
+       ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+       ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+       ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
+       ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
+                                 sizeof(decoder_ops[0]))) - 1;
+       hdw->decoder_ctrl = &ctxt->ctrl;
+       cp->handler = &ctxt->handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
new file mode 100644 (file)
index 0000000..54b2844
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_CX2584X_V4L_H
+#define __PVRUSB2_CX2584X_V4L_H
+
+/*
+
+   This module connects the pvrusb2 driver to the I2C chip level
+   driver which handles combined device audio & video processing.
+   This interface is used internally by the driver; higher level code
+   should only interact through the interface provided by
+   pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_CX2584X_V4L_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
new file mode 100644 (file)
index 0000000..d95a858
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_DEBUG_H
+#define __PVRUSB2_DEBUG_H
+
+extern int pvrusb2_debug;
+
+#define pvr2_trace(msk, fmt, arg...) do {if(msk & pvrusb2_debug) printk(KERN_INFO "pvrusb2: " fmt "\n", ##arg); } while (0)
+
+/* These are listed in *rough* order of decreasing usefulness and
+   increasing noise level. */
+#define PVR2_TRACE_INFO       (1 <<  0) // Normal messages
+#define PVR2_TRACE_ERROR_LEGS (1 <<  1) // error messages
+#define PVR2_TRACE_TOLERANCE  (1 <<  2) // track tolerance-affected errors
+#define PVR2_TRACE_TRAP       (1 <<  3) // Trap & report misbehavior from app
+#define PVR2_TRACE_INIT       (1 <<  4) // misc initialization steps
+#define PVR2_TRACE_START_STOP (1 <<  5) // Streaming start / stop
+#define PVR2_TRACE_CTL        (1 <<  6) // commit of control changes
+#define PVR2_TRACE_DEBUG      (1 <<  7) // Temporary debug code
+#define PVR2_TRACE_EEPROM     (1 <<  8) // eeprom parsing / report
+#define PVR2_TRACE_STRUCT     (1 <<  9) // internal struct creation
+#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close
+#define PVR2_TRACE_CREG       (1 << 11) // Main critical region entry / exit
+#define PVR2_TRACE_SYSFS      (1 << 12) // Sysfs driven I/O
+#define PVR2_TRACE_FIRMWARE   (1 << 13) // firmware upload actions
+#define PVR2_TRACE_CHIPS      (1 << 14) // chip broadcast operation
+#define PVR2_TRACE_I2C        (1 << 15) // I2C related stuff
+#define PVR2_TRACE_I2C_CMD    (1 << 16) // Software commands to I2C modules
+#define PVR2_TRACE_I2C_CORE   (1 << 17) // I2C core debugging
+#define PVR2_TRACE_I2C_TRAF   (1 << 18) // I2C traffic through the adapter
+#define PVR2_TRACE_V4LIOCTL   (1 << 19) // v4l ioctl details
+#define PVR2_TRACE_ENCODER    (1 << 20) // mpeg2 encoder operation
+#define PVR2_TRACE_BUF_POOL   (1 << 21) // Track buffer pool management
+#define PVR2_TRACE_BUF_FLOW   (1 << 22) // Track buffer flow in system
+#define PVR2_TRACE_DATA_FLOW  (1 << 23) // Track data flow
+#define PVR2_TRACE_DEBUGIFC   (1 << 24) // Debug interface actions
+#define PVR2_TRACE_GPIO       (1 << 25) // GPIO state bit changes
+
+
+#endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
new file mode 100644 (file)
index 0000000..586900e
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "pvrusb2-debugifc.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-i2c-core.h"
+
+struct debugifc_mask_item {
+       const char *name;
+       unsigned long msk;
+};
+
+static struct debugifc_mask_item mask_items[] = {
+       {"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
+       {"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
+       {"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
+       {"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
+       {"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
+};
+
+
+static unsigned int debugifc_count_whitespace(const char *buf,
+                                             unsigned int count)
+{
+       unsigned int scnt;
+       char ch;
+
+       for (scnt = 0; scnt < count; scnt++) {
+               ch = buf[scnt];
+               if (ch == ' ') continue;
+               if (ch == '\t') continue;
+               if (ch == '\n') continue;
+               break;
+       }
+       return scnt;
+}
+
+
+static unsigned int debugifc_count_nonwhitespace(const char *buf,
+                                                unsigned int count)
+{
+       unsigned int scnt;
+       char ch;
+
+       for (scnt = 0; scnt < count; scnt++) {
+               ch = buf[scnt];
+               if (ch == ' ') break;
+               if (ch == '\t') break;
+               if (ch == '\n') break;
+       }
+       return scnt;
+}
+
+
+static unsigned int debugifc_isolate_word(const char *buf,unsigned int count,
+                                         const char **wstrPtr,
+                                         unsigned int *wlenPtr)
+{
+       const char *wptr;
+       unsigned int consume_cnt = 0;
+       unsigned int wlen;
+       unsigned int scnt;
+
+       wptr = 0;
+       wlen = 0;
+       scnt = debugifc_count_whitespace(buf,count);
+       consume_cnt += scnt; count -= scnt; buf += scnt;
+       if (!count) goto done;
+
+       scnt = debugifc_count_nonwhitespace(buf,count);
+       if (!scnt) goto done;
+       wptr = buf;
+       wlen = scnt;
+       consume_cnt += scnt; count -= scnt; buf += scnt;
+
+ done:
+       *wstrPtr = wptr;
+       *wlenPtr = wlen;
+       return consume_cnt;
+}
+
+
+static int debugifc_parse_unsigned_number(const char *buf,unsigned int count,
+                                         u32 *num_ptr)
+{
+       u32 result = 0;
+       u32 val;
+       int ch;
+       int radix = 10;
+       if ((count >= 2) && (buf[0] == '0') &&
+           ((buf[1] == 'x') || (buf[1] == 'X'))) {
+               radix = 16;
+               count -= 2;
+               buf += 2;
+       } else if ((count >= 1) && (buf[0] == '0')) {
+               radix = 8;
+       }
+
+       while (count--) {
+               ch = *buf++;
+               if ((ch >= '0') && (ch <= '9')) {
+                       val = ch - '0';
+               } else if ((ch >= 'a') && (ch <= 'f')) {
+                       val = ch - 'a' + 10;
+               } else if ((ch >= 'A') && (ch <= 'F')) {
+                       val = ch - 'A' + 10;
+               } else {
+                       return -EINVAL;
+               }
+               if (val >= radix) return -EINVAL;
+               result *= radix;
+               result += val;
+       }
+       *num_ptr = result;
+       return 0;
+}
+
+
+static int debugifc_match_keyword(const char *buf,unsigned int count,
+                                 const char *keyword)
+{
+       unsigned int kl;
+       if (!keyword) return 0;
+       kl = strlen(keyword);
+       if (kl != count) return 0;
+       return !memcmp(buf,keyword,kl);
+}
+
+
+static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
+{
+       struct debugifc_mask_item *mip;
+       unsigned int idx;
+       for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+               mip = mask_items + idx;
+               if (debugifc_match_keyword(buf,count,mip->name)) {
+                       return mip->msk;
+               }
+       }
+       return 0;
+}
+
+
+static int debugifc_print_mask(char *buf,unsigned int sz,
+                              unsigned long msk,unsigned long val)
+{
+       struct debugifc_mask_item *mip;
+       unsigned int idx;
+       int bcnt = 0;
+       int ccnt;
+       for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+               mip = mask_items + idx;
+               if (!(mip->msk & msk)) continue;
+               ccnt = scnprintf(buf,sz,"%s%c%s",
+                                (bcnt ? " " : ""),
+                                ((mip->msk & val) ? '+' : '-'),
+                                mip->name);
+               sz -= ccnt;
+               buf += ccnt;
+               bcnt += ccnt;
+       }
+       return bcnt;
+}
+
+static unsigned int debugifc_parse_subsys_mask(const char *buf,
+                                              unsigned int count,
+                                              unsigned long *mskPtr,
+                                              unsigned long *valPtr)
+{
+       const char *wptr;
+       unsigned int consume_cnt = 0;
+       unsigned int scnt;
+       unsigned int wlen;
+       int mode;
+       unsigned long m1,msk,val;
+
+       msk = 0;
+       val = 0;
+
+       while (count) {
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) break;
+               consume_cnt += scnt; count -= scnt; buf += scnt;
+               if (!wptr) break;
+
+               mode = 0;
+               if (wlen) switch (wptr[0]) {
+               case '+':
+                       wptr++;
+                       wlen--;
+                       break;
+               case '-':
+                       mode = 1;
+                       wptr++;
+                       wlen--;
+                       break;
+               }
+               if (!wlen) continue;
+               m1 = debugifc_find_mask(wptr,wlen);
+               if (!m1) break;
+               msk |= m1;
+               if (!mode) val |= m1;
+       }
+       *mskPtr = msk;
+       *valPtr = val;
+       return consume_cnt;
+}
+
+
+int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
+{
+       int bcnt = 0;
+       int ccnt;
+       struct pvr2_hdw_debug_info dbg;
+
+       pvr2_hdw_get_debug_info(hdw,&dbg);
+
+       ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
+                        (dbg.big_lock_held ? "held" : "free"),
+                        (dbg.ctl_lock_held ? "held" : "free"));
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       if (dbg.ctl_lock_held) {
+               ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
+                                " cmd_wlen=%d cmd_rlen=%d"
+                                " wpend=%d rpend=%d tmout=%d rstatus=%d"
+                                " wstatus=%d",
+                                dbg.cmd_debug_state,dbg.cmd_code,
+                                dbg.cmd_debug_write_len,
+                                dbg.cmd_debug_read_len,
+                                dbg.cmd_debug_write_pend,
+                                dbg.cmd_debug_read_pend,
+                                dbg.cmd_debug_timeout,
+                                dbg.cmd_debug_rstatus,
+                                dbg.cmd_debug_wstatus);
+               bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       }
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(
+               buf,acnt,"driver flags: %s %s %s\n",
+               (dbg.flag_init_ok ? "initialized" : "uninitialized"),
+               (dbg.flag_ok ? "ok" : "fail"),
+               (dbg.flag_disconnected ? "disconnected" : "connected"));
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = pvr2_i2c_report(hdw,buf,acnt);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       return bcnt;
+}
+
+
+int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
+                              char *buf,unsigned int acnt)
+{
+       int bcnt = 0;
+       int ccnt;
+       unsigned long msk;
+       int ret;
+       u32 gpio_dir,gpio_in,gpio_out;
+
+       ret = pvr2_hdw_is_hsm(hdw);
+       ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
+                        (ret < 0 ? "FAIL" : (ret ? "high" : "full")));
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       gpio_dir = 0; gpio_in = 0; gpio_out = 0;
+       pvr2_hdw_gpio_get_dir(hdw,&gpio_dir);
+       pvr2_hdw_gpio_get_out(hdw,&gpio_out);
+       pvr2_hdw_gpio_get_in(hdw,&gpio_in);
+       ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n",
+                        gpio_dir,gpio_in,gpio_out);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       ccnt = scnprintf(buf,acnt,"Streaming is %s\n",
+                        pvr2_hdw_get_streaming(hdw) ? "on" : "off");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       msk = pvr2_hdw_subsys_get(hdw);
+       ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,msk,msk);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       msk = pvr2_hdw_subsys_stream_get(hdw);
+       ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,msk,msk);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       return bcnt;
+}
+
+
+int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
+                        unsigned int count)
+{
+       const char *wptr;
+       unsigned int wlen;
+       unsigned int scnt;
+
+       scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+       if (!scnt) return 0;
+       count -= scnt; buf += scnt;
+       if (!wptr) return 0;
+
+       pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr);
+       if (debugifc_match_keyword(wptr,wlen,"reset")) {
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) return -EINVAL;
+               count -= scnt; buf += scnt;
+               if (!wptr) return -EINVAL;
+               if (debugifc_match_keyword(wptr,wlen,"cpu")) {
+                       pvr2_hdw_cpureset_assert(hdw,!0);
+                       pvr2_hdw_cpureset_assert(hdw,0);
+                       return 0;
+               } else if (debugifc_match_keyword(wptr,wlen,"bus")) {
+                       pvr2_hdw_device_reset(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"soft")) {
+                       return pvr2_hdw_cmd_powerup(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"deep")) {
+                       return pvr2_hdw_cmd_deep_reset(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"firmware")) {
+                       return pvr2_upload_firmware2(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
+                       return pvr2_hdw_cmd_decoder_reset(hdw);
+               }
+               return -EINVAL;
+       } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
+               unsigned long msk = 0;
+               unsigned long val = 0;
+               if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
+                       pvr2_trace(PVR2_TRACE_DEBUGIFC,
+                                  "debugifc parse error on subsys mask");
+                       return -EINVAL;
+               }
+               pvr2_hdw_subsys_bit_chg(hdw,msk,val);
+               return 0;
+       } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
+               unsigned long msk = 0;
+               unsigned long val = 0;
+               if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
+                       pvr2_trace(PVR2_TRACE_DEBUGIFC,
+                                  "debugifc parse error on stream mask");
+                       return -EINVAL;
+               }
+               pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
+               return 0;
+       } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) return -EINVAL;
+               count -= scnt; buf += scnt;
+               if (!wptr) return -EINVAL;
+               if (debugifc_match_keyword(wptr,wlen,"fetch")) {
+                       pvr2_hdw_cpufw_set_enabled(hdw,!0);
+                       return 0;
+               } else if (debugifc_match_keyword(wptr,wlen,"done")) {
+                       pvr2_hdw_cpufw_set_enabled(hdw,0);
+                       return 0;
+               } else {
+                       return -EINVAL;
+               }
+       } else if (debugifc_match_keyword(wptr,wlen,"gpio")) {
+               int dir_fl = 0;
+               int ret;
+               u32 msk,val;
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) return -EINVAL;
+               count -= scnt; buf += scnt;
+               if (!wptr) return -EINVAL;
+               if (debugifc_match_keyword(wptr,wlen,"dir")) {
+                       dir_fl = !0;
+               } else if (!debugifc_match_keyword(wptr,wlen,"out")) {
+                       return -EINVAL;
+               }
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) return -EINVAL;
+               count -= scnt; buf += scnt;
+               if (!wptr) return -EINVAL;
+               ret = debugifc_parse_unsigned_number(wptr,wlen,&msk);
+               if (ret) return ret;
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (wptr) {
+                       ret = debugifc_parse_unsigned_number(wptr,wlen,&val);
+                       if (ret) return ret;
+               } else {
+                       val = msk;
+                       msk = 0xffffffff;
+               }
+               if (dir_fl) {
+                       ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val);
+               } else {
+                       ret = pvr2_hdw_gpio_chg_out(hdw,msk,val);
+               }
+               return ret;
+       }
+       pvr2_trace(PVR2_TRACE_DEBUGIFC,
+                  "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr);
+       return -EINVAL;
+}
+
+
+int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf,
+                       unsigned int count)
+{
+       unsigned int bcnt = 0;
+       int ret;
+
+       while (count) {
+               for (bcnt = 0; bcnt < count; bcnt++) {
+                       if (buf[bcnt] == '\n') break;
+               }
+
+               ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt);
+               if (ret < 0) return ret;
+               if (bcnt < count) bcnt++;
+               buf += bcnt;
+               count -= bcnt;
+       }
+
+       return 0;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
new file mode 100644 (file)
index 0000000..990b02d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_DEBUGIFC_H
+#define __PVRUSB2_DEBUGIFC_H
+
+struct pvr2_hdw;
+
+/* Non-intrusively print some useful debugging info from inside the
+   driver.  This should work even if the driver appears to be
+   wedged. */
+int pvr2_debugifc_print_info(struct pvr2_hdw *,
+                            char *buf_ptr,unsigned int buf_size);
+
+/* Print general status of driver.  This will also trigger a probe of
+   the USB link.  Unlike print_info(), this one synchronizes with the
+   driver so the information should be self-consistent (but it will
+   hang if the driver is wedged). */
+int pvr2_debugifc_print_status(struct pvr2_hdw *,
+                              char *buf_ptr,unsigned int buf_size);
+
+/* Parse a string command into a driver action. */
+int pvr2_debugifc_docmd(struct pvr2_hdw *,
+                       const char *buf_ptr,unsigned int buf_size);
+
+#endif /* __PVRUSB2_DEBUGIFC_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-demod.c b/drivers/media/video/pvrusb2/pvrusb2-demod.c
new file mode 100644 (file)
index 0000000..9686569
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2.h"
+#include "pvrusb2-util.h"
+#include "pvrusb2-demod.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+
+
+struct pvr2_demod_handler {
+       struct pvr2_hdw *hdw;
+       struct pvr2_i2c_client *client;
+       struct pvr2_i2c_handler i2c_handler;
+       int type_update_fl;
+};
+
+
+static void set_config(struct pvr2_demod_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       int cfg = 0;
+
+       switch (hdw->tuner_type) {
+       case TUNER_PHILIPS_FM1216ME_MK3:
+       case TUNER_PHILIPS_FM1236_MK3:
+               cfg = TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE;
+               break;
+       default:
+               break;
+       }
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c demod set_config(0x%x)",cfg);
+       pvr2_i2c_client_cmd(ctxt->client,TDA9887_SET_CONFIG,&cfg);
+       ctxt->type_update_fl = 0;
+}
+
+
+static int demod_check(struct pvr2_demod_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       if (hdw->tuner_updated) ctxt->type_update_fl = !0;
+       return ctxt->type_update_fl != 0;
+}
+
+
+static void demod_update(struct pvr2_demod_handler *ctxt)
+{
+       if (ctxt->type_update_fl) set_config(ctxt);
+}
+
+
+static void demod_detach(struct pvr2_demod_handler *ctxt)
+{
+       ctxt->client->handler = 0;
+       kfree(ctxt);
+}
+
+
+static unsigned int demod_describe(struct pvr2_demod_handler *ctxt,char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-demod");
+}
+
+
+const static struct pvr2_i2c_handler_functions tuner_funcs = {
+       .detach = (void (*)(void *))demod_detach,
+       .check = (int (*)(void *))demod_check,
+       .update = (void (*)(void *))demod_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))demod_describe,
+};
+
+
+int pvr2_i2c_demod_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       struct pvr2_demod_handler *ctxt;
+       if (cp->handler) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->i2c_handler.func_data = ctxt;
+       ctxt->i2c_handler.func_table = &tuner_funcs;
+       ctxt->type_update_fl = !0;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       cp->handler = &ctxt->i2c_handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tda9887 V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-demod.h b/drivers/media/video/pvrusb2/pvrusb2-demod.h
new file mode 100644 (file)
index 0000000..4c4e40f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_DEMOD_H
+#define __PVRUSB2_DEMOD_H
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_demod_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+#endif /* __PVRUSB2_DEMOD_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
new file mode 100644 (file)
index 0000000..94d383f
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-eeprom.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
+
+
+
+/*
+
+   Read and analyze data in the eeprom.  Use tveeprom to figure out
+   the packet structure, since this is another Hauppauge device and
+   internally it has a family resemblence to ivtv-type devices
+
+*/
+
+#include <media/tveeprom.h>
+
+/* We seem to only be interested in the last 128 bytes of the EEPROM */
+#define EEPROM_SIZE 128
+
+/* Grab EEPROM contents, needed for direct method. */
+static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
+{
+       struct i2c_msg msg[2];
+       u8 *eeprom;
+       u8 iadd[2];
+       u8 addr;
+       u16 eepromSize;
+       unsigned int offs;
+       int ret;
+       int mode16 = 0;
+       unsigned pcnt,tcnt;
+       eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL);
+       if (!eeprom) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to allocate memory"
+                          " required to read eeprom");
+               return 0;
+       }
+
+       trace_eeprom("Value for eeprom addr from controller was 0x%x",
+                    hdw->eeprom_addr);
+       addr = hdw->eeprom_addr;
+       /* Seems that if the high bit is set, then the *real* eeprom
+          address is shifted right now bit position (noticed this in
+          newer PVR USB2 hardware) */
+       if (addr & 0x80) addr >>= 1;
+
+       /* FX2 documentation states that a 16bit-addressed eeprom is
+          expected if the I2C address is an odd number (yeah, this is
+          strange but it's what they do) */
+       mode16 = (addr & 1);
+       eepromSize = (mode16 ? 4096 : 256);
+       trace_eeprom("Examining %d byte eeprom at location 0x%x"
+                    " using %d bit addressing",eepromSize,addr,
+                    mode16 ? 16 : 8);
+
+       msg[0].addr = addr;
+       msg[0].flags = 0;
+       msg[0].len = mode16 ? 2 : 1;
+       msg[0].buf = iadd;
+       msg[1].addr = addr;
+       msg[1].flags = I2C_M_RD;
+
+       /* We have to do the actual eeprom data fetch ourselves, because
+          (1) we're only fetching part of the eeprom, and (2) if we were
+          getting the whole thing our I2C driver can't grab it in one
+          pass - which is what tveeprom is otherwise going to attempt */
+       memset(eeprom,0,EEPROM_SIZE);
+       for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
+               pcnt = 16;
+               if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
+               offs = tcnt + (eepromSize - EEPROM_SIZE);
+               if (mode16) {
+                       iadd[0] = offs >> 8;
+                       iadd[1] = offs;
+               } else {
+                       iadd[0] = offs;
+               }
+               msg[1].len = pcnt;
+               msg[1].buf = eeprom+tcnt;
+               if ((ret = i2c_transfer(
+                            &hdw->i2c_adap,
+                            msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "eeprom fetch set offs err=%d",ret);
+                       kfree(eeprom);
+                       return 0;
+               }
+       }
+       return eeprom;
+}
+
+
+/* Directly call eeprom analysis function within tveeprom. */
+int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
+{
+       u8 *eeprom;
+       struct tveeprom tvdata;
+
+       memset(&tvdata,0,sizeof(tvdata));
+
+       eeprom = pvr2_eeprom_fetch(hdw);
+       if (!eeprom) return -EINVAL;
+
+       {
+               struct i2c_client fake_client;
+               /* Newer version expects a useless client interface */
+               fake_client.addr = hdw->eeprom_addr;
+               fake_client.adapter = &hdw->i2c_adap;
+               tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom);
+       }
+
+       trace_eeprom("eeprom assumed v4l tveeprom module");
+       trace_eeprom("eeprom direct call results:");
+       trace_eeprom("has_radio=%d",tvdata.has_radio);
+       trace_eeprom("tuner_type=%d",tvdata.tuner_type);
+       trace_eeprom("tuner_formats=0x%x",tvdata.tuner_formats);
+       trace_eeprom("audio_processor=%d",tvdata.audio_processor);
+       trace_eeprom("model=%d",tvdata.model);
+       trace_eeprom("revision=%d",tvdata.revision);
+       trace_eeprom("serial_number=%d",tvdata.serial_number);
+       trace_eeprom("rev_str=%s",tvdata.rev_str);
+       hdw->tuner_type = tvdata.tuner_type;
+       hdw->serial_number = tvdata.serial_number;
+       hdw->std_mask_eeprom = tvdata.tuner_formats;
+
+       kfree(eeprom);
+
+       return 0;
+}
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
new file mode 100644 (file)
index 0000000..8424297
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_EEPROM_H
+#define __PVRUSB2_EEPROM_H
+
+struct pvr2_hdw;
+
+int pvr2_eeprom_analyze(struct pvr2_hdw *);
+
+#endif /* __PVRUSB2_EEPROM_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
new file mode 100644 (file)
index 0000000..2cc3169
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/device.h>   // for linux/firmware.h
+#include <linux/firmware.h>
+#include "pvrusb2-util.h"
+#include "pvrusb2-encoder.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+
+
+/* Firmware mailbox flags - definitions found from ivtv */
+#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
+#define IVTV_MBOX_DRIVER_DONE 0x00000002
+#define IVTV_MBOX_DRIVER_BUSY 0x00000001
+
+
+static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
+                                   const u32 *data, unsigned int dlen)
+{
+       unsigned int idx;
+       int ret;
+       unsigned int offs = 0;
+       unsigned int chunkCnt;
+
+       /*
+
+       Format: First byte must be 0x01.  Remaining 32 bit words are
+       spread out into chunks of 7 bytes each, little-endian ordered,
+       offset at zero within each 2 blank bytes following and a
+       single byte that is 0x44 plus the offset of the word.  Repeat
+       request for additional words, with offset adjusted
+       accordingly.
+
+       */
+       while (dlen) {
+               chunkCnt = 8;
+               if (chunkCnt > dlen) chunkCnt = dlen;
+               memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
+               hdw->cmd_buffer[0] = 0x01;
+               for (idx = 0; idx < chunkCnt; idx++) {
+                       hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
+                       PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
+                                         data[idx]);
+               }
+               ret = pvr2_send_request(hdw,
+                                       hdw->cmd_buffer,1+(chunkCnt*7),
+                                       0,0);
+               if (ret) return ret;
+               data += chunkCnt;
+               dlen -= chunkCnt;
+               offs += chunkCnt;
+       }
+
+       return 0;
+}
+
+
+static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
+                                  u32 *data, unsigned int dlen)
+{
+       unsigned int idx;
+       int ret;
+       unsigned int offs = 0;
+       unsigned int chunkCnt;
+
+       /*
+
+       Format: First byte must be 0x02 (status check) or 0x28 (read
+       back block of 32 bit words).  Next 6 bytes must be zero,
+       followed by a single byte of 0x44+offset for portion to be
+       read.  Returned data is packed set of 32 bits words that were
+       read.
+
+       */
+
+       while (dlen) {
+               chunkCnt = 16;
+               if (chunkCnt > dlen) chunkCnt = dlen;
+               memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
+               hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
+               hdw->cmd_buffer[7] = 0x44 + offs;
+               ret = pvr2_send_request(hdw,
+                                       hdw->cmd_buffer,8,
+                                       hdw->cmd_buffer,chunkCnt * 4);
+               if (ret) return ret;
+
+               for (idx = 0; idx < chunkCnt; idx++) {
+                       data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);
+               }
+               data += chunkCnt;
+               dlen -= chunkCnt;
+               offs += chunkCnt;
+       }
+
+       return 0;
+}
+
+
+/* This prototype is set up to be compatible with the
+   cx2341x_mbox_func prototype in cx2341x.h, which should be in
+   kernels 2.6.18 or later.  We do this so that we can enable
+   cx2341x.ko to write to our encoder (by handing it a pointer to this
+   function).  For earlier kernels this doesn't really matter. */
+static int pvr2_encoder_cmd(void *ctxt,
+                           int cmd,
+                           int arg_cnt_send,
+                           int arg_cnt_recv,
+                           u32 *argp)
+{
+       unsigned int poll_count;
+       int ret = 0;
+       unsigned int idx;
+       /* These sizes look to be limited by the FX2 firmware implementation */
+       u32 wrData[16];
+       u32 rdData[16];
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
+
+
+       /*
+
+       The encoder seems to speak entirely using blocks 32 bit words.
+       In ivtv driver terms, this is a mailbox which we populate with
+       data and watch what the hardware does with it.  The first word
+       is a set of flags used to control the transaction, the second
+       word is the command to execute, the third byte is zero (ivtv
+       driver suggests that this is some kind of return value), and
+       the fourth byte is a specified timeout (windows driver always
+       uses 0x00060000 except for one case when it is zero).  All
+       successive words are the argument words for the command.
+
+       First, write out the entire set of words, with the first word
+       being zero.
+
+       Next, write out just the first word again, but set it to
+       IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
+       probably means "go").
+
+       Next, read back 16 words as status.  Check the first word,
+       which should have IVTV_MBOX_FIRMWARE_DONE set.  If however
+       that bit is not set, then the command isn't done so repeat the
+       read.
+
+       Next, read back 32 words and compare with the original
+       arugments.  Hopefully they will match.
+
+       Finally, write out just the first word again, but set it to
+       0x0 this time (which probably means "idle").
+
+       */
+
+       if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Failed to write cx23416 command"
+                       " - too many input arguments"
+                       " (was given %u limit %u)",
+                       arg_cnt_send,
+                       (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
+               return -EINVAL;
+       }
+
+       if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Failed to write cx23416 command"
+                       " - too many return arguments"
+                       " (was given %u limit %u)",
+                       arg_cnt_recv,
+                       (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
+               return -EINVAL;
+       }
+
+
+       LOCK_TAKE(hdw->ctl_lock); do {
+
+               wrData[0] = 0;
+               wrData[1] = cmd;
+               wrData[2] = 0;
+               wrData[3] = 0x00060000;
+               for (idx = 0; idx < arg_cnt_send; idx++) {
+                       wrData[idx+4] = argp[idx];
+               }
+               for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+                       wrData[idx+4] = 0;
+               }
+
+               ret = pvr2_encoder_write_words(hdw,wrData,idx);
+               if (ret) break;
+               wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
+               ret = pvr2_encoder_write_words(hdw,wrData,1);
+               if (ret) break;
+               poll_count = 0;
+               while (1) {
+                       if (poll_count < 10000000) poll_count++;
+                       ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
+                       if (ret) break;
+                       if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
+                               break;
+                       }
+                       if (poll_count == 100) {
+                               pvr2_trace(
+                                       PVR2_TRACE_ERROR_LEGS,
+                                       "***WARNING*** device's encoder"
+                                       " appears to be stuck"
+                                       " (status=0%08x)",rdData[0]);
+                               pvr2_trace(
+                                       PVR2_TRACE_ERROR_LEGS,
+                                       "Encoder command: 0x%02x",cmd);
+                               for (idx = 4; idx < arg_cnt_send; idx++) {
+                                       pvr2_trace(
+                                               PVR2_TRACE_ERROR_LEGS,
+                                               "Encoder arg%d: 0x%08x",
+                                               idx-3,wrData[idx]);
+                               }
+                               pvr2_trace(
+                                       PVR2_TRACE_ERROR_LEGS,
+                                       "Giving up waiting."
+                                       "  It is likely that"
+                                       " this is a bad idea...");
+                               ret = -EBUSY;
+                               break;
+                       }
+               }
+               if (ret) break;
+               wrData[0] = 0x7;
+               ret = pvr2_encoder_read_words(
+                       hdw,0,rdData,
+                       sizeof(rdData)/sizeof(rdData[0]));
+               if (ret) break;
+               for (idx = 0; idx < arg_cnt_recv; idx++) {
+                       argp[idx] = rdData[idx+4];
+               }
+
+               wrData[0] = 0x0;
+               ret = pvr2_encoder_write_words(hdw,wrData,1);
+               if (ret) break;
+
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
+                            int args, ...)
+{
+       va_list vl;
+       unsigned int idx;
+       u32 data[12];
+
+       if (args > sizeof(data)/sizeof(data[0])) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Failed to write cx23416 command"
+                       " - too many arguments"
+                       " (was given %u limit %u)",
+                       args,(unsigned int)(sizeof(data)/sizeof(data[0])));
+               return -EINVAL;
+       }
+
+       va_start(vl, args);
+       for (idx = 0; idx < args; idx++) {
+               data[idx] = va_arg(vl, u32);
+       }
+       va_end(vl);
+
+       return pvr2_encoder_cmd(hdw,cmd,args,0,data);
+}
+
+int pvr2_encoder_configure(struct pvr2_hdw *hdw)
+{
+       int ret;
+       pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure"
+                  " (cx2341x module)");
+       hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING;
+       hdw->enc_ctl_state.width = hdw->res_hor_val;
+       hdw->enc_ctl_state.height = hdw->res_ver_val;
+       hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur &
+                                      (V4L2_STD_NTSC|V4L2_STD_PAL_M)) ?
+                                     0 : 1);
+
+       ret = 0;
+
+       if (!ret) ret = pvr2_encoder_vcmd(
+               hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
+               0xf0, 0xf0);
+
+       /* setup firmware to notify us about some events (don't know why...) */
+       if (!ret) ret = pvr2_encoder_vcmd(
+               hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
+               0, 0, 0x10000000, 0xffffffff);
+
+       if (!ret) ret = pvr2_encoder_vcmd(
+               hdw,CX2341X_ENC_SET_VBI_LINE, 5,
+               0xffffffff,0,0,0,0);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to configure cx32416");
+               return ret;
+       }
+
+       ret = cx2341x_update(hdw,pvr2_encoder_cmd,
+                            (hdw->enc_cur_valid ? &hdw->enc_cur_state : 0),
+                            &hdw->enc_ctl_state);
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Error from cx2341x module code=%d",ret);
+               return ret;
+       }
+
+       ret = 0;
+
+       if (!ret) ret = pvr2_encoder_vcmd(
+               hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to initialize cx32416 video input");
+               return ret;
+       }
+
+       hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+       memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
+              sizeof(struct cx2341x_mpeg_params));
+       hdw->enc_cur_valid = !0;
+       return 0;
+}
+
+
+int pvr2_encoder_start(struct pvr2_hdw *hdw)
+{
+       int status;
+
+       /* unmask some interrupts */
+       pvr2_write_register(hdw, 0x0048, 0xbfffffff);
+
+       /* change some GPIO data */
+       pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
+       pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
+
+       if (hdw->config == pvr2_config_vbi) {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+                                          0x01,0x14);
+       } else if (hdw->config == pvr2_config_mpeg) {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+                                          0,0x13);
+       } else {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+                                          0,0x13);
+       }
+       if (!status) {
+               hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+       }
+       return status;
+}
+
+int pvr2_encoder_stop(struct pvr2_hdw *hdw)
+{
+       int status;
+
+       /* mask all interrupts */
+       pvr2_write_register(hdw, 0x0048, 0xffffffff);
+
+       if (hdw->config == pvr2_config_vbi) {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+                                          0x01,0x01,0x14);
+       } else if (hdw->config == pvr2_config_mpeg) {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+                                          0x01,0,0x13);
+       } else {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+                                          0x01,0,0x13);
+       }
+
+       /* change some GPIO data */
+       /* Note: Bit d7 of dir appears to control the LED.  So we shut it
+          off here. */
+       pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
+       pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
+
+       if (!status) {
+               hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
+       }
+       return status;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
new file mode 100644 (file)
index 0000000..01b5a0b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_ENCODER_H
+#define __PVRUSB2_ENCODER_H
+
+struct pvr2_hdw;
+
+int pvr2_encoder_configure(struct pvr2_hdw *);
+int pvr2_encoder_start(struct pvr2_hdw *);
+int pvr2_encoder_stop(struct pvr2_hdw *);
+
+#endif /* __PVRUSB2_ENCODER_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
new file mode 100644 (file)
index 0000000..ba2afbf
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_HDW_INTERNAL_H
+#define __PVRUSB2_HDW_INTERNAL_H
+
+/*
+
+  This header sets up all the internal structures and definitions needed to
+  track and coordinate the driver's interaction with the hardware.  ONLY
+  source files which actually implement part of that whole circus should be
+  including this header.  Higher levels, like the external layers to the
+  various public APIs (V4L, sysfs, etc) should NOT ever include this
+  private, internal header.  This means that pvrusb2-hdw, pvrusb2-encoder,
+  etc will include this, but pvrusb2-v4l should not.
+
+*/
+
+#include <linux/config.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-io.h"
+#include <media/cx2341x.h>
+
+/* Legal values for the SRATE state variable */
+#define PVR2_CVAL_SRATE_48 0
+#define PVR2_CVAL_SRATE_44_1 1
+
+/* Legal values for the AUDIOBITRATE state variable */
+#define PVR2_CVAL_AUDIOBITRATE_384 0
+#define PVR2_CVAL_AUDIOBITRATE_320 1
+#define PVR2_CVAL_AUDIOBITRATE_256 2
+#define PVR2_CVAL_AUDIOBITRATE_224 3
+#define PVR2_CVAL_AUDIOBITRATE_192 4
+#define PVR2_CVAL_AUDIOBITRATE_160 5
+#define PVR2_CVAL_AUDIOBITRATE_128 6
+#define PVR2_CVAL_AUDIOBITRATE_112 7
+#define PVR2_CVAL_AUDIOBITRATE_96 8
+#define PVR2_CVAL_AUDIOBITRATE_80 9
+#define PVR2_CVAL_AUDIOBITRATE_64 10
+#define PVR2_CVAL_AUDIOBITRATE_56 11
+#define PVR2_CVAL_AUDIOBITRATE_48 12
+#define PVR2_CVAL_AUDIOBITRATE_32 13
+#define PVR2_CVAL_AUDIOBITRATE_VBR 14
+
+/* Legal values for the AUDIOEMPHASIS state variable */
+#define PVR2_CVAL_AUDIOEMPHASIS_NONE 0
+#define PVR2_CVAL_AUDIOEMPHASIS_50_15 1
+#define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2
+
+/* Legal values for PVR2_CID_HSM */
+#define PVR2_CVAL_HSM_FAIL 0
+#define PVR2_CVAL_HSM_FULL 1
+#define PVR2_CVAL_HSM_HIGH 2
+
+#define PVR2_VID_ENDPOINT        0x84
+#define PVR2_UNK_ENDPOINT        0x86    /* maybe raw yuv ? */
+#define PVR2_VBI_ENDPOINT        0x88
+
+#define PVR2_CTL_BUFFSIZE        64
+
+#define FREQTABLE_SIZE 500
+
+#define LOCK_TAKE(x) do { mutex_lock(&x##_mutex); x##_held = !0; } while (0)
+#define LOCK_GIVE(x) do { x##_held = 0; mutex_unlock(&x##_mutex); } while (0)
+
+struct pvr2_decoder;
+
+typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
+typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *);
+typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val);
+typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
+                                   char *,unsigned int,unsigned int *);
+typedef int (*pvr2_ctlf_sym_to_val)(struct pvr2_ctrl *,
+                                   const char *,unsigned int,
+                                   int *mskp,int *valp);
+typedef unsigned int (*pvr2_ctlf_get_v4lflags)(struct pvr2_ctrl *);
+
+/* This structure describes a specific control.  A table of these is set up
+   in pvrusb2-hdw.c. */
+struct pvr2_ctl_info {
+       /* Control's name suitable for use as an identifier */
+       const char *name;
+
+       /* Short description of control */
+       const char *desc;
+
+       /* Control's implementation */
+       pvr2_ctlf_get_value get_value;      /* Get its value */
+       pvr2_ctlf_set_value set_value;      /* Set its value */
+       pvr2_ctlf_val_to_sym val_to_sym;    /* Custom convert value->symbol */
+       pvr2_ctlf_sym_to_val sym_to_val;    /* Custom convert symbol->value */
+       pvr2_ctlf_is_dirty is_dirty;        /* Return true if dirty */
+       pvr2_ctlf_clear_dirty clear_dirty;  /* Clear dirty state */
+       pvr2_ctlf_get_v4lflags get_v4lflags;/* Retrieve v4l flags */
+
+       /* Control's type (int, enum, bitmask) */
+       enum pvr2_ctl_type type;
+
+       /* Associated V4L control ID, if any */
+       int v4l_id;
+
+       /* Associated driver internal ID, if any */
+       int internal_id;
+
+       /* Don't implicitly initialize this control's value */
+       int skip_init;
+
+       /* Starting value for this control */
+       int default_value;
+
+       /* Type-specific control information */
+       union {
+               struct { /* Integer control */
+                       long min_value; /* lower limit */
+                       long max_value; /* upper limit */
+               } type_int;
+               struct { /* enumerated control */
+                       unsigned int count;       /* enum value count */
+                       const char **value_names; /* symbol names */
+               } type_enum;
+               struct { /* bitmask control */
+                       unsigned int valid_bits; /* bits in use */
+                       const char **bit_names;  /* symbol name/bit */
+               } type_bitmask;
+       } def;
+};
+
+
+/* Same as pvr2_ctl_info, but includes storage for the control description */
+#define PVR2_CTLD_INFO_DESC_SIZE 32
+struct pvr2_ctld_info {
+       struct pvr2_ctl_info info;
+       char desc[PVR2_CTLD_INFO_DESC_SIZE];
+};
+
+struct pvr2_ctrl {
+       const struct pvr2_ctl_info *info;
+       struct pvr2_hdw *hdw;
+};
+
+
+struct pvr2_audio_stat {
+       void *ctxt;
+       void (*detach)(void *);
+       int (*status)(void *);
+};
+
+struct pvr2_decoder_ctrl {
+       void *ctxt;
+       void (*detach)(void *);
+       void (*enable)(void *,int);
+       int (*tuned)(void *);
+       void (*force_reset)(void *);
+};
+
+#define PVR2_I2C_PEND_DETECT  0x01  /* Need to detect a client type */
+#define PVR2_I2C_PEND_CLIENT  0x02  /* Client needs a specific update */
+#define PVR2_I2C_PEND_REFRESH 0x04  /* Client has specific pending bits */
+#define PVR2_I2C_PEND_STALE   0x08  /* Broadcast pending bits */
+
+#define PVR2_I2C_PEND_ALL (PVR2_I2C_PEND_DETECT |\
+                          PVR2_I2C_PEND_CLIENT |\
+                          PVR2_I2C_PEND_REFRESH |\
+                          PVR2_I2C_PEND_STALE)
+
+/* Disposition of firmware1 loading situation */
+#define FW1_STATE_UNKNOWN 0
+#define FW1_STATE_MISSING 1
+#define FW1_STATE_FAILED 2
+#define FW1_STATE_RELOAD 3
+#define FW1_STATE_OK 4
+
+/* Known major hardware variants, keyed from device ID */
+#define PVR2_HDW_TYPE_29XXX 0
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+#define PVR2_HDW_TYPE_24XXX 1
+#endif
+
+typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
+#define PVR2_I2C_FUNC_CNT 128
+
+/* This structure contains all state data directly needed to
+   manipulate the hardware (as opposed to complying with a kernel
+   interface) */
+struct pvr2_hdw {
+       /* Underlying USB device handle */
+       struct usb_device *usb_dev;
+       struct usb_interface *usb_intf;
+
+       /* Device type, one of PVR2_HDW_TYPE_xxxxx */
+       unsigned int hdw_type;
+
+       /* Video spigot */
+       struct pvr2_stream *vid_stream;
+
+       /* Mutex for all hardware state control */
+       struct mutex big_lock_mutex;
+       int big_lock_held;  /* For debugging */
+
+       void (*poll_trigger_func)(void *);
+       void *poll_trigger_data;
+
+       char name[32];
+
+       /* I2C stuff */
+       struct i2c_adapter i2c_adap;
+       struct i2c_algorithm i2c_algo;
+       pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT];
+       int i2c_cx25840_hack_state;
+       int i2c_linked;
+       unsigned int i2c_pend_types;    /* Which types of update are needed */
+       unsigned long i2c_pend_mask;    /* Change bits we need to scan */
+       unsigned long i2c_stale_mask;   /* Pending broadcast change bits */
+       unsigned long i2c_active_mask;  /* All change bits currently in use */
+       struct list_head i2c_clients;
+       struct mutex i2c_list_lock;
+
+       /* Frequency table */
+       unsigned int freqTable[FREQTABLE_SIZE];
+       unsigned int freqProgSlot;
+       unsigned int freqSlot;
+
+       /* Stuff for handling low level control interaction with device */
+       struct mutex ctl_lock_mutex;
+       int ctl_lock_held;  /* For debugging */
+       struct urb *ctl_write_urb;
+       struct urb *ctl_read_urb;
+       unsigned char *ctl_write_buffer;
+       unsigned char *ctl_read_buffer;
+       volatile int ctl_write_pend_flag;
+       volatile int ctl_read_pend_flag;
+       volatile int ctl_timeout_flag;
+       struct completion ctl_done;
+       unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE];
+       int cmd_debug_state;               // Low level command debugging info
+       unsigned char cmd_debug_code;      //
+       unsigned int cmd_debug_write_len;  //
+       unsigned int cmd_debug_read_len;   //
+
+       int flag_ok;            // device in known good state
+       int flag_disconnected;  // flag_ok == 0 due to disconnect
+       int flag_init_ok;       // true if structure is fully initialized
+       int flag_streaming_enabled; // true if streaming should be on
+       int fw1_state;          // current situation with fw1
+
+       int flag_decoder_is_tuned;
+
+       struct pvr2_decoder_ctrl *decoder_ctrl;
+
+       // CPU firmware info (used to help find / save firmware data)
+       char *fw_buffer;
+       unsigned int fw_size;
+
+       // Which subsystem pieces have been enabled / configured
+       unsigned long subsys_enabled_mask;
+
+       // Which subsystems are manipulated to enable streaming
+       unsigned long subsys_stream_mask;
+
+       // True if there is a request to trigger logging of state in each
+       // module.
+       int log_requested;
+
+       /* Tuner / frequency control stuff */
+       unsigned int tuner_type;
+       int tuner_updated;
+       unsigned int freqVal;
+       int freqDirty;
+
+       /* Video standard handling */
+       v4l2_std_id std_mask_eeprom; // Hardware supported selections
+       v4l2_std_id std_mask_avail;  // Which standards we may select from
+       v4l2_std_id std_mask_cur;    // Currently selected standard(s)
+       unsigned int std_enum_cnt;   // # of enumerated standards
+       int std_enum_cur;            // selected standard enumeration value
+       int std_dirty;               // True if std_mask_cur has changed
+       struct pvr2_ctl_info std_info_enum;
+       struct pvr2_ctl_info std_info_avail;
+       struct pvr2_ctl_info std_info_cur;
+       struct v4l2_standard *std_defs;
+       const char **std_enum_names;
+
+       // Generated string names, one per actual V4L2 standard
+       const char *std_mask_ptrs[32];
+       char std_mask_names[32][10];
+
+       int unit_number;             /* ID for driver instance */
+       unsigned long serial_number; /* ID for hardware itself */
+
+       /* Minor number used by v4l logic (yes, this is a hack, as there should
+          be no v4l junk here).  Probably a better way to do this. */
+       int v4l_minor_number;
+
+       /* Location of eeprom or a negative number if none */
+       int eeprom_addr;
+
+       enum pvr2_config config;
+
+       /* Information about what audio signal we're hearing */
+       int flag_stereo;
+       int flag_bilingual;
+       struct pvr2_audio_stat *audio_stat;
+
+       /* Control state needed for cx2341x module */
+       struct cx2341x_mpeg_params enc_cur_state;
+       struct cx2341x_mpeg_params enc_ctl_state;
+       /* True if an encoder attribute has changed */
+       int enc_stale;
+       /* True if enc_cur_state is valid */
+       int enc_cur_valid;
+
+       /* Control state */
+#define VCREATE_DATA(lab) int lab##_val; int lab##_dirty
+       VCREATE_DATA(brightness);
+       VCREATE_DATA(contrast);
+       VCREATE_DATA(saturation);
+       VCREATE_DATA(hue);
+       VCREATE_DATA(volume);
+       VCREATE_DATA(balance);
+       VCREATE_DATA(bass);
+       VCREATE_DATA(treble);
+       VCREATE_DATA(mute);
+       VCREATE_DATA(input);
+       VCREATE_DATA(audiomode);
+       VCREATE_DATA(res_hor);
+       VCREATE_DATA(res_ver);
+       VCREATE_DATA(srate);
+#undef VCREATE_DATA
+
+       struct pvr2_ctld_info *mpeg_ctrl_info;
+
+       struct pvr2_ctrl *controls;
+       unsigned int control_cnt;
+};
+
+int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
+
+unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *);
+
+void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+                                    unsigned long msk,unsigned long val);
+void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+                                           unsigned long msk,
+                                           unsigned long val);
+
+void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
+void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
+
+int pvr2_i2c_basic_op(struct pvr2_hdw *,u8 i2c_addr,
+                     u8 *wdata,u16 wlen,
+                     u8 *rdata,u16 rlen);
+
+#endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
new file mode 100644 (file)
index 0000000..643c471
--- /dev/null
@@ -0,0 +1,3120 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/videodev2.h>
+#include <asm/semaphore.h>
+#include "pvrusb2.h"
+#include "pvrusb2-std.h"
+#include "pvrusb2-util.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-eeprom.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-encoder.h"
+#include "pvrusb2-debug.h"
+
+struct usb_device_id pvr2_device_table[] = {
+       [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
+#endif
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, pvr2_device_table);
+
+static const char *pvr2_device_names[] = {
+       [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
+#endif
+};
+
+struct pvr2_string_table {
+       const char **lst;
+       unsigned int cnt;
+};
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+// Names of other client modules to request for 24xxx model hardware
+static const char *pvr2_client_24xxx[] = {
+       "cx25840",
+       "tuner",
+       "tda9887",
+       "wm8775",
+};
+#endif
+
+// Names of other client modules to request for 29xxx model hardware
+static const char *pvr2_client_29xxx[] = {
+       "msp3400",
+       "saa7115",
+       "tuner",
+       "tda9887",
+};
+
+static struct pvr2_string_table pvr2_client_lists[] = {
+       [PVR2_HDW_TYPE_29XXX] = {
+               pvr2_client_29xxx,
+               sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+       },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       [PVR2_HDW_TYPE_24XXX] = {
+               pvr2_client_24xxx,
+               sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+       },
+#endif
+};
+
+static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = 0};
+DECLARE_MUTEX(pvr2_unit_sem);
+
+static int ctlchg = 0;
+static int initusbreset = 1;
+static int procreload = 0;
+static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
+static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
+static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
+static int init_pause_msec = 0;
+
+module_param(ctlchg, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
+module_param(init_pause_msec, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay");
+module_param(initusbreset, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe");
+module_param(procreload, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(procreload,
+                "Attempt init failure recovery with firmware reload");
+module_param_array(tuner,    int, NULL, 0444);
+MODULE_PARM_DESC(tuner,"specify installed tuner type");
+module_param_array(video_std,    int, NULL, 0444);
+MODULE_PARM_DESC(video_std,"specify initial video standard");
+module_param_array(tolerance,    int, NULL, 0444);
+MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
+
+#define PVR2_CTL_WRITE_ENDPOINT  0x01
+#define PVR2_CTL_READ_ENDPOINT   0x81
+
+#define PVR2_GPIO_IN 0x9008
+#define PVR2_GPIO_OUT 0x900c
+#define PVR2_GPIO_DIR 0x9020
+
+#define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__)
+
+#define PVR2_FIRMWARE_ENDPOINT   0x02
+
+/* size of a firmware chunk */
+#define FIRMWARE_CHUNK_SIZE 0x2000
+
+/* Define the list of additional controls we'll dynamically construct based
+   on query of the cx2341x module. */
+struct pvr2_mpeg_ids {
+       const char *strid;
+       int id;
+};
+static const struct pvr2_mpeg_ids mpeg_ids[] = {
+       {
+               .strid = "audio_layer",
+               .id = V4L2_CID_MPEG_AUDIO_ENCODING,
+       },{
+               .strid = "audio_bitrate",
+               .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+       },{
+               /* Already using audio_mode elsewhere :-( */
+               .strid = "mpeg_audio_mode",
+               .id = V4L2_CID_MPEG_AUDIO_MODE,
+       },{
+               .strid = "mpeg_audio_mode_extension",
+               .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+       },{
+               .strid = "audio_emphasis",
+               .id = V4L2_CID_MPEG_AUDIO_EMPHASIS,
+       },{
+               .strid = "audio_crc",
+               .id = V4L2_CID_MPEG_AUDIO_CRC,
+       },{
+               .strid = "video_aspect",
+               .id = V4L2_CID_MPEG_VIDEO_ASPECT,
+       },{
+               .strid = "video_b_frames",
+               .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+       },{
+               .strid = "video_gop_size",
+               .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+       },{
+               .strid = "video_gop_closure",
+               .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+       },{
+               .strid = "video_pulldown",
+               .id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
+       },{
+               .strid = "video_bitrate_mode",
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+       },{
+               .strid = "video_bitrate",
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+       },{
+               .strid = "video_bitrate_peak",
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+       },{
+               .strid = "video_temporal_decimation",
+               .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+       },{
+               .strid = "stream_type",
+               .id = V4L2_CID_MPEG_STREAM_TYPE,
+       },{
+               .strid = "video_spatial_filter_mode",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+       },{
+               .strid = "video_spatial_filter",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+       },{
+               .strid = "video_luma_spatial_filter_type",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+       },{
+               .strid = "video_chroma_spatial_filter_type",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+       },{
+               .strid = "video_temporal_filter_mode",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+       },{
+               .strid = "video_temporal_filter",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+       },{
+               .strid = "video_median_filter_type",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+       },{
+               .strid = "video_luma_median_filter_top",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+       },{
+               .strid = "video_luma_median_filter_bottom",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+       },{
+               .strid = "video_chroma_median_filter_top",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+       },{
+               .strid = "video_chroma_median_filter_bottom",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+       }
+};
+#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+
+static const char *control_values_srate[] = {
+       [PVR2_CVAL_SRATE_48]   = "48KHz",
+       [PVR2_CVAL_SRATE_44_1] = "44.1KHz",
+};
+
+
+
+
+static const char *control_values_input[] = {
+       [PVR2_CVAL_INPUT_TV]        = "television",  /*xawtv needs this name*/
+       [PVR2_CVAL_INPUT_RADIO]     = "radio",
+       [PVR2_CVAL_INPUT_SVIDEO]    = "s-video",
+       [PVR2_CVAL_INPUT_COMPOSITE] = "composite",
+};
+
+
+static const char *control_values_audiomode[] = {
+       [V4L2_TUNER_MODE_MONO]   = "Mono",
+       [V4L2_TUNER_MODE_STEREO] = "Stereo",
+       [V4L2_TUNER_MODE_LANG1]  = "Lang1",
+       [V4L2_TUNER_MODE_LANG2]  = "Lang2",
+       [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2",
+};
+
+
+static const char *control_values_hsm[] = {
+       [PVR2_CVAL_HSM_FAIL] = "Fail",
+       [PVR2_CVAL_HSM_HIGH] = "High",
+       [PVR2_CVAL_HSM_FULL] = "Full",
+};
+
+
+static const char *control_values_subsystem[] = {
+       [PVR2_SUBSYS_B_ENC_FIRMWARE]  = "enc_firmware",
+       [PVR2_SUBSYS_B_ENC_CFG] = "enc_config",
+       [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",
+       [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",
+       [PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
+};
+
+
+static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
+               *vp = hdw->freqTable[hdw->freqProgSlot-1];
+       } else {
+               *vp = 0;
+       }
+       return 0;
+}
+
+static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
+               hdw->freqTable[hdw->freqProgSlot-1] = v;
+       }
+       return 0;
+}
+
+static int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->freqProgSlot;
+       return 0;
+}
+
+static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if ((v >= 0) && (v <= FREQTABLE_SIZE)) {
+               hdw->freqProgSlot = v;
+       }
+       return 0;
+}
+
+static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->freqSlot;
+       return 0;
+}
+
+static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       unsigned freq = 0;
+       struct pvr2_hdw *hdw = cptr->hdw;
+       hdw->freqSlot = v;
+       if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) {
+               freq = hdw->freqTable[hdw->freqSlot-1];
+       }
+       if (freq && (freq != hdw->freqVal)) {
+               hdw->freqVal = freq;
+               hdw->freqDirty = !0;
+       }
+       return 0;
+}
+
+static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->freqVal;
+       return 0;
+}
+
+static int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->freqDirty != 0;
+}
+
+static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->freqDirty = 0;
+}
+
+static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       hdw->freqVal = v;
+       hdw->freqDirty = !0;
+       hdw->freqSlot = 0;
+       return 0;
+}
+
+static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->enc_stale != 0;
+}
+
+static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->enc_stale = 0;
+}
+
+static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       int ret;
+       struct v4l2_ext_controls cs;
+       struct v4l2_ext_control c1;
+       memset(&cs,0,sizeof(cs));
+       memset(&c1,0,sizeof(c1));
+       cs.controls = &c1;
+       cs.count = 1;
+       c1.id = cptr->info->v4l_id;
+       ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+                               VIDIOC_G_EXT_CTRLS);
+       if (ret) return ret;
+       *vp = c1.value;
+       return 0;
+}
+
+static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       int ret;
+       struct v4l2_ext_controls cs;
+       struct v4l2_ext_control c1;
+       memset(&cs,0,sizeof(cs));
+       memset(&c1,0,sizeof(c1));
+       cs.controls = &c1;
+       cs.count = 1;
+       c1.id = cptr->info->v4l_id;
+       c1.value = v;
+       ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+                               VIDIOC_S_EXT_CTRLS);
+       if (ret) return ret;
+       cptr->hdw->enc_stale = !0;
+       return 0;
+}
+
+static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
+{
+       struct v4l2_queryctrl qctrl;
+       struct pvr2_ctl_info *info;
+       qctrl.id = cptr->info->v4l_id;
+       cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl);
+       /* Strip out the const so we can adjust a function pointer.  It's
+          OK to do this here because we know this is a dynamically created
+          control, so the underlying storage for the info pointer is (a)
+          private to us, and (b) not in read-only storage.  Either we do
+          this or we significantly complicate the underlying control
+          implementation. */
+       info = (struct pvr2_ctl_info *)(cptr->info);
+       if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
+               if (info->set_value) {
+                       info->set_value = 0;
+               }
+       } else {
+               if (!(info->set_value)) {
+                       info->set_value = ctrl_cx2341x_set;
+               }
+       }
+       return qctrl.flags;
+}
+
+static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->flag_streaming_enabled;
+       return 0;
+}
+
+static int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       int result = pvr2_hdw_is_hsm(cptr->hdw);
+       *vp = PVR2_CVAL_HSM_FULL;
+       if (result < 0) *vp = PVR2_CVAL_HSM_FAIL;
+       if (result) *vp = PVR2_CVAL_HSM_HIGH;
+       return 0;
+}
+
+static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->std_mask_avail;
+       return 0;
+}
+
+static int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       v4l2_std_id ns;
+       ns = hdw->std_mask_avail;
+       ns = (ns & ~m) | (v & m);
+       if (ns == hdw->std_mask_avail) return 0;
+       hdw->std_mask_avail = ns;
+       pvr2_hdw_internal_set_std_avail(hdw);
+       pvr2_hdw_internal_find_stdenum(hdw);
+       return 0;
+}
+
+static int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val,
+                              char *bufPtr,unsigned int bufSize,
+                              unsigned int *len)
+{
+       *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val);
+       return 0;
+}
+
+static int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr,
+                              const char *bufPtr,unsigned int bufSize,
+                              int *mskp,int *valp)
+{
+       int ret;
+       v4l2_std_id id;
+       ret = pvr2_std_str_to_id(&id,bufPtr,bufSize);
+       if (ret < 0) return ret;
+       if (mskp) *mskp = id;
+       if (valp) *valp = id;
+       return 0;
+}
+
+static int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->std_mask_cur;
+       return 0;
+}
+
+static int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       v4l2_std_id ns;
+       ns = hdw->std_mask_cur;
+       ns = (ns & ~m) | (v & m);
+       if (ns == hdw->std_mask_cur) return 0;
+       hdw->std_mask_cur = ns;
+       hdw->std_dirty = !0;
+       pvr2_hdw_internal_find_stdenum(hdw);
+       return 0;
+}
+
+static int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->std_dirty != 0;
+}
+
+static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->std_dirty = 0;
+}
+
+static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
+               PVR2_SIGNAL_OK) ? 1 : 0);
+       return 0;
+}
+
+static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->subsys_enabled_mask;
+       return 0;
+}
+
+static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v);
+       return 0;
+}
+
+static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->subsys_stream_mask;
+       return 0;
+}
+
+static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v);
+       return 0;
+}
+
+static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if (v < 0) return -EINVAL;
+       if (v > hdw->std_enum_cnt) return -EINVAL;
+       hdw->std_enum_cur = v;
+       if (!v) return 0;
+       v--;
+       if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0;
+       hdw->std_mask_cur = hdw->std_defs[v].id;
+       hdw->std_dirty = !0;
+       return 0;
+}
+
+
+static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->std_enum_cur;
+       return 0;
+}
+
+
+static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->std_dirty != 0;
+}
+
+
+static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->std_dirty = 0;
+}
+
+
+#define DEFINT(vmin,vmax) \
+       .type = pvr2_ctl_int, \
+       .def.type_int.min_value = vmin, \
+       .def.type_int.max_value = vmax
+
+#define DEFENUM(tab) \
+       .type = pvr2_ctl_enum, \
+       .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+       .def.type_enum.value_names = tab
+
+#define DEFBOOL \
+       .type = pvr2_ctl_bool
+
+#define DEFMASK(msk,tab) \
+       .type = pvr2_ctl_bitmask, \
+       .def.type_bitmask.valid_bits = msk, \
+       .def.type_bitmask.bit_names = tab
+
+#define DEFREF(vname) \
+       .set_value = ctrl_set_##vname, \
+       .get_value = ctrl_get_##vname, \
+       .is_dirty = ctrl_isdirty_##vname, \
+       .clear_dirty = ctrl_cleardirty_##vname
+
+
+#define VCREATE_FUNCS(vname) \
+static int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \
+{*vp = cptr->hdw->vname##_val; return 0;} \
+static int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \
+{cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \
+static int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \
+{return cptr->hdw->vname##_dirty != 0;} \
+static void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \
+{cptr->hdw->vname##_dirty = 0;}
+
+VCREATE_FUNCS(brightness)
+VCREATE_FUNCS(contrast)
+VCREATE_FUNCS(saturation)
+VCREATE_FUNCS(hue)
+VCREATE_FUNCS(volume)
+VCREATE_FUNCS(balance)
+VCREATE_FUNCS(bass)
+VCREATE_FUNCS(treble)
+VCREATE_FUNCS(mute)
+VCREATE_FUNCS(input)
+VCREATE_FUNCS(audiomode)
+VCREATE_FUNCS(res_hor)
+VCREATE_FUNCS(res_ver)
+VCREATE_FUNCS(srate)
+
+#define MIN_FREQ 55250000L
+#define MAX_FREQ 850000000L
+
+/* Table definition of all controls which can be manipulated */
+static const struct pvr2_ctl_info control_defs[] = {
+       {
+               .v4l_id = V4L2_CID_BRIGHTNESS,
+               .desc = "Brightness",
+               .name = "brightness",
+               .default_value = 128,
+               DEFREF(brightness),
+               DEFINT(0,255),
+       },{
+               .v4l_id = V4L2_CID_CONTRAST,
+               .desc = "Contrast",
+               .name = "contrast",
+               .default_value = 68,
+               DEFREF(contrast),
+               DEFINT(0,127),
+       },{
+               .v4l_id = V4L2_CID_SATURATION,
+               .desc = "Saturation",
+               .name = "saturation",
+               .default_value = 64,
+               DEFREF(saturation),
+               DEFINT(0,127),
+       },{
+               .v4l_id = V4L2_CID_HUE,
+               .desc = "Hue",
+               .name = "hue",
+               .default_value = 0,
+               DEFREF(hue),
+               DEFINT(-128,127),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_VOLUME,
+               .desc = "Volume",
+               .name = "volume",
+               .default_value = 65535,
+               DEFREF(volume),
+               DEFINT(0,65535),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_BALANCE,
+               .desc = "Balance",
+               .name = "balance",
+               .default_value = 0,
+               DEFREF(balance),
+               DEFINT(-32768,32767),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_BASS,
+               .desc = "Bass",
+               .name = "bass",
+               .default_value = 0,
+               DEFREF(bass),
+               DEFINT(-32768,32767),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_TREBLE,
+               .desc = "Treble",
+               .name = "treble",
+               .default_value = 0,
+               DEFREF(treble),
+               DEFINT(-32768,32767),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_MUTE,
+               .desc = "Mute",
+               .name = "mute",
+               .default_value = 0,
+               DEFREF(mute),
+               DEFBOOL,
+       },{
+               .desc = "Video Source",
+               .name = "input",
+               .internal_id = PVR2_CID_INPUT,
+               .default_value = PVR2_CVAL_INPUT_TV,
+               DEFREF(input),
+               DEFENUM(control_values_input),
+       },{
+               .desc = "Audio Mode",
+               .name = "audio_mode",
+               .internal_id = PVR2_CID_AUDIOMODE,
+               .default_value = V4L2_TUNER_MODE_STEREO,
+               DEFREF(audiomode),
+               DEFENUM(control_values_audiomode),
+       },{
+               .desc = "Horizontal capture resolution",
+               .name = "resolution_hor",
+               .internal_id = PVR2_CID_HRES,
+               .default_value = 720,
+               DEFREF(res_hor),
+               DEFINT(320,720),
+       },{
+               .desc = "Vertical capture resolution",
+               .name = "resolution_ver",
+               .internal_id = PVR2_CID_VRES,
+               .default_value = 480,
+               DEFREF(res_ver),
+               DEFINT(200,625),
+       },{
+               .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+               .desc = "Sample rate",
+               .name = "srate",
+               .default_value = PVR2_CVAL_SRATE_48,
+               DEFREF(srate),
+               DEFENUM(control_values_srate),
+       },{
+               .desc = "Tuner Frequency (Hz)",
+               .name = "frequency",
+               .internal_id = PVR2_CID_FREQUENCY,
+               .default_value = 175250000L,
+               .set_value = ctrl_freq_set,
+               .get_value = ctrl_freq_get,
+               .is_dirty = ctrl_freq_is_dirty,
+               .clear_dirty = ctrl_freq_clear_dirty,
+               DEFINT(MIN_FREQ,MAX_FREQ),
+       },{
+               .desc = "Channel",
+               .name = "channel",
+               .set_value = ctrl_channel_set,
+               .get_value = ctrl_channel_get,
+               DEFINT(0,FREQTABLE_SIZE),
+       },{
+               .desc = "Channel Program Frequency",
+               .name = "freq_table_value",
+               .set_value = ctrl_channelfreq_set,
+               .get_value = ctrl_channelfreq_get,
+               DEFINT(MIN_FREQ,MAX_FREQ),
+       },{
+               .desc = "Channel Program ID",
+               .name = "freq_table_channel",
+               .set_value = ctrl_channelprog_set,
+               .get_value = ctrl_channelprog_get,
+               DEFINT(0,FREQTABLE_SIZE),
+       },{
+               .desc = "Streaming Enabled",
+               .name = "streaming_enabled",
+               .get_value = ctrl_streamingenabled_get,
+               DEFBOOL,
+       },{
+               .desc = "USB Speed",
+               .name = "usb_speed",
+               .get_value = ctrl_hsm_get,
+               DEFENUM(control_values_hsm),
+       },{
+               .desc = "Signal Present",
+               .name = "signal_present",
+               .get_value = ctrl_signal_get,
+               DEFBOOL,
+       },{
+               .desc = "Video Standards Available Mask",
+               .name = "video_standard_mask_available",
+               .internal_id = PVR2_CID_STDAVAIL,
+               .skip_init = !0,
+               .get_value = ctrl_stdavail_get,
+               .set_value = ctrl_stdavail_set,
+               .val_to_sym = ctrl_std_val_to_sym,
+               .sym_to_val = ctrl_std_sym_to_val,
+               .type = pvr2_ctl_bitmask,
+       },{
+               .desc = "Video Standards In Use Mask",
+               .name = "video_standard_mask_active",
+               .internal_id = PVR2_CID_STDCUR,
+               .skip_init = !0,
+               .get_value = ctrl_stdcur_get,
+               .set_value = ctrl_stdcur_set,
+               .is_dirty = ctrl_stdcur_is_dirty,
+               .clear_dirty = ctrl_stdcur_clear_dirty,
+               .val_to_sym = ctrl_std_val_to_sym,
+               .sym_to_val = ctrl_std_sym_to_val,
+               .type = pvr2_ctl_bitmask,
+       },{
+               .desc = "Subsystem enabled mask",
+               .name = "debug_subsys_mask",
+               .skip_init = !0,
+               .get_value = ctrl_subsys_get,
+               .set_value = ctrl_subsys_set,
+               DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+       },{
+               .desc = "Subsystem stream mask",
+               .name = "debug_subsys_stream_mask",
+               .skip_init = !0,
+               .get_value = ctrl_subsys_stream_get,
+               .set_value = ctrl_subsys_stream_set,
+               DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+       },{
+               .desc = "Video Standard Name",
+               .name = "video_standard",
+               .internal_id = PVR2_CID_STDENUM,
+               .skip_init = !0,
+               .get_value = ctrl_stdenumcur_get,
+               .set_value = ctrl_stdenumcur_set,
+               .is_dirty = ctrl_stdenumcur_is_dirty,
+               .clear_dirty = ctrl_stdenumcur_clear_dirty,
+               .type = pvr2_ctl_enum,
+       }
+};
+
+#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+
+
+const char *pvr2_config_get_name(enum pvr2_config cfg)
+{
+       switch (cfg) {
+       case pvr2_config_empty: return "empty";
+       case pvr2_config_mpeg: return "mpeg";
+       case pvr2_config_vbi: return "vbi";
+       case pvr2_config_radio: return "radio";
+       }
+       return "<unknown>";
+}
+
+
+struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw)
+{
+       return hdw->usb_dev;
+}
+
+
+unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
+{
+       return hdw->serial_number;
+}
+
+
+struct pvr2_hdw *pvr2_hdw_find(int unit_number)
+{
+       if (unit_number < 0) return 0;
+       if (unit_number >= PVR_NUM) return 0;
+       return unit_pointers[unit_number];
+}
+
+
+int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
+{
+       return hdw->unit_number;
+}
+
+
+/* Attempt to locate one of the given set of files.  Messages are logged
+   appropriate to what has been found.  The return value will be 0 or
+   greater on success (it will be the index of the file name found) and
+   fw_entry will be filled in.  Otherwise a negative error is returned on
+   failure.  If the return value is -ENOENT then no viable firmware file
+   could be located. */
+static int pvr2_locate_firmware(struct pvr2_hdw *hdw,
+                               const struct firmware **fw_entry,
+                               const char *fwtypename,
+                               unsigned int fwcount,
+                               const char *fwnames[])
+{
+       unsigned int idx;
+       int ret = -EINVAL;
+       for (idx = 0; idx < fwcount; idx++) {
+               ret = request_firmware(fw_entry,
+                                      fwnames[idx],
+                                      &hdw->usb_dev->dev);
+               if (!ret) {
+                       trace_firmware("Located %s firmware: %s;"
+                                      " uploading...",
+                                      fwtypename,
+                                      fwnames[idx]);
+                       return idx;
+               }
+               if (ret == -ENOENT) continue;
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "request_firmware fatal error with code=%d",ret);
+               return ret;
+       }
+       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                  "***WARNING***"
+                  " Device %s firmware"
+                  " seems to be missing.",
+                  fwtypename);
+       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                  "Did you install the pvrusb2 firmware files"
+                  " in their proper location?");
+       if (fwcount == 1) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "request_firmware unable to locate %s file %s",
+                          fwtypename,fwnames[0]);
+       } else {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "request_firmware unable to locate"
+                          " one of the following %s files:",
+                          fwtypename);
+               for (idx = 0; idx < fwcount; idx++) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "request_firmware: Failed to find %s",
+                                  fwnames[idx]);
+               }
+       }
+       return ret;
+}
+
+
+/*
+ * pvr2_upload_firmware1().
+ *
+ * Send the 8051 firmware to the device.  After the upload, arrange for
+ * device to re-enumerate.
+ *
+ * NOTE : the pointer to the firmware data given by request_firmware()
+ * is not suitable for an usb transaction.
+ *
+ */
+int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
+{
+       const struct firmware *fw_entry = 0;
+       void  *fw_ptr;
+       unsigned int pipe;
+       int ret;
+       u16 address;
+       static const char *fw_files_29xxx[] = {
+               "v4l-pvrusb2-29xxx-01.fw",
+       };
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       static const char *fw_files_24xxx[] = {
+               "v4l-pvrusb2-24xxx-01.fw",
+       };
+#endif
+       static const struct pvr2_string_table fw_file_defs[] = {
+               [PVR2_HDW_TYPE_29XXX] = {
+                       fw_files_29xxx,
+                       sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+               },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+               [PVR2_HDW_TYPE_24XXX] = {
+                       fw_files_24xxx,
+                       sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+               },
+#endif
+       };
+       hdw->fw1_state = FW1_STATE_FAILED; // default result
+
+       trace_firmware("pvr2_upload_firmware1");
+
+       ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller",
+                                  fw_file_defs[hdw->hdw_type].cnt,
+                                  fw_file_defs[hdw->hdw_type].lst);
+       if (ret < 0) {
+               if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING;
+               return ret;
+       }
+
+       usb_settoggle(hdw->usb_dev, 0 & 0xf, !(0 & USB_DIR_IN), 0);
+       usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f));
+
+       pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
+
+       if (fw_entry->size != 0x2000){
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,"wrong fx2 firmware size");
+               release_firmware(fw_entry);
+               return -ENOMEM;
+       }
+
+       fw_ptr = kmalloc(0x800, GFP_KERNEL);
+       if (fw_ptr == NULL){
+               release_firmware(fw_entry);
+               return -ENOMEM;
+       }
+
+       /* We have to hold the CPU during firmware upload. */
+       pvr2_hdw_cpureset_assert(hdw,1);
+
+       /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes
+          chunk. */
+
+       ret = 0;
+       for(address = 0; address < fw_entry->size; address += 0x800) {
+               memcpy(fw_ptr, fw_entry->data + address, 0x800);
+               ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address,
+                                      0, fw_ptr, 0x800, HZ);
+       }
+
+       trace_firmware("Upload done, releasing device's CPU");
+
+       /* Now release the CPU.  It will disconnect and reconnect later. */
+       pvr2_hdw_cpureset_assert(hdw,0);
+
+       kfree(fw_ptr);
+       release_firmware(fw_entry);
+
+       trace_firmware("Upload done (%d bytes sent)",ret);
+
+       /* We should have written 8192 bytes */
+       if (ret == 8192) {
+               hdw->fw1_state = FW1_STATE_RELOAD;
+               return 0;
+       }
+
+       return -EIO;
+}
+
+
+/*
+ * pvr2_upload_firmware2()
+ *
+ * This uploads encoder firmware on endpoint 2.
+ *
+ */
+
+int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
+{
+       const struct firmware *fw_entry = 0;
+       void  *fw_ptr;
+       unsigned int pipe, fw_len, fw_done;
+       int actual_length;
+       int ret = 0;
+       int fwidx;
+       static const char *fw_files[] = {
+               CX2341X_FIRM_ENC_FILENAME,
+       };
+
+       trace_firmware("pvr2_upload_firmware2");
+
+       ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
+                                  sizeof(fw_files)/sizeof(fw_files[0]),
+                                  fw_files);
+       if (ret < 0) return ret;
+       fwidx = ret;
+       ret = 0;
+       /* Since we're about to completely reinitialize the encoder,
+          invalidate our cached copy of its configuration state.  Next
+          time we configure the encoder, then we'll fully configure it. */
+       hdw->enc_cur_valid = 0;
+
+       /* First prepare firmware loading */
+       ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
+       ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
+       ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
+       ret |= pvr2_hdw_cmd_deep_reset(hdw);
+       ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/
+       ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/
+       ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
+       ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/
+       ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/
+       ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/
+       ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/
+       ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/
+       ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/
+       ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
+       ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
+       ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
+       ret |= pvr2_write_u8(hdw, 0x52, 0);
+       ret |= pvr2_write_u16(hdw, 0x0600, 0);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "firmware2 upload prep failed, ret=%d",ret);
+               release_firmware(fw_entry);
+               return ret;
+       }
+
+       /* Now send firmware */
+
+       fw_len = fw_entry->size;
+
+       if (fw_len % FIRMWARE_CHUNK_SIZE) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "size of %s firmware"
+                          " must be a multiple of 8192B",
+                          fw_files[fwidx]);
+               release_firmware(fw_entry);
+               return -1;
+       }
+
+       fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
+       if (fw_ptr == NULL){
+               release_firmware(fw_entry);
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "failed to allocate memory for firmware2 upload");
+               return -ENOMEM;
+       }
+
+       pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
+
+       for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
+            fw_done += FIRMWARE_CHUNK_SIZE ) {
+               int i;
+               memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
+               /* Usbsnoop log  shows that we must swap bytes... */
+               for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
+                       ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
+
+               ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
+                                   FIRMWARE_CHUNK_SIZE,
+                                   &actual_length, HZ);
+               ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
+       }
+
+       trace_firmware("upload of %s : %i / %i ",
+                      fw_files[fwidx],fw_done,fw_len);
+
+       kfree(fw_ptr);
+       release_firmware(fw_entry);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "firmware2 upload transfer failure");
+               return ret;
+       }
+
+       /* Finish upload */
+
+       ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
+       ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
+       ret |= pvr2_write_u16(hdw, 0x0600, 0);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "firmware2 upload post-proc failure");
+       } else {
+               hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
+       }
+       return ret;
+}
+
+
+#define FIRMWARE_RECOVERY_BITS \
+       ((1<<PVR2_SUBSYS_B_ENC_CFG) | \
+        (1<<PVR2_SUBSYS_B_ENC_RUN) | \
+        (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+        (1<<PVR2_SUBSYS_B_USBSTREAM_RUN))
+
+/*
+
+  This single function is key to pretty much everything.  The pvrusb2
+  device can logically be viewed as a series of subsystems which can be
+  stopped / started or unconfigured / configured.  To get things streaming,
+  one must configure everything and start everything, but there may be
+  various reasons over time to deconfigure something or stop something.
+  This function handles all of this activity.  Everything EVERYWHERE that
+  must affect a subsystem eventually comes here to do the work.
+
+  The current state of all subsystems is represented by a single bit mask,
+  known as subsys_enabled_mask.  The bit positions are defined by the
+  PVR2_SUBSYS_xxxx macros, with one subsystem per bit position.  At any
+  time the set of configured or active subsystems can be queried just by
+  looking at that mask.  To change bits in that mask, this function here
+  must be called.  The "msk" argument indicates which bit positions to
+  change, and the "val" argument defines the new values for the positions
+  defined by "msk".
+
+  There is a priority ordering of starting / stopping things, and for
+  multiple requested changes, this function implements that ordering.
+  (Thus we will act on a request to load encoder firmware before we
+  configure the encoder.)  In addition to priority ordering, there is a
+  recovery strategy implemented here.  If a particular step fails and we
+  detect that failure, this function will clear the affected subsystem bits
+  and restart.  Thus we have a means for recovering from a dead encoder:
+  Clear all bits that correspond to subsystems that we need to restart /
+  reconfigure and start over.
+
+*/
+void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+                                    unsigned long msk,unsigned long val)
+{
+       unsigned long nmsk;
+       unsigned long vmsk;
+       int ret;
+       unsigned int tryCount = 0;
+
+       if (!hdw->flag_ok) return;
+
+       msk &= PVR2_SUBSYS_ALL;
+       nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk);
+       nmsk &= PVR2_SUBSYS_ALL;
+
+       for (;;) {
+               tryCount++;
+               if (!((nmsk ^ hdw->subsys_enabled_mask) &
+                     PVR2_SUBSYS_ALL)) break;
+               if (tryCount > 4) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Too many retries when configuring device;"
+                                  " giving up");
+                       pvr2_hdw_render_useless(hdw);
+                       break;
+               }
+               if (tryCount > 1) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Retrying device reconfiguration");
+               }
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "subsys mask changing 0x%lx:0x%lx"
+                          " from 0x%lx to 0x%lx",
+                          msk,val,hdw->subsys_enabled_mask,nmsk);
+
+               vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
+                       hdw->subsys_enabled_mask;
+               if (vmsk) {
+                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_encoder_stop");
+                               ret = pvr2_encoder_stop(hdw);
+                               if (ret) {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "Error recovery initiated");
+                                       hdw->subsys_enabled_mask &=
+                                               ~FIRMWARE_RECOVERY_BITS;
+                                       continue;
+                               }
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_hdw_cmd_usbstream(0)");
+                               pvr2_hdw_cmd_usbstream(hdw,0);
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " decoder disable");
+                               if (hdw->decoder_ctrl) {
+                                       hdw->decoder_ctrl->enable(
+                                               hdw->decoder_ctrl->ctxt,0);
+                               } else {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "WARNING:"
+                                                  " No decoder present");
+                               }
+                               hdw->subsys_enabled_mask &=
+                                       ~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
+                       }
+                       if (vmsk & PVR2_SUBSYS_CFG_ALL) {
+                               hdw->subsys_enabled_mask &=
+                                       ~(vmsk & PVR2_SUBSYS_CFG_ALL);
+                       }
+               }
+               vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
+               if (vmsk) {
+                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_upload_firmware2");
+                               ret = pvr2_upload_firmware2(hdw);
+                               if (ret) {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "Failure uploading encoder"
+                                                  " firmware");
+                                       pvr2_hdw_render_useless(hdw);
+                                       break;
+                               }
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_encoder_configure");
+                               ret = pvr2_encoder_configure(hdw);
+                               if (ret) {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "Error recovery initiated");
+                                       hdw->subsys_enabled_mask &=
+                                               ~FIRMWARE_RECOVERY_BITS;
+                                       continue;
+                               }
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " decoder enable");
+                               if (hdw->decoder_ctrl) {
+                                       hdw->decoder_ctrl->enable(
+                                               hdw->decoder_ctrl->ctxt,!0);
+                               } else {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "WARNING:"
+                                                  " No decoder present");
+                               }
+                               hdw->subsys_enabled_mask |=
+                                       (1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_hdw_cmd_usbstream(1)");
+                               pvr2_hdw_cmd_usbstream(hdw,!0);
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_encoder_start");
+                               ret = pvr2_encoder_start(hdw);
+                               if (ret) {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "Error recovery initiated");
+                                       hdw->subsys_enabled_mask &=
+                                               ~FIRMWARE_RECOVERY_BITS;
+                                       continue;
+                               }
+                       }
+               }
+       }
+}
+
+
+void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
+                            unsigned long msk,unsigned long val)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+void pvr2_hdw_subsys_bit_set(struct pvr2_hdw *hdw,unsigned long msk)
+{
+       pvr2_hdw_subsys_bit_chg(hdw,msk,msk);
+}
+
+
+void pvr2_hdw_subsys_bit_clr(struct pvr2_hdw *hdw,unsigned long msk)
+{
+       pvr2_hdw_subsys_bit_chg(hdw,msk,0);
+}
+
+
+unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw)
+{
+       return hdw->subsys_enabled_mask;
+}
+
+
+unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw)
+{
+       return hdw->subsys_stream_mask;
+}
+
+
+void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+                                           unsigned long msk,
+                                           unsigned long val)
+{
+       unsigned long val2;
+       msk &= PVR2_SUBSYS_ALL;
+       val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk));
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx",
+                  msk,val,hdw->subsys_stream_mask,val2);
+       hdw->subsys_stream_mask = val2;
+}
+
+
+void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
+                                   unsigned long msk,
+                                   unsigned long val)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
+{
+       if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
+       if (enableFl) {
+               pvr2_trace(PVR2_TRACE_START_STOP,
+                          "/*--TRACE_STREAM--*/ enable");
+               pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0);
+       } else {
+               pvr2_trace(PVR2_TRACE_START_STOP,
+                          "/*--TRACE_STREAM--*/ disable");
+               pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+       }
+       if (!hdw->flag_ok) return -EIO;
+       hdw->flag_streaming_enabled = enableFl != 0;
+       return 0;
+}
+
+
+int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
+{
+       return hdw->flag_streaming_enabled != 0;
+}
+
+
+int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
+{
+       int ret;
+       LOCK_TAKE(hdw->big_lock); do {
+               ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return ret;
+}
+
+
+int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw,
+                                    enum pvr2_config config)
+{
+       unsigned long sm = hdw->subsys_enabled_mask;
+       if (!hdw->flag_ok) return -EIO;
+       pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+       hdw->config = config;
+       pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm);
+       return 0;
+}
+
+
+int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
+{
+       int ret;
+       if (!hdw->flag_ok) return -EIO;
+       LOCK_TAKE(hdw->big_lock);
+       ret = pvr2_hdw_set_stream_type_no_lock(hdw,config);
+       LOCK_GIVE(hdw->big_lock);
+       return ret;
+}
+
+
+static int get_default_tuner_type(struct pvr2_hdw *hdw)
+{
+       int unit_number = hdw->unit_number;
+       int tp = -1;
+       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+               tp = tuner[unit_number];
+       }
+       if (tp < 0) return -EINVAL;
+       hdw->tuner_type = tp;
+       return 0;
+}
+
+
+static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
+{
+       int unit_number = hdw->unit_number;
+       int tp = 0;
+       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+               tp = video_std[unit_number];
+       }
+       return tp;
+}
+
+
+static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw)
+{
+       int unit_number = hdw->unit_number;
+       int tp = 0;
+       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+               tp = tolerance[unit_number];
+       }
+       return tp;
+}
+
+
+static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
+{
+       /* Try a harmless request to fetch the eeprom's address over
+          endpoint 1.  See what happens.  Only the full FX2 image can
+          respond to this.  If this probe fails then likely the FX2
+          firmware needs be loaded. */
+       int result;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = 0xeb;
+               result = pvr2_send_request_ex(hdw,HZ*1,!0,
+                                          hdw->cmd_buffer,1,
+                                          hdw->cmd_buffer,1);
+               if (result < 0) break;
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+       if (result) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Probe of device endpoint 1 result status %d",
+                          result);
+       } else {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Probe of device endpoint 1 succeeded");
+       }
+       return result == 0;
+}
+
+static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
+{
+       char buf[40];
+       unsigned int bcnt;
+       v4l2_std_id std1,std2;
+
+       std1 = get_default_standard(hdw);
+
+       bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Supported video standard(s) reported by eeprom: %.*s",
+                  bcnt,buf);
+
+       hdw->std_mask_avail = hdw->std_mask_eeprom;
+
+       std2 = std1 & ~hdw->std_mask_avail;
+       if (std2) {
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Expanding supported video standards"
+                          " to include: %.*s",
+                          bcnt,buf);
+               hdw->std_mask_avail |= std2;
+       }
+
+       pvr2_hdw_internal_set_std_avail(hdw);
+
+       if (std1) {
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Initial video standard forced to %.*s",
+                          bcnt,buf);
+               hdw->std_mask_cur = std1;
+               hdw->std_dirty = !0;
+               pvr2_hdw_internal_find_stdenum(hdw);
+               return;
+       }
+
+       if (hdw->std_enum_cnt > 1) {
+               // Autoselect the first listed standard
+               hdw->std_enum_cur = 1;
+               hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
+               hdw->std_dirty = !0;
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Initial video standard auto-selected to %s",
+                          hdw->std_defs[hdw->std_enum_cur-1].name);
+               return;
+       }
+
+       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                  "Unable to select a viable initial video standard");
+}
+
+
+static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+{
+       int ret;
+       unsigned int idx;
+       struct pvr2_ctrl *cptr;
+       int reloadFl = 0;
+       if (!reloadFl) {
+               reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
+                           == 0);
+               if (reloadFl) {
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "USB endpoint config looks strange"
+                                  "; possibly firmware needs to be loaded");
+               }
+       }
+       if (!reloadFl) {
+               reloadFl = !pvr2_hdw_check_firmware(hdw);
+               if (reloadFl) {
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "Check for FX2 firmware failed"
+                                  "; possibly firmware needs to be loaded");
+               }
+       }
+       if (reloadFl) {
+               if (pvr2_upload_firmware1(hdw) != 0) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Failure uploading firmware1");
+               }
+               return;
+       }
+       hdw->fw1_state = FW1_STATE_OK;
+
+       if (initusbreset) {
+               pvr2_hdw_device_reset(hdw);
+       }
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) {
+               request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]);
+       }
+
+       pvr2_hdw_cmd_powerup(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       if (pvr2_upload_firmware2(hdw)){
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
+               pvr2_hdw_render_useless(hdw);
+               return;
+       }
+
+       // This step MUST happen after the earlier powerup step.
+       pvr2_i2c_core_init(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
+               cptr = hdw->controls + idx;
+               if (cptr->info->skip_init) continue;
+               if (!cptr->info->set_value) continue;
+               cptr->info->set_value(cptr,~0,cptr->info->default_value);
+       }
+
+       // Do not use pvr2_reset_ctl_endpoints() here.  It is not
+       // thread-safe against the normal pvr2_send_request() mechanism.
+       // (We should make it thread safe).
+
+       ret = pvr2_hdw_get_eeprom_addr(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+       if (ret < 0) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Unable to determine location of eeprom, skipping");
+       } else {
+               hdw->eeprom_addr = ret;
+               pvr2_eeprom_analyze(hdw);
+               if (!pvr2_hdw_dev_ok(hdw)) return;
+       }
+
+       pvr2_hdw_setup_std(hdw);
+
+       if (!get_default_tuner_type(hdw)) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "pvr2_hdw_setup: Tuner type overridden to %d",
+                          hdw->tuner_type);
+       }
+
+       hdw->tuner_updated = !0;
+       pvr2_i2c_core_check_stale(hdw);
+       hdw->tuner_updated = 0;
+
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       pvr2_hdw_commit_ctl_internal(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       hdw->vid_stream = pvr2_stream_create();
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "pvr2_hdw_setup: video stream is %p",hdw->vid_stream);
+       if (hdw->vid_stream) {
+               idx = get_default_error_tolerance(hdw);
+               if (idx) {
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "pvr2_hdw_setup: video stream %p"
+                                  " setting tolerance %u",
+                                  hdw->vid_stream,idx);
+               }
+               pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev,
+                                 PVR2_VID_ENDPOINT,idx);
+       }
+
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       /* Make sure everything is up to date */
+       pvr2_i2c_core_sync(hdw);
+
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       hdw->flag_init_ok = !0;
+}
+
+
+int pvr2_hdw_setup(struct pvr2_hdw *hdw)
+{
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw);
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_setup_low(hdw);
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d",
+                          hdw,hdw->flag_ok,hdw->flag_init_ok);
+               if (pvr2_hdw_dev_ok(hdw)) {
+                       if (pvr2_hdw_init_ok(hdw)) {
+                               pvr2_trace(
+                                       PVR2_TRACE_INFO,
+                                       "Device initialization"
+                                       " completed successfully.");
+                               break;
+                       }
+                       if (hdw->fw1_state == FW1_STATE_RELOAD) {
+                               pvr2_trace(
+                                       PVR2_TRACE_INFO,
+                                       "Device microcontroller firmware"
+                                       " (re)loaded; it should now reset"
+                                       " and reconnect.");
+                               break;
+                       }
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "Device initialization was not successful.");
+                       if (hdw->fw1_state == FW1_STATE_MISSING) {
+                               pvr2_trace(
+                                       PVR2_TRACE_ERROR_LEGS,
+                                       "Giving up since device"
+                                       " microcontroller firmware"
+                                       " appears to be missing.");
+                               break;
+                       }
+               }
+               if (procreload) {
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "Attempting pvrusb2 recovery by reloading"
+                               " primary firmware.");
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "If this works, device should disconnect"
+                               " and reconnect in a sane state.");
+                       hdw->fw1_state = FW1_STATE_UNKNOWN;
+                       pvr2_upload_firmware1(hdw);
+               } else {
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "***WARNING*** pvrusb2 device hardware"
+                               " appears to be jammed"
+                               " and I can't clear it.");
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "You might need to power cycle"
+                               " the pvrusb2 device"
+                               " in order to recover.");
+               }
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw);
+       return hdw->flag_init_ok;
+}
+
+
+/* Create and return a structure for interacting with the underlying
+   hardware */
+struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+                                const struct usb_device_id *devid)
+{
+       unsigned int idx,cnt1,cnt2;
+       struct pvr2_hdw *hdw;
+       unsigned int hdw_type;
+       int valid_std_mask;
+       struct pvr2_ctrl *cptr;
+       __u8 ifnum;
+       struct v4l2_queryctrl qctrl;
+       struct pvr2_ctl_info *ciptr;
+
+       hdw_type = devid - pvr2_device_table;
+       if (hdw_type >=
+           sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Bogus device type of %u reported",hdw_type);
+               return 0;
+       }
+
+       hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
+                  hdw,pvr2_device_names[hdw_type]);
+       if (!hdw) goto fail;
+       memset(hdw,0,sizeof(*hdw));
+       cx2341x_fill_defaults(&hdw->enc_ctl_state);
+
+       hdw->control_cnt = CTRLDEF_COUNT;
+       hdw->control_cnt += MPEGDEF_COUNT;
+       hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+                               GFP_KERNEL);
+       if (!hdw->controls) goto fail;
+       memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
+       hdw->hdw_type = hdw_type;
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               cptr->hdw = hdw;
+       }
+       for (idx = 0; idx < 32; idx++) {
+               hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx];
+       }
+       for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
+               cptr = hdw->controls + idx;
+               cptr->info = control_defs+idx;
+       }
+       /* Define and configure additional controls from cx2341x module. */
+       hdw->mpeg_ctrl_info = kmalloc(
+               sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
+       if (!hdw->mpeg_ctrl_info) goto fail;
+       memset(hdw->mpeg_ctrl_info,0,
+              sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
+       for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
+               cptr = hdw->controls + idx + CTRLDEF_COUNT;
+               ciptr = &(hdw->mpeg_ctrl_info[idx].info);
+               ciptr->desc = hdw->mpeg_ctrl_info[idx].desc;
+               ciptr->name = mpeg_ids[idx].strid;
+               ciptr->v4l_id = mpeg_ids[idx].id;
+               ciptr->skip_init = !0;
+               ciptr->get_value = ctrl_cx2341x_get;
+               ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags;
+               ciptr->is_dirty = ctrl_cx2341x_is_dirty;
+               if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty;
+               qctrl.id = ciptr->v4l_id;
+               cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl);
+               if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) {
+                       ciptr->set_value = ctrl_cx2341x_set;
+               }
+               strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name,
+                       PVR2_CTLD_INFO_DESC_SIZE);
+               hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0;
+               ciptr->default_value = qctrl.default_value;
+               switch (qctrl.type) {
+               default:
+               case V4L2_CTRL_TYPE_INTEGER:
+                       ciptr->type = pvr2_ctl_int;
+                       ciptr->def.type_int.min_value = qctrl.minimum;
+                       ciptr->def.type_int.max_value = qctrl.maximum;
+                       break;
+               case V4L2_CTRL_TYPE_BOOLEAN:
+                       ciptr->type = pvr2_ctl_bool;
+                       break;
+               case V4L2_CTRL_TYPE_MENU:
+                       ciptr->type = pvr2_ctl_enum;
+                       ciptr->def.type_enum.value_names =
+                               cx2341x_ctrl_get_menu(ciptr->v4l_id);
+                       for (cnt1 = 0;
+                            ciptr->def.type_enum.value_names[cnt1] != NULL;
+                            cnt1++) { }
+                       ciptr->def.type_enum.count = cnt1;
+                       break;
+               }
+               cptr->info = ciptr;
+       }
+
+       // Initialize video standard enum dynamic control
+       cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM);
+       if (cptr) {
+               memcpy(&hdw->std_info_enum,cptr->info,
+                      sizeof(hdw->std_info_enum));
+               cptr->info = &hdw->std_info_enum;
+
+       }
+       // Initialize control data regarding video standard masks
+       valid_std_mask = pvr2_std_get_usable();
+       for (idx = 0; idx < 32; idx++) {
+               if (!(valid_std_mask & (1 << idx))) continue;
+               cnt1 = pvr2_std_id_to_str(
+                       hdw->std_mask_names[idx],
+                       sizeof(hdw->std_mask_names[idx])-1,
+                       1 << idx);
+               hdw->std_mask_names[idx][cnt1] = 0;
+       }
+       cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL);
+       if (cptr) {
+               memcpy(&hdw->std_info_avail,cptr->info,
+                      sizeof(hdw->std_info_avail));
+               cptr->info = &hdw->std_info_avail;
+               hdw->std_info_avail.def.type_bitmask.bit_names =
+                       hdw->std_mask_ptrs;
+               hdw->std_info_avail.def.type_bitmask.valid_bits =
+                       valid_std_mask;
+       }
+       cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR);
+       if (cptr) {
+               memcpy(&hdw->std_info_cur,cptr->info,
+                      sizeof(hdw->std_info_cur));
+               cptr->info = &hdw->std_info_cur;
+               hdw->std_info_cur.def.type_bitmask.bit_names =
+                       hdw->std_mask_ptrs;
+               hdw->std_info_avail.def.type_bitmask.valid_bits =
+                       valid_std_mask;
+       }
+
+       hdw->eeprom_addr = -1;
+       hdw->unit_number = -1;
+       hdw->v4l_minor_number = -1;
+       hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
+       if (!hdw->ctl_write_buffer) goto fail;
+       hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
+       if (!hdw->ctl_read_buffer) goto fail;
+       hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL);
+       if (!hdw->ctl_write_urb) goto fail;
+       hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
+       if (!hdw->ctl_read_urb) goto fail;
+
+       down(&pvr2_unit_sem); do {
+               for (idx = 0; idx < PVR_NUM; idx++) {
+                       if (unit_pointers[idx]) continue;
+                       hdw->unit_number = idx;
+                       unit_pointers[idx] = hdw;
+                       break;
+               }
+       } while (0); up(&pvr2_unit_sem);
+
+       cnt1 = 0;
+       cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2");
+       cnt1 += cnt2;
+       if (hdw->unit_number >= 0) {
+               cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c",
+                                ('a' + hdw->unit_number));
+               cnt1 += cnt2;
+       }
+       if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
+       hdw->name[cnt1] = 0;
+
+       pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
+                  hdw->unit_number,hdw->name);
+
+       hdw->tuner_type = -1;
+       hdw->flag_ok = !0;
+       /* Initialize the mask of subsystems that we will shut down when we
+          stop streaming. */
+       hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
+       hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+
+       pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
+                  hdw->subsys_stream_mask);
+
+       hdw->usb_intf = intf;
+       hdw->usb_dev = interface_to_usbdev(intf);
+
+       ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
+       usb_set_interface(hdw->usb_dev,ifnum,0);
+
+       mutex_init(&hdw->ctl_lock_mutex);
+       mutex_init(&hdw->big_lock_mutex);
+
+       return hdw;
+ fail:
+       if (hdw) {
+               if (hdw->ctl_read_urb) usb_free_urb(hdw->ctl_read_urb);
+               if (hdw->ctl_write_urb) usb_free_urb(hdw->ctl_write_urb);
+               if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
+               if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
+               if (hdw->controls) kfree(hdw->controls);
+               if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+               kfree(hdw);
+       }
+       return 0;
+}
+
+
+/* Remove _all_ associations between this driver and the underlying USB
+   layer. */
+void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
+{
+       if (hdw->flag_disconnected) return;
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw);
+       if (hdw->ctl_read_urb) {
+               usb_kill_urb(hdw->ctl_read_urb);
+               usb_free_urb(hdw->ctl_read_urb);
+               hdw->ctl_read_urb = 0;
+       }
+       if (hdw->ctl_write_urb) {
+               usb_kill_urb(hdw->ctl_write_urb);
+               usb_free_urb(hdw->ctl_write_urb);
+               hdw->ctl_write_urb = 0;
+       }
+       if (hdw->ctl_read_buffer) {
+               kfree(hdw->ctl_read_buffer);
+               hdw->ctl_read_buffer = 0;
+       }
+       if (hdw->ctl_write_buffer) {
+               kfree(hdw->ctl_write_buffer);
+               hdw->ctl_write_buffer = 0;
+       }
+       pvr2_hdw_render_useless_unlocked(hdw);
+       hdw->flag_disconnected = !0;
+       hdw->usb_dev = 0;
+       hdw->usb_intf = 0;
+}
+
+
+/* Destroy hardware interaction structure */
+void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
+{
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
+       if (hdw->fw_buffer) {
+               kfree(hdw->fw_buffer);
+               hdw->fw_buffer = 0;
+       }
+       if (hdw->vid_stream) {
+               pvr2_stream_destroy(hdw->vid_stream);
+               hdw->vid_stream = 0;
+       }
+       if (hdw->audio_stat) {
+               hdw->audio_stat->detach(hdw->audio_stat->ctxt);
+       }
+       if (hdw->decoder_ctrl) {
+               hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
+       }
+       pvr2_i2c_core_done(hdw);
+       pvr2_hdw_remove_usb_stuff(hdw);
+       down(&pvr2_unit_sem); do {
+               if ((hdw->unit_number >= 0) &&
+                   (hdw->unit_number < PVR_NUM) &&
+                   (unit_pointers[hdw->unit_number] == hdw)) {
+                       unit_pointers[hdw->unit_number] = 0;
+               }
+       } while (0); up(&pvr2_unit_sem);
+       if (hdw->controls) kfree(hdw->controls);
+       if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+       if (hdw->std_defs) kfree(hdw->std_defs);
+       if (hdw->std_enum_names) kfree(hdw->std_enum_names);
+       kfree(hdw);
+}
+
+
+int pvr2_hdw_init_ok(struct pvr2_hdw *hdw)
+{
+       return hdw->flag_init_ok;
+}
+
+
+int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw)
+{
+       return (hdw && hdw->flag_ok);
+}
+
+
+/* Called when hardware has been unplugged */
+void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
+{
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw);
+       LOCK_TAKE(hdw->big_lock);
+       LOCK_TAKE(hdw->ctl_lock);
+       pvr2_hdw_remove_usb_stuff(hdw);
+       LOCK_GIVE(hdw->ctl_lock);
+       LOCK_GIVE(hdw->big_lock);
+}
+
+
+// Attempt to autoselect an appropriate value for std_enum_cur given
+// whatever is currently in std_mask_cur
+void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw)
+{
+       unsigned int idx;
+       for (idx = 1; idx < hdw->std_enum_cnt; idx++) {
+               if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) {
+                       hdw->std_enum_cur = idx;
+                       return;
+               }
+       }
+       hdw->std_enum_cur = 0;
+}
+
+
+// Calculate correct set of enumerated standards based on currently known
+// set of available standards bits.
+void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw)
+{
+       struct v4l2_standard *newstd;
+       unsigned int std_cnt;
+       unsigned int idx;
+
+       newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail);
+
+       if (hdw->std_defs) {
+               kfree(hdw->std_defs);
+               hdw->std_defs = 0;
+       }
+       hdw->std_enum_cnt = 0;
+       if (hdw->std_enum_names) {
+               kfree(hdw->std_enum_names);
+               hdw->std_enum_names = 0;
+       }
+
+       if (!std_cnt) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "WARNING: Failed to identify any viable standards");
+       }
+       hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL);
+       hdw->std_enum_names[0] = "none";
+       for (idx = 0; idx < std_cnt; idx++) {
+               hdw->std_enum_names[idx+1] =
+                       newstd[idx].name;
+       }
+       // Set up the dynamic control for this standard
+       hdw->std_info_enum.def.type_enum.value_names = hdw->std_enum_names;
+       hdw->std_info_enum.def.type_enum.count = std_cnt+1;
+       hdw->std_defs = newstd;
+       hdw->std_enum_cnt = std_cnt+1;
+       hdw->std_enum_cur = 0;
+       hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
+}
+
+
+int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,
+                              struct v4l2_standard *std,
+                              unsigned int idx)
+{
+       int ret = -EINVAL;
+       if (!idx) return ret;
+       LOCK_TAKE(hdw->big_lock); do {
+               if (idx >= hdw->std_enum_cnt) break;
+               idx--;
+               memcpy(std,hdw->std_defs+idx,sizeof(*std));
+               ret = 0;
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return ret;
+}
+
+
+/* Get the number of defined controls */
+unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw)
+{
+       return hdw->control_cnt;
+}
+
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw,
+                                            unsigned int idx)
+{
+       if (idx >= hdw->control_cnt) return 0;
+       return hdw->controls + idx;
+}
+
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw,
+                                         unsigned int ctl_id)
+{
+       struct pvr2_ctrl *cptr;
+       unsigned int idx;
+       int i;
+
+       /* This could be made a lot more efficient, but for now... */
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               i = cptr->info->internal_id;
+               if (i && (i == ctl_id)) return cptr;
+       }
+       return 0;
+}
+
+
+/* Given a V4L ID, retrieve the control structure associated with it. */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id)
+{
+       struct pvr2_ctrl *cptr;
+       unsigned int idx;
+       int i;
+
+       /* This could be made a lot more efficient, but for now... */
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               i = cptr->info->v4l_id;
+               if (i && (i == ctl_id)) return cptr;
+       }
+       return 0;
+}
+
+
+/* Given a V4L ID for its immediate predecessor, retrieve the control
+   structure associated with it. */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *hdw,
+                                           unsigned int ctl_id)
+{
+       struct pvr2_ctrl *cptr,*cp2;
+       unsigned int idx;
+       int i;
+
+       /* This could be made a lot more efficient, but for now... */
+       cp2 = 0;
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               i = cptr->info->v4l_id;
+               if (!i) continue;
+               if (i <= ctl_id) continue;
+               if (cp2 && (cp2->info->v4l_id < i)) continue;
+               cp2 = cptr;
+       }
+       return cp2;
+       return 0;
+}
+
+
+static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
+{
+       switch (tp) {
+       case pvr2_ctl_int: return "integer";
+       case pvr2_ctl_enum: return "enum";
+       case pvr2_ctl_bool: return "boolean";
+       case pvr2_ctl_bitmask: return "bitmask";
+       }
+       return "";
+}
+
+
+/* Commit all control changes made up to this point.  Subsystems can be
+   indirectly affected by these changes.  For a given set of things being
+   committed, we'll clear the affected subsystem bits and then once we're
+   done committing everything we'll make a request to restore the subsystem
+   state(s) back to their previous value before this function was called.
+   Thus we can automatically reconfigure affected pieces of the driver as
+   controls are changed. */
+int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
+{
+       unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
+       unsigned long stale_subsys_mask = 0;
+       unsigned int idx;
+       struct pvr2_ctrl *cptr;
+       int value;
+       int commit_flag = 0;
+       char buf[100];
+       unsigned int bcnt,ccnt;
+
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               if (cptr->info->is_dirty == 0) continue;
+               if (!cptr->info->is_dirty(cptr)) continue;
+               if (!commit_flag) {
+                       commit_flag = !0;
+               }
+
+               bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
+                                cptr->info->name);
+               value = 0;
+               cptr->info->get_value(cptr,&value);
+               pvr2_ctrl_value_to_sym_internal(cptr,~0,value,
+                                               buf+bcnt,
+                                               sizeof(buf)-bcnt,&ccnt);
+               bcnt += ccnt;
+               bcnt += scnprintf(buf+bcnt,sizeof(buf)-bcnt," <%s>",
+                                 get_ctrl_typename(cptr->info->type));
+               pvr2_trace(PVR2_TRACE_CTL,
+                          "/*--TRACE_COMMIT--*/ %.*s",
+                          bcnt,buf);
+       }
+
+       if (!commit_flag) {
+               /* Nothing has changed */
+               return 0;
+       }
+
+       /* When video standard changes, reset the hres and vres values -
+          but if the user has pending changes there, then let the changes
+          take priority. */
+       if (hdw->std_dirty) {
+               /* Rewrite the vertical resolution to be appropriate to the
+                  video standard that has been selected. */
+               int nvres;
+               if (hdw->std_mask_cur & V4L2_STD_525_60) {
+                       nvres = 480;
+               } else {
+                       nvres = 576;
+               }
+               if (nvres != hdw->res_ver_val) {
+                       hdw->res_ver_val = nvres;
+                       hdw->res_ver_dirty = !0;
+               }
+       }
+
+       if (hdw->std_dirty ||
+           0) {
+               /* If any of this changes, then the encoder needs to be
+                  reconfigured, and we need to reset the stream. */
+               stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+               stale_subsys_mask |= hdw->subsys_stream_mask;
+       }
+
+       if (hdw->srate_dirty) {
+               /* Write new sample rate into control structure since
+                * the master copy is stale.  We must track srate
+                * separate from the mpeg control structure because
+                * other logic also uses this value. */
+               struct v4l2_ext_controls cs;
+               struct v4l2_ext_control c1;
+               memset(&cs,0,sizeof(cs));
+               memset(&c1,0,sizeof(c1));
+               cs.controls = &c1;
+               cs.count = 1;
+               c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
+               c1.value = hdw->srate_val;
+               cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS);
+       }
+
+       /* Scan i2c core at this point - before we clear all the dirty
+          bits.  Various parts of the i2c core will notice dirty bits as
+          appropriate and arrange to broadcast or directly send updates to
+          the client drivers in order to keep everything in sync */
+       pvr2_i2c_core_check_stale(hdw);
+
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               if (!cptr->info->clear_dirty) continue;
+               cptr->info->clear_dirty(cptr);
+       }
+
+       /* Now execute i2c core update */
+       pvr2_i2c_core_sync(hdw);
+
+       pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0);
+       pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask);
+
+       return 0;
+}
+
+
+int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_commit_ctl_internal(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return 0;
+}
+
+
+void pvr2_hdw_poll(struct pvr2_hdw *hdw)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_i2c_core_sync(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw,
+                                void (*func)(void *),
+                                void *data)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               hdw->poll_trigger_func = func;
+               hdw->poll_trigger_data = data;
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
+{
+       if (hdw->poll_trigger_func) {
+               hdw->poll_trigger_func(hdw->poll_trigger_data);
+       }
+}
+
+
+void pvr2_hdw_poll_trigger(struct pvr2_hdw *hdw)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_poll_trigger_unlocked(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+/* Return name for this driver instance */
+const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
+{
+       return hdw->name;
+}
+
+
+/* Return bit mask indicating signal status */
+unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
+{
+       unsigned int msk = 0;
+       switch (hdw->input_val) {
+       case PVR2_CVAL_INPUT_TV:
+       case PVR2_CVAL_INPUT_RADIO:
+               if (hdw->decoder_ctrl &&
+                   hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
+                       msk |= PVR2_SIGNAL_OK;
+                       if (hdw->audio_stat &&
+                           hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
+                               if (hdw->flag_stereo) {
+                                       msk |= PVR2_SIGNAL_STEREO;
+                               }
+                               if (hdw->flag_bilingual) {
+                                       msk |= PVR2_SIGNAL_SAP;
+                               }
+                       }
+               }
+               break;
+       default:
+               msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
+       }
+       return msk;
+}
+
+
+int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
+{
+       int result;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = 0x0b;
+               result = pvr2_send_request(hdw,
+                                          hdw->cmd_buffer,1,
+                                          hdw->cmd_buffer,1);
+               if (result < 0) break;
+               result = (hdw->cmd_buffer[0] != 0);
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+       return result;
+}
+
+
+/* Return bit mask indicating signal status */
+unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+{
+       unsigned int msk = 0;
+       LOCK_TAKE(hdw->big_lock); do {
+               msk = pvr2_hdw_get_signal_status_internal(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return msk;
+}
+
+
+/* Get handle to video output stream */
+struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp)
+{
+       return hp->vid_stream;
+}
+
+
+void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
+{
+       int nr = pvr2_hdw_get_unit_number(hdw);
+       LOCK_TAKE(hdw->big_lock); do {
+               hdw->log_requested = !0;
+               printk(KERN_INFO "pvrusb2: =================  START STATUS CARD #%d  =================\n", nr);
+               pvr2_i2c_core_check_stale(hdw);
+               hdw->log_requested = 0;
+               pvr2_i2c_core_sync(hdw);
+               pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
+               cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
+               printk(KERN_INFO "pvrusb2: ==================  END STATUS CARD #%d  ==================\n", nr);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
+{
+       int ret;
+       u16 address;
+       unsigned int pipe;
+       LOCK_TAKE(hdw->big_lock); do {
+               if ((hdw->fw_buffer == 0) == !enable_flag) break;
+
+               if (!enable_flag) {
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Cleaning up after CPU firmware fetch");
+                       kfree(hdw->fw_buffer);
+                       hdw->fw_buffer = 0;
+                       hdw->fw_size = 0;
+                       /* Now release the CPU.  It will disconnect and
+                          reconnect later. */
+                       pvr2_hdw_cpureset_assert(hdw,0);
+                       break;
+               }
+
+               pvr2_trace(PVR2_TRACE_FIRMWARE,
+                          "Preparing to suck out CPU firmware");
+               hdw->fw_size = 0x2000;
+               hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+               if (!hdw->fw_buffer) {
+                       hdw->fw_size = 0;
+                       break;
+               }
+
+               memset(hdw->fw_buffer,0,hdw->fw_size);
+
+               /* We have to hold the CPU during firmware upload. */
+               pvr2_hdw_cpureset_assert(hdw,1);
+
+               /* download the firmware from address 0000-1fff in 2048
+                  (=0x800) bytes chunk. */
+
+               pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware");
+               pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
+               for(address = 0; address < hdw->fw_size; address += 0x800) {
+                       ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0,
+                                             address,0,
+                                             hdw->fw_buffer+address,0x800,HZ);
+                       if (ret < 0) break;
+               }
+
+               pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware");
+
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+/* Return true if we're in a mode for retrieval CPU firmware */
+int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw)
+{
+       return hdw->fw_buffer != 0;
+}
+
+
+int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
+                      char *buf,unsigned int cnt)
+{
+       int ret = -EINVAL;
+       LOCK_TAKE(hdw->big_lock); do {
+               if (!buf) break;
+               if (!cnt) break;
+
+               if (!hdw->fw_buffer) {
+                       ret = -EIO;
+                       break;
+               }
+
+               if (offs >= hdw->fw_size) {
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Read firmware data offs=%d EOF",
+                                  offs);
+                       ret = 0;
+                       break;
+               }
+
+               if (offs + cnt > hdw->fw_size) cnt = hdw->fw_size - offs;
+
+               memcpy(buf,hdw->fw_buffer+offs,cnt);
+
+               pvr2_trace(PVR2_TRACE_FIRMWARE,
+                          "Read firmware data offs=%d cnt=%d",
+                          offs,cnt);
+               ret = cnt;
+       } while (0); LOCK_GIVE(hdw->big_lock);
+
+       return ret;
+}
+
+
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
+{
+       return hdw->v4l_minor_number;
+}
+
+
+/* Store the v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
+{
+       hdw->v4l_minor_number = v;
+}
+
+
+void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw)
+{
+       if (!hdw->usb_dev) return;
+       usb_settoggle(hdw->usb_dev, PVR2_CTL_WRITE_ENDPOINT & 0xf,
+                     !(PVR2_CTL_WRITE_ENDPOINT & USB_DIR_IN), 0);
+       usb_settoggle(hdw->usb_dev, PVR2_CTL_READ_ENDPOINT & 0xf,
+                     !(PVR2_CTL_READ_ENDPOINT & USB_DIR_IN), 0);
+       usb_clear_halt(hdw->usb_dev,
+                      usb_rcvbulkpipe(hdw->usb_dev,
+                                      PVR2_CTL_READ_ENDPOINT & 0x7f));
+       usb_clear_halt(hdw->usb_dev,
+                      usb_sndbulkpipe(hdw->usb_dev,
+                                      PVR2_CTL_WRITE_ENDPOINT & 0x7f));
+}
+
+
+static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct pvr2_hdw *hdw = urb->context;
+       hdw->ctl_write_pend_flag = 0;
+       if (hdw->ctl_read_pend_flag) return;
+       complete(&hdw->ctl_done);
+}
+
+
+static void pvr2_ctl_read_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct pvr2_hdw *hdw = urb->context;
+       hdw->ctl_read_pend_flag = 0;
+       if (hdw->ctl_write_pend_flag) return;
+       complete(&hdw->ctl_done);
+}
+
+
+static void pvr2_ctl_timeout(unsigned long data)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
+               hdw->ctl_timeout_flag = !0;
+               if (hdw->ctl_write_pend_flag && hdw->ctl_write_urb) {
+                       usb_unlink_urb(hdw->ctl_write_urb);
+               }
+               if (hdw->ctl_read_pend_flag && hdw->ctl_read_urb) {
+                       usb_unlink_urb(hdw->ctl_read_urb);
+               }
+       }
+}
+
+
+int pvr2_send_request_ex(struct pvr2_hdw *hdw,
+                        unsigned int timeout,int probe_fl,
+                        void *write_data,unsigned int write_len,
+                        void *read_data,unsigned int read_len)
+{
+       unsigned int idx;
+       int status = 0;
+       struct timer_list timer;
+       if (!hdw->ctl_lock_held) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Attempted to execute control transfer"
+                          " without lock!!");
+               return -EDEADLK;
+       }
+       if ((!hdw->flag_ok) && !probe_fl) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Attempted to execute control transfer"
+                          " when device not ok");
+               return -EIO;
+       }
+       if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) {
+               if (!probe_fl) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Attempted to execute control transfer"
+                                  " when USB is disconnected");
+               }
+               return -ENOTTY;
+       }
+
+       /* Ensure that we have sane parameters */
+       if (!write_data) write_len = 0;
+       if (!read_data) read_len = 0;
+       if (write_len > PVR2_CTL_BUFFSIZE) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Attempted to execute %d byte"
+                       " control-write transfer (limit=%d)",
+                       write_len,PVR2_CTL_BUFFSIZE);
+               return -EINVAL;
+       }
+       if (read_len > PVR2_CTL_BUFFSIZE) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Attempted to execute %d byte"
+                       " control-read transfer (limit=%d)",
+                       write_len,PVR2_CTL_BUFFSIZE);
+               return -EINVAL;
+       }
+       if ((!write_len) && (!read_len)) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Attempted to execute null control transfer?");
+               return -EINVAL;
+       }
+
+
+       hdw->cmd_debug_state = 1;
+       if (write_len) {
+               hdw->cmd_debug_code = ((unsigned char *)write_data)[0];
+       } else {
+               hdw->cmd_debug_code = 0;
+       }
+       hdw->cmd_debug_write_len = write_len;
+       hdw->cmd_debug_read_len = read_len;
+
+       /* Initialize common stuff */
+       init_completion(&hdw->ctl_done);
+       hdw->ctl_timeout_flag = 0;
+       hdw->ctl_write_pend_flag = 0;
+       hdw->ctl_read_pend_flag = 0;
+       init_timer(&timer);
+       timer.expires = jiffies + timeout;
+       timer.data = (unsigned long)hdw;
+       timer.function = pvr2_ctl_timeout;
+
+       if (write_len) {
+               hdw->cmd_debug_state = 2;
+               /* Transfer write data to internal buffer */
+               for (idx = 0; idx < write_len; idx++) {
+                       hdw->ctl_write_buffer[idx] =
+                               ((unsigned char *)write_data)[idx];
+               }
+               /* Initiate a write request */
+               usb_fill_bulk_urb(hdw->ctl_write_urb,
+                                 hdw->usb_dev,
+                                 usb_sndbulkpipe(hdw->usb_dev,
+                                                 PVR2_CTL_WRITE_ENDPOINT),
+                                 hdw->ctl_write_buffer,
+                                 write_len,
+                                 pvr2_ctl_write_complete,
+                                 hdw);
+               hdw->ctl_write_urb->actual_length = 0;
+               hdw->ctl_write_pend_flag = !0;
+               status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL);
+               if (status < 0) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Failed to submit write-control"
+                                  " URB status=%d",status);
+                       hdw->ctl_write_pend_flag = 0;
+                       goto done;
+               }
+       }
+
+       if (read_len) {
+               hdw->cmd_debug_state = 3;
+               memset(hdw->ctl_read_buffer,0x43,read_len);
+               /* Initiate a read request */
+               usb_fill_bulk_urb(hdw->ctl_read_urb,
+                                 hdw->usb_dev,
+                                 usb_rcvbulkpipe(hdw->usb_dev,
+                                                 PVR2_CTL_READ_ENDPOINT),
+                                 hdw->ctl_read_buffer,
+                                 read_len,
+                                 pvr2_ctl_read_complete,
+                                 hdw);
+               hdw->ctl_read_urb->actual_length = 0;
+               hdw->ctl_read_pend_flag = !0;
+               status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL);
+               if (status < 0) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Failed to submit read-control"
+                                  " URB status=%d",status);
+                       hdw->ctl_read_pend_flag = 0;
+                       goto done;
+               }
+       }
+
+       /* Start timer */
+       add_timer(&timer);
+
+       /* Now wait for all I/O to complete */
+       hdw->cmd_debug_state = 4;
+       while (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
+               wait_for_completion(&hdw->ctl_done);
+       }
+       hdw->cmd_debug_state = 5;
+
+       /* Stop timer */
+       del_timer_sync(&timer);
+
+       hdw->cmd_debug_state = 6;
+       status = 0;
+
+       if (hdw->ctl_timeout_flag) {
+               status = -ETIMEDOUT;
+               if (!probe_fl) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Timed out control-write");
+               }
+               goto done;
+       }
+
+       if (write_len) {
+               /* Validate results of write request */
+               if ((hdw->ctl_write_urb->status != 0) &&
+                   (hdw->ctl_write_urb->status != -ENOENT) &&
+                   (hdw->ctl_write_urb->status != -ESHUTDOWN) &&
+                   (hdw->ctl_write_urb->status != -ECONNRESET)) {
+                       /* USB subsystem is reporting some kind of failure
+                          on the write */
+                       status = hdw->ctl_write_urb->status;
+                       if (!probe_fl) {
+                               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                          "control-write URB failure,"
+                                          " status=%d",
+                                          status);
+                       }
+                       goto done;
+               }
+               if (hdw->ctl_write_urb->actual_length < write_len) {
+                       /* Failed to write enough data */
+                       status = -EIO;
+                       if (!probe_fl) {
+                               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                          "control-write URB short,"
+                                          " expected=%d got=%d",
+                                          write_len,
+                                          hdw->ctl_write_urb->actual_length);
+                       }
+                       goto done;
+               }
+       }
+       if (read_len) {
+               /* Validate results of read request */
+               if ((hdw->ctl_read_urb->status != 0) &&
+                   (hdw->ctl_read_urb->status != -ENOENT) &&
+                   (hdw->ctl_read_urb->status != -ESHUTDOWN) &&
+                   (hdw->ctl_read_urb->status != -ECONNRESET)) {
+                       /* USB subsystem is reporting some kind of failure
+                          on the read */
+                       status = hdw->ctl_read_urb->status;
+                       if (!probe_fl) {
+                               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                          "control-read URB failure,"
+                                          " status=%d",
+                                          status);
+                       }
+                       goto done;
+               }
+               if (hdw->ctl_read_urb->actual_length < read_len) {
+                       /* Failed to read enough data */
+                       status = -EIO;
+                       if (!probe_fl) {
+                               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                          "control-read URB short,"
+                                          " expected=%d got=%d",
+                                          read_len,
+                                          hdw->ctl_read_urb->actual_length);
+                       }
+                       goto done;
+               }
+               /* Transfer retrieved data out from internal buffer */
+               for (idx = 0; idx < read_len; idx++) {
+                       ((unsigned char *)read_data)[idx] =
+                               hdw->ctl_read_buffer[idx];
+               }
+       }
+
+ done:
+
+       hdw->cmd_debug_state = 0;
+       if ((status < 0) && (!probe_fl)) {
+               pvr2_hdw_render_useless_unlocked(hdw);
+       }
+       return status;
+}
+
+
+int pvr2_send_request(struct pvr2_hdw *hdw,
+                     void *write_data,unsigned int write_len,
+                     void *read_data,unsigned int read_len)
+{
+       return pvr2_send_request_ex(hdw,HZ*4,0,
+                                   write_data,write_len,
+                                   read_data,read_len);
+}
+
+int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
+{
+       int ret;
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       hdw->cmd_buffer[0] = 0x04;  /* write register prefix */
+       PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
+       hdw->cmd_buffer[5] = 0;
+       hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
+       hdw->cmd_buffer[7] = reg & 0xff;
+
+
+       ret = pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 0);
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
+{
+       int ret = 0;
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       hdw->cmd_buffer[0] = 0x05;  /* read register prefix */
+       hdw->cmd_buffer[1] = 0;
+       hdw->cmd_buffer[2] = 0;
+       hdw->cmd_buffer[3] = 0;
+       hdw->cmd_buffer[4] = 0;
+       hdw->cmd_buffer[5] = 0;
+       hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
+       hdw->cmd_buffer[7] = reg & 0xff;
+
+       ret |= pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 4);
+       *data = PVR2_COMPOSE_LE(hdw->cmd_buffer,0);
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
+{
+       int ret;
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       hdw->cmd_buffer[0] = (data >> 8) & 0xff;
+       hdw->cmd_buffer[1] = data & 0xff;
+
+       ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
+{
+       int ret;
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       hdw->cmd_buffer[0] = data;
+
+       ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
+{
+       if (!hdw->flag_ok) return;
+       pvr2_trace(PVR2_TRACE_INIT,"render_useless");
+       hdw->flag_ok = 0;
+       if (hdw->vid_stream) {
+               pvr2_stream_setup(hdw->vid_stream,0,0,0);
+       }
+       hdw->flag_streaming_enabled = 0;
+       hdw->subsys_enabled_mask = 0;
+}
+
+
+void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
+{
+       LOCK_TAKE(hdw->ctl_lock);
+       pvr2_hdw_render_useless_unlocked(hdw);
+       LOCK_GIVE(hdw->ctl_lock);
+}
+
+
+void pvr2_hdw_device_reset(struct pvr2_hdw *hdw)
+{
+       int ret;
+       pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset...");
+       ret = usb_lock_device_for_reset(hdw->usb_dev,0);
+       if (ret == 1) {
+               ret = usb_reset_device(hdw->usb_dev);
+               usb_unlock_device(hdw->usb_dev);
+       } else {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to lock USB device ret=%d",ret);
+       }
+       if (init_pause_msec) {
+               pvr2_trace(PVR2_TRACE_INFO,
+                          "Waiting %u msec for hardware to settle",
+                          init_pause_msec);
+               msleep(init_pause_msec);
+       }
+
+}
+
+
+void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
+{
+       char da[1];
+       unsigned int pipe;
+       int ret;
+
+       if (!hdw->usb_dev) return;
+
+       pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val);
+
+       da[0] = val ? 0x01 : 0x00;
+
+       /* Write the CPUCS register on the 8051.  The lsb of the register
+          is the reset bit; a 1 asserts reset while a 0 clears it. */
+       pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
+       ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,HZ);
+       if (ret < 0) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "cpureset_assert(%d) error=%d",val,ret);
+               pvr2_hdw_render_useless(hdw);
+       }
+}
+
+
+int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
+{
+       int status;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
+               hdw->flag_ok = !0;
+               hdw->cmd_buffer[0] = 0xdd;
+               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
+       return status;
+}
+
+
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
+{
+       int status;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
+               hdw->cmd_buffer[0] = 0xde;
+               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
+       return status;
+}
+
+
+int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
+{
+       if (!hdw->decoder_ctrl) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Unable to reset decoder: nothing attached");
+               return -ENOTTY;
+       }
+
+       if (!hdw->decoder_ctrl->force_reset) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Unable to reset decoder: not implemented");
+               return -ENOTTY;
+       }
+
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Requesting decoder reset");
+       hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
+       return 0;
+}
+
+
+int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
+{
+       int status;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
+               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
+       if (!status) {
+               hdw->subsys_enabled_mask =
+                       ((hdw->subsys_enabled_mask &
+                         ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) |
+                        (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0));
+       }
+       return status;
+}
+
+
+void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
+                            struct pvr2_hdw_debug_info *ptr)
+{
+       ptr->big_lock_held = hdw->big_lock_held;
+       ptr->ctl_lock_held = hdw->ctl_lock_held;
+       ptr->flag_ok = hdw->flag_ok;
+       ptr->flag_disconnected = hdw->flag_disconnected;
+       ptr->flag_init_ok = hdw->flag_init_ok;
+       ptr->flag_streaming_enabled = hdw->flag_streaming_enabled;
+       ptr->subsys_flags = hdw->subsys_enabled_mask;
+       ptr->cmd_debug_state = hdw->cmd_debug_state;
+       ptr->cmd_code = hdw->cmd_debug_code;
+       ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
+       ptr->cmd_debug_read_len = hdw->cmd_debug_read_len;
+       ptr->cmd_debug_timeout = hdw->ctl_timeout_flag;
+       ptr->cmd_debug_write_pend = hdw->ctl_write_pend_flag;
+       ptr->cmd_debug_read_pend = hdw->ctl_read_pend_flag;
+       ptr->cmd_debug_rstatus = hdw->ctl_read_urb->status;
+       ptr->cmd_debug_wstatus = hdw->ctl_read_urb->status;
+}
+
+
+int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
+{
+       return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
+}
+
+
+int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *dp)
+{
+       return pvr2_read_register(hdw,PVR2_GPIO_OUT,dp);
+}
+
+
+int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *dp)
+{
+       return pvr2_read_register(hdw,PVR2_GPIO_IN,dp);
+}
+
+
+int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val)
+{
+       u32 cval,nval;
+       int ret;
+       if (~msk) {
+               ret = pvr2_read_register(hdw,PVR2_GPIO_DIR,&cval);
+               if (ret) return ret;
+               nval = (cval & ~msk) | (val & msk);
+               pvr2_trace(PVR2_TRACE_GPIO,
+                          "GPIO direction changing 0x%x:0x%x"
+                          " from 0x%x to 0x%x",
+                          msk,val,cval,nval);
+       } else {
+               nval = val;
+               pvr2_trace(PVR2_TRACE_GPIO,
+                          "GPIO direction changing to 0x%x",nval);
+       }
+       return pvr2_write_register(hdw,PVR2_GPIO_DIR,nval);
+}
+
+
+int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
+{
+       u32 cval,nval;
+       int ret;
+       if (~msk) {
+               ret = pvr2_read_register(hdw,PVR2_GPIO_OUT,&cval);
+               if (ret) return ret;
+               nval = (cval & ~msk) | (val & msk);
+               pvr2_trace(PVR2_TRACE_GPIO,
+                          "GPIO output changing 0x%x:0x%x from 0x%x to 0x%x",
+                          msk,val,cval,nval);
+       } else {
+               nval = val;
+               pvr2_trace(PVR2_TRACE_GPIO,
+                          "GPIO output changing to 0x%x",nval);
+       }
+       return pvr2_write_register(hdw,PVR2_GPIO_OUT,nval);
+}
+
+
+int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
+{
+       int result;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = 0xeb;
+               result = pvr2_send_request(hdw,
+                                          hdw->cmd_buffer,1,
+                                          hdw->cmd_buffer,1);
+               if (result < 0) break;
+               result = hdw->cmd_buffer[0];
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+       return result;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
new file mode 100644 (file)
index 0000000..63f5291
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_HDW_H
+#define __PVRUSB2_HDW_H
+
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include "pvrusb2-io.h"
+#include "pvrusb2-ctrl.h"
+
+
+/* Private internal control ids, look these up with
+   pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */
+#define PVR2_CID_STDENUM 1
+#define PVR2_CID_STDCUR 2
+#define PVR2_CID_STDAVAIL 3
+#define PVR2_CID_INPUT 4
+#define PVR2_CID_AUDIOMODE 5
+#define PVR2_CID_FREQUENCY 6
+#define PVR2_CID_HRES 7
+#define PVR2_CID_VRES 8
+
+/* Legal values for the INPUT state variable */
+#define PVR2_CVAL_INPUT_TV 0
+#define PVR2_CVAL_INPUT_SVIDEO 1
+#define PVR2_CVAL_INPUT_COMPOSITE 2
+#define PVR2_CVAL_INPUT_RADIO 3
+
+/* Values that pvr2_hdw_get_signal_status() returns */
+#define PVR2_SIGNAL_OK     0x0001
+#define PVR2_SIGNAL_STEREO 0x0002
+#define PVR2_SIGNAL_SAP    0x0004
+
+
+/* Subsystem definitions - these are various pieces that can be
+   independently stopped / started.  Usually you don't want to mess with
+   this directly (let the driver handle things itself), but it is useful
+   for debugging. */
+#define PVR2_SUBSYS_B_ENC_FIRMWARE        0
+#define PVR2_SUBSYS_B_ENC_CFG             1
+#define PVR2_SUBSYS_B_DIGITIZER_RUN       2
+#define PVR2_SUBSYS_B_USBSTREAM_RUN       3
+#define PVR2_SUBSYS_B_ENC_RUN             4
+
+#define PVR2_SUBSYS_CFG_ALL ( \
+       (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+       (1 << PVR2_SUBSYS_B_ENC_CFG) )
+#define PVR2_SUBSYS_RUN_ALL ( \
+       (1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \
+       (1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \
+       (1 << PVR2_SUBSYS_B_ENC_RUN) )
+#define PVR2_SUBSYS_ALL ( \
+       PVR2_SUBSYS_CFG_ALL | \
+       PVR2_SUBSYS_RUN_ALL )
+
+enum pvr2_config {
+       pvr2_config_empty,
+       pvr2_config_mpeg,
+       pvr2_config_vbi,
+       pvr2_config_radio,
+};
+
+const char *pvr2_config_get_name(enum pvr2_config);
+
+struct pvr2_hdw;
+
+/* Create and return a structure for interacting with the underlying
+   hardware */
+struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+                                const struct usb_device_id *devid);
+
+/* Poll for background activity (if any) */
+void pvr2_hdw_poll(struct pvr2_hdw *);
+
+/* Trigger a poll to take place later at a convenient time */
+void pvr2_hdw_poll_trigger(struct pvr2_hdw *);
+void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *);
+
+/* Register a callback used to trigger a future poll */
+void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *,
+                                void (*func)(void *),
+                                void *data);
+
+/* Get pointer to structure given unit number */
+struct pvr2_hdw *pvr2_hdw_find(int unit_number);
+
+/* Destroy hardware interaction structure */
+void pvr2_hdw_destroy(struct pvr2_hdw *);
+
+/* Set up the structure and attempt to put the device into a usable state.
+   This can be a time-consuming operation, which is why it is not done
+   internally as part of the create() step.  Return value is exactly the
+   same as pvr2_hdw_init_ok(). */
+int pvr2_hdw_setup(struct pvr2_hdw *);
+
+/* Initialization succeeded */
+int pvr2_hdw_init_ok(struct pvr2_hdw *);
+
+/* Return true if in the ready (normal) state */
+int pvr2_hdw_dev_ok(struct pvr2_hdw *);
+
+/* Return small integer number [1..N] for logical instance number of this
+   device.  This is useful for indexing array-valued module parameters. */
+int pvr2_hdw_get_unit_number(struct pvr2_hdw *);
+
+/* Get pointer to underlying USB device */
+struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *);
+
+/* Retrieve serial number of device */
+unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *);
+
+/* Called when hardware has been unplugged */
+void pvr2_hdw_disconnect(struct pvr2_hdw *);
+
+/* Get the number of defined controls */
+unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *);
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *,unsigned int);
+
+/* Retrieve a control handle given its internal ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *,unsigned int);
+
+/* Retrieve a control handle given its V4L ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *,unsigned int ctl_id);
+
+/* Retrieve a control handle given its immediate predecessor V4L ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *,
+                                           unsigned int ctl_id);
+
+/* Commit all control changes made up to this point */
+int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
+
+/* Return name for this driver instance */
+const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
+
+/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
+unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+
+/* Query device and see if it thinks it is on a high-speed USB link */
+int pvr2_hdw_is_hsm(struct pvr2_hdw *);
+
+/* Turn streaming on/off */
+int pvr2_hdw_set_streaming(struct pvr2_hdw *,int);
+
+/* Find out if streaming is on */
+int pvr2_hdw_get_streaming(struct pvr2_hdw *);
+
+/* Configure the type of stream to generate */
+int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
+
+/* Get handle to video output stream */
+struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
+
+/* Emit a video standard struct */
+int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
+                              unsigned int idx);
+
+/* Enable / disable various pieces of hardware.  Items to change are
+   identified by bit positions within msk, and new state for each item is
+   identified by corresponding bit positions within val. */
+void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
+                            unsigned long msk,unsigned long val);
+
+/* Shortcut for pvr2_hdw_subsys_bit_chg(hdw,msk,msk) */
+void pvr2_hdw_subsys_bit_set(struct pvr2_hdw *hdw,unsigned long msk);
+
+/* Shortcut for pvr2_hdw_subsys_bit_chg(hdw,msk,0) */
+void pvr2_hdw_subsys_bit_clr(struct pvr2_hdw *hdw,unsigned long msk);
+
+/* Retrieve mask indicating which pieces of hardware are currently enabled
+   / configured. */
+unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *);
+
+/* Adjust mask of what get shut down when streaming is stopped.  This is a
+   debugging aid. */
+void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
+                                   unsigned long msk,unsigned long val);
+
+/* Retrieve mask indicating which pieces of hardware are disabled when
+   streaming is turned off. */
+unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
+
+
+/* Enable / disable retrieval of CPU firmware.  This must be enabled before
+   pvr2_hdw_cpufw_get() will function.  Note that doing this may prevent
+   the device from running (and leaving this mode may imply a device
+   reset). */
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag);
+
+/* Return true if we're in a mode for retrieval CPU firmware */
+int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
+
+/* Retrieve a piece of the CPU's firmware at the given offset.  Return
+   value is the number of bytes retrieved or zero if we're past the end or
+   an error otherwise (e.g. if firmware retrieval is not enabled). */
+int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs,
+                      char *buf,unsigned int cnt);
+
+/* Retrieve previously stored v4l minor device number */
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
+
+/* Store the v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+
+
+/* The following entry points are all lower level things you normally don't
+   want to worry about. */
+
+/* Attempt to recover from a USB foul-up (in practice I find that if you
+   have to do this, then it's already too late). */
+void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw);
+
+/* Issue a command and get a response from the device.  LOTS of higher
+   level stuff is built on this. */
+int pvr2_send_request(struct pvr2_hdw *,
+                     void *write_ptr,unsigned int write_len,
+                     void *read_ptr,unsigned int read_len);
+
+/* Issue a command and get a response from the device.  This extended
+   version includes a probe flag (which if set means that device errors
+   should not be logged or treated as fatal) and a timeout in jiffies.
+   This can be used to non-lethally probe the health of endpoint 1. */
+int pvr2_send_request_ex(struct pvr2_hdw *,unsigned int timeout,int probe_fl,
+                        void *write_ptr,unsigned int write_len,
+                        void *read_ptr,unsigned int read_len);
+
+/* Slightly higher level device communication functions. */
+int pvr2_write_register(struct pvr2_hdw *, u16, u32);
+int pvr2_read_register(struct pvr2_hdw *, u16, u32 *);
+int pvr2_write_u16(struct pvr2_hdw *, u16, int);
+int pvr2_write_u8(struct pvr2_hdw *, u8, int);
+
+/* Call if for any reason we can't talk to the hardware anymore - this will
+   cause the driver to stop flailing on the device. */
+void pvr2_hdw_render_useless(struct pvr2_hdw *);
+void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *);
+
+/* Set / clear 8051's reset bit */
+void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int);
+
+/* Execute a USB-commanded device reset */
+void pvr2_hdw_device_reset(struct pvr2_hdw *);
+
+/* Execute hard reset command (after this point it's likely that the
+   encoder will have to be reconfigured).  This also clears the "useless"
+   state. */
+int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *);
+
+/* Execute simple reset command */
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *);
+
+/* Order decoder to reset */
+int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *);
+
+/* Stop / start video stream transport */
+int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
+
+/* Find I2C address of eeprom */
+int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *);
+
+/* Direct manipulation of GPIO bits */
+int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val);
+int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val);
+
+/* This data structure is specifically for the next function... */
+struct pvr2_hdw_debug_info {
+       int big_lock_held;
+       int ctl_lock_held;
+       int flag_ok;
+       int flag_disconnected;
+       int flag_init_ok;
+       int flag_streaming_enabled;
+       unsigned long subsys_flags;
+       int cmd_debug_state;
+       int cmd_debug_write_len;
+       int cmd_debug_read_len;
+       int cmd_debug_write_pend;
+       int cmd_debug_read_pend;
+       int cmd_debug_timeout;
+       int cmd_debug_rstatus;
+       int cmd_debug_wstatus;
+       unsigned char cmd_code;
+};
+
+/* Non-intrusively retrieve internal state info - this is useful for
+   diagnosing lockups.  Note that this operation is completed without any
+   kind of locking and so it is not atomic and may yield inconsistent
+   results.  This is *purely* a debugging aid. */
+void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
+                            struct pvr2_hdw_debug_info *);
+
+/* Cause modules to log their state once */
+void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
+
+/* Cause encoder firmware to be uploaded into the device.  This is normally
+   done autonomously, but the interface is exported here because it is also
+   a debugging aid. */
+int pvr2_upload_firmware2(struct pvr2_hdw *hdw);
+
+/* List of device types that we can match */
+extern struct usb_device_id pvr2_device_table[];
+
+#endif /* __PVRUSB2_HDW_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
new file mode 100644 (file)
index 0000000..1dd4f62
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+#include "pvrusb2-audio.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-demod.h"
+#include "pvrusb2-video-v4l.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-wm8775.h"
+#endif
+
+#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+
+#define OP_STANDARD 0
+#define OP_BCSH 1
+#define OP_VOLUME 2
+#define OP_FREQ 3
+#define OP_AUDIORATE 4
+#define OP_SIZE 5
+#define OP_LOG 6
+
+static const struct pvr2_i2c_op * const ops[] = {
+       [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+       [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
+       [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
+       [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
+       [OP_SIZE] = &pvr2_i2c_op_v4l2_size,
+       [OP_LOG] = &pvr2_i2c_op_v4l2_log,
+};
+
+void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       int id;
+       id = cp->client->driver->id;
+       cp->ctl_mask = ((1 << OP_STANDARD) |
+                       (1 << OP_BCSH) |
+                       (1 << OP_VOLUME) |
+                       (1 << OP_FREQ) |
+                       (1 << OP_SIZE) |
+                       (1 << OP_LOG));
+
+       if (id == I2C_DRIVERID_MSP3400) {
+               if (pvr2_i2c_msp3400_setup(hdw,cp)) {
+                       return;
+               }
+       }
+       if (id == I2C_DRIVERID_TUNER) {
+               if (pvr2_i2c_tuner_setup(hdw,cp)) {
+                       return;
+               }
+       }
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       if (id == I2C_DRIVERID_CX25840) {
+               if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
+                       return;
+               }
+       }
+       if (id == I2C_DRIVERID_WM8775) {
+               if (pvr2_i2c_wm8775_setup(hdw,cp)) {
+                       return;
+               }
+       }
+#endif
+       if (id == I2C_DRIVERID_SAA711X) {
+               if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
+                       return;
+               }
+       }
+       if (id == I2C_DRIVERID_TDA9887) {
+               if (pvr2_i2c_demod_setup(hdw,cp)) {
+                       return;
+               }
+       }
+}
+
+
+const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx)
+{
+       if (idx >= sizeof(ops)/sizeof(ops[0])) return 0;
+       return ops[idx];
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
new file mode 100644 (file)
index 0000000..9f81aff
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-i2c-cmd-v4l2.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+
+
+static void set_standard(struct pvr2_hdw *hdw)
+{
+       v4l2_std_id vs;
+       vs = hdw->std_mask_cur;
+       pvr2_trace(PVR2_TRACE_CHIPS,
+                  "i2c v4l2 set_standard(0x%llx)",(__u64)vs);
+
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+}
+
+
+static int check_standard(struct pvr2_hdw *hdw)
+{
+       return hdw->std_dirty != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard = {
+       .check = check_standard,
+       .update = set_standard,
+       .name = "v4l2_standard",
+};
+
+
+static void set_bcsh(struct pvr2_hdw *hdw)
+{
+       struct v4l2_control ctrl;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_bcsh"
+                  " b=%d c=%d s=%d h=%d",
+                  hdw->brightness_val,hdw->contrast_val,
+                  hdw->saturation_val,hdw->hue_val);
+       memset(&ctrl,0,sizeof(ctrl));
+       ctrl.id = V4L2_CID_BRIGHTNESS;
+       ctrl.value = hdw->brightness_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_CONTRAST;
+       ctrl.value = hdw->contrast_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_SATURATION;
+       ctrl.value = hdw->saturation_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_HUE;
+       ctrl.value = hdw->hue_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+}
+
+
+static int check_bcsh(struct pvr2_hdw *hdw)
+{
+       return (hdw->brightness_dirty ||
+               hdw->contrast_dirty ||
+               hdw->saturation_dirty ||
+               hdw->hue_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh = {
+       .check = check_bcsh,
+       .update = set_bcsh,
+       .name = "v4l2_bcsh",
+};
+
+
+static void set_volume(struct pvr2_hdw *hdw)
+{
+       struct v4l2_control ctrl;
+       pvr2_trace(PVR2_TRACE_CHIPS,
+                  "i2c v4l2 set_volume"
+                  "(vol=%d bal=%d bas=%d treb=%d mute=%d)",
+                  hdw->volume_val,
+                  hdw->balance_val,
+                  hdw->bass_val,
+                  hdw->treble_val,
+                  hdw->mute_val);
+       memset(&ctrl,0,sizeof(ctrl));
+       ctrl.id = V4L2_CID_AUDIO_MUTE;
+       ctrl.value = hdw->mute_val ? 1 : 0;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_AUDIO_VOLUME;
+       ctrl.value = hdw->volume_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_AUDIO_BALANCE;
+       ctrl.value = hdw->balance_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_AUDIO_BASS;
+       ctrl.value = hdw->bass_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_AUDIO_TREBLE;
+       ctrl.value = hdw->treble_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+}
+
+
+static int check_volume(struct pvr2_hdw *hdw)
+{
+       return (hdw->volume_dirty ||
+               hdw->balance_dirty ||
+               hdw->bass_dirty ||
+               hdw->treble_dirty ||
+               hdw->mute_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
+       .check = check_volume,
+       .update = set_volume,
+       .name = "v4l2_volume",
+};
+
+
+static void set_frequency(struct pvr2_hdw *hdw)
+{
+       unsigned long fv;
+       struct v4l2_frequency freq;
+       fv = hdw->freqVal;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+       memset(&freq,0,sizeof(freq));
+       freq.frequency = fv / 62500;
+       freq.tuner = 0;
+       freq.type = V4L2_TUNER_ANALOG_TV;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
+}
+
+
+static int check_frequency(struct pvr2_hdw *hdw)
+{
+       return hdw->freqDirty != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency = {
+       .check = check_frequency,
+       .update = set_frequency,
+       .name = "v4l2_freq",
+};
+
+
+static void set_size(struct pvr2_hdw *hdw)
+{
+       struct v4l2_format fmt;
+
+       memset(&fmt,0,sizeof(fmt));
+
+       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt.fmt.pix.width = hdw->res_hor_val;
+       fmt.fmt.pix.height = hdw->res_ver_val;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_size(%dx%d)",
+                          fmt.fmt.pix.width,fmt.fmt.pix.height);
+
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_FMT,&fmt);
+}
+
+
+static int check_size(struct pvr2_hdw *hdw)
+{
+       return (hdw->res_hor_dirty || hdw->res_ver_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
+       .check = check_size,
+       .update = set_size,
+       .name = "v4l2_size",
+};
+
+
+static void do_log(struct pvr2_hdw *hdw)
+{
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
+       pvr2_i2c_core_cmd(hdw,VIDIOC_LOG_STATUS,0);
+
+}
+
+
+static int check_log(struct pvr2_hdw *hdw)
+{
+       return hdw->log_requested != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = {
+       .check = check_log,
+       .update = do_log,
+       .name = "v4l2_log",
+};
+
+
+void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
+{
+       pvr2_i2c_client_cmd(cp,
+                           (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),0);
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
new file mode 100644 (file)
index 0000000..ecabddb
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_CMD_V4L2_H
+#define __PVRUSB2_CMD_V4L2_H
+
+#include "pvrusb2-i2c-core.h"
+
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
+
+void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+
+#endif /* __PVRUSB2_CMD_V4L2_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
new file mode 100644 (file)
index 0000000..c8d0bde
--- /dev/null
@@ -0,0 +1,937 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+
+/*
+
+  This module attempts to implement a compliant I2C adapter for the pvrusb2
+  device.  By doing this we can then make use of existing functionality in
+  V4L (e.g. tuner.c) rather than rolling our own.
+
+*/
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
+                         u8 i2c_addr,      /* I2C address we're talking to */
+                         u8 *data,         /* Data to write */
+                         u16 length)       /* Size of data to write */
+{
+       /* Return value - default 0 means success */
+       int ret;
+
+
+       if (!data) length = 0;
+       if (length > (sizeof(hdw->cmd_buffer) - 3)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Killing an I2C write to %u that is too large"
+                          " (desired=%u limit=%u)",
+                          i2c_addr,
+                          length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3));
+               return -ENOTSUPP;
+       }
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       /* Clear the command buffer (likely to be paranoia) */
+       memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
+
+       /* Set up command buffer for an I2C write */
+       hdw->cmd_buffer[0] = 0x08;      /* write prefix */
+       hdw->cmd_buffer[1] = i2c_addr;  /* i2c addr of chip */
+       hdw->cmd_buffer[2] = length;    /* length of what follows */
+       if (length) memcpy(hdw->cmd_buffer + 3, data, length);
+
+       /* Do the operation */
+       ret = pvr2_send_request(hdw,
+                               hdw->cmd_buffer,
+                               length + 3,
+                               hdw->cmd_buffer,
+                               1);
+       if (!ret) {
+               if (hdw->cmd_buffer[0] != 8) {
+                       ret = -EIO;
+                       if (hdw->cmd_buffer[0] != 7) {
+                               trace_i2c("unexpected status"
+                                         " from i2_write[%d]: %d",
+                                         i2c_addr,hdw->cmd_buffer[0]);
+                       }
+               }
+       }
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
+                        u8 i2c_addr,       /* I2C address we're talking to */
+                        u8 *data,          /* Data to write */
+                        u16 dlen,          /* Size of data to write */
+                        u8 *res,           /* Where to put data we read */
+                        u16 rlen)          /* Amount of data to read */
+{
+       /* Return value - default 0 means success */
+       int ret;
+
+
+       if (!data) dlen = 0;
+       if (dlen > (sizeof(hdw->cmd_buffer) - 4)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Killing an I2C read to %u that has wlen too large"
+                          " (desired=%u limit=%u)",
+                          i2c_addr,
+                          dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4));
+               return -ENOTSUPP;
+       }
+       if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Killing an I2C read to %u that has rlen too large"
+                          " (desired=%u limit=%u)",
+                          i2c_addr,
+                          rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1));
+               return -ENOTSUPP;
+       }
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       /* Clear the command buffer (likely to be paranoia) */
+       memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
+
+       /* Set up command buffer for an I2C write followed by a read */
+       hdw->cmd_buffer[0] = 0x09;  /* read prefix */
+       hdw->cmd_buffer[1] = dlen;  /* arg length */
+       hdw->cmd_buffer[2] = rlen;  /* answer length. Device will send one
+                                      more byte (status). */
+       hdw->cmd_buffer[3] = i2c_addr;  /* i2c addr of chip */
+       if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen);
+
+       /* Do the operation */
+       ret = pvr2_send_request(hdw,
+                               hdw->cmd_buffer,
+                               4 + dlen,
+                               hdw->cmd_buffer,
+                               rlen + 1);
+       if (!ret) {
+               if (hdw->cmd_buffer[0] != 8) {
+                       ret = -EIO;
+                       if (hdw->cmd_buffer[0] != 7) {
+                               trace_i2c("unexpected status"
+                                         " from i2_read[%d]: %d",
+                                         i2c_addr,hdw->cmd_buffer[0]);
+                       }
+               }
+       }
+
+       /* Copy back the result */
+       if (res && rlen) {
+               if (ret) {
+                       /* Error, just blank out the return buffer */
+                       memset(res, 0, rlen);
+               } else {
+                       memcpy(res, hdw->cmd_buffer + 1, rlen);
+               }
+       }
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+/* This is the common low level entry point for doing I2C operations to the
+   hardware. */
+int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
+                     u8 i2c_addr,
+                     u8 *wdata,
+                     u16 wlen,
+                     u8 *rdata,
+                     u16 rlen)
+{
+       if (!rdata) rlen = 0;
+       if (!wdata) wlen = 0;
+       if (rlen || !wlen) {
+               return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+       } else {
+               return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen);
+       }
+}
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+
+/* This is a special entry point that is entered if an I2C operation is
+   attempted to a wm8775 chip on model 24xxx hardware.  Autodetect of this
+   part doesn't work, but we know it is really there.  So let's look for
+   the autodetect attempt and just return success if we see that. */
+static int i2c_hack_wm8775(struct pvr2_hdw *hdw,
+                          u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+       if (!(rlen || wlen)) {
+               // This is a probe attempt.  Just let it succeed.
+               return 0;
+       }
+       return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+}
+
+/* This is a special entry point that is entered if an I2C operation is
+   attempted to a cx25840 chip on model 24xxx hardware.  This chip can
+   sometimes wedge itself.  Worse still, when this happens msp3400 can
+   falsely detect this part and then the system gets hosed up after msp3400
+   gets confused and dies.  What we want to do here is try to keep msp3400
+   away and also try to notice if the chip is wedged and send a warning to
+   the system log. */
+static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
+                           u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+       int ret;
+       unsigned int subaddr;
+       u8 wbuf[2];
+       int state = hdw->i2c_cx25840_hack_state;
+
+       if (!(rlen || wlen)) {
+               // Probe attempt - always just succeed and don't bother the
+               // hardware (this helps to make the state machine further
+               // down somewhat easier).
+               return 0;
+       }
+
+       if (state == 3) {
+               return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+       }
+
+       /* We're looking for the exact pattern where the revision register
+          is being read.  The cx25840 module will always look at the
+          revision register first.  Any other pattern of access therefore
+          has to be a probe attempt from somebody else so we'll reject it.
+          Normally we could just let each client just probe the part
+          anyway, but when the cx25840 is wedged, msp3400 will get a false
+          positive and that just screws things up... */
+
+       if (wlen == 0) {
+               switch (state) {
+               case 1: subaddr = 0x0100; break;
+               case 2: subaddr = 0x0101; break;
+               default: goto fail;
+               }
+       } else if (wlen == 2) {
+               subaddr = (wdata[0] << 8) | wdata[1];
+               switch (subaddr) {
+               case 0x0100: state = 1; break;
+               case 0x0101: state = 2; break;
+               default: goto fail;
+               }
+       } else {
+               goto fail;
+       }
+       if (!rlen) goto success;
+       state = 0;
+       if (rlen != 1) goto fail;
+
+       /* If we get to here then we have a legitimate read for one of the
+          two revision bytes, so pass it through. */
+       wbuf[0] = subaddr >> 8;
+       wbuf[1] = subaddr;
+       ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen);
+
+       if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "WARNING: Detected a wedged cx25840 chip;"
+                          " the device will not work.");
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "WARNING: Try power cycling the pvrusb2 device.");
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "WARNING: Disabling further access to the device"
+                          " to prevent other foul-ups.");
+               // This blocks all further communication with the part.
+               hdw->i2c_func[0x44] = 0;
+               pvr2_hdw_render_useless(hdw);
+               goto fail;
+       }
+
+       /* Success! */
+       pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK.");
+       state = 3;
+
+ success:
+       hdw->i2c_cx25840_hack_state = state;
+       return 0;
+
+ fail:
+       hdw->i2c_cx25840_hack_state = state;
+       return -EIO;
+}
+
+#endif /* CONFIG_VIDEO_PVRUSB2_24XXX */
+
+/* This is a very, very limited I2C adapter implementation.  We can only
+   support what we actually know will work on the device... */
+static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
+                        struct i2c_msg msgs[],
+                        int num)
+{
+       int ret = -ENOTSUPP;
+       pvr2_i2c_func funcp = 0;
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
+
+       if (!num) {
+               ret = -EINVAL;
+               goto done;
+       }
+       if ((msgs[0].flags & I2C_M_NOSTART)) {
+               trace_i2c("i2c refusing I2C_M_NOSTART");
+               goto done;
+       }
+       if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
+               funcp = hdw->i2c_func[msgs[0].addr];
+       }
+       if (!funcp) {
+               ret = -EIO;
+               goto done;
+       }
+
+       if (num == 1) {
+               if (msgs[0].flags & I2C_M_RD) {
+                       /* Simple read */
+                       u16 tcnt,bcnt,offs;
+                       if (!msgs[0].len) {
+                               /* Length == 0 read.  This is a probe. */
+                               if (funcp(hdw,msgs[0].addr,0,0,0,0)) {
+                                       ret = -EIO;
+                                       goto done;
+                               }
+                               ret = 1;
+                               goto done;
+                       }
+                       /* If the read is short enough we'll do the whole
+                          thing atomically.  Otherwise we have no choice
+                          but to break apart the reads. */
+                       tcnt = msgs[0].len;
+                       offs = 0;
+                       while (tcnt) {
+                               bcnt = tcnt;
+                               if (bcnt > sizeof(hdw->cmd_buffer)-1) {
+                                       bcnt = sizeof(hdw->cmd_buffer)-1;
+                               }
+                               if (funcp(hdw,msgs[0].addr,0,0,
+                                         msgs[0].buf+offs,bcnt)) {
+                                       ret = -EIO;
+                                       goto done;
+                               }
+                               offs += bcnt;
+                               tcnt -= bcnt;
+                       }
+                       ret = 1;
+                       goto done;
+               } else {
+                       /* Simple write */
+                       ret = 1;
+                       if (funcp(hdw,msgs[0].addr,
+                                 msgs[0].buf,msgs[0].len,0,0)) {
+                               ret = -EIO;
+                       }
+                       goto done;
+               }
+       } else if (num == 2) {
+               if (msgs[0].addr != msgs[1].addr) {
+                       trace_i2c("i2c refusing 2 phase transfer with"
+                                 " conflicting target addresses");
+                       ret = -ENOTSUPP;
+                       goto done;
+               }
+               if ((!((msgs[0].flags & I2C_M_RD))) &&
+                   (msgs[1].flags & I2C_M_RD)) {
+                       u16 tcnt,bcnt,wcnt,offs;
+                       /* Write followed by atomic read.  If the read
+                          portion is short enough we'll do the whole thing
+                          atomically.  Otherwise we have no choice but to
+                          break apart the reads. */
+                       tcnt = msgs[1].len;
+                       wcnt = msgs[0].len;
+                       offs = 0;
+                       while (tcnt || wcnt) {
+                               bcnt = tcnt;
+                               if (bcnt > sizeof(hdw->cmd_buffer)-1) {
+                                       bcnt = sizeof(hdw->cmd_buffer)-1;
+                               }
+                               if (funcp(hdw,msgs[0].addr,
+                                         msgs[0].buf,wcnt,
+                                         msgs[1].buf+offs,bcnt)) {
+                                       ret = -EIO;
+                                       goto done;
+                               }
+                               offs += bcnt;
+                               tcnt -= bcnt;
+                               wcnt = 0;
+                       }
+                       ret = 2;
+                       goto done;
+               } else {
+                       trace_i2c("i2c refusing complex transfer"
+                                 " read0=%d read1=%d",
+                                 (msgs[0].flags & I2C_M_RD),
+                                 (msgs[1].flags & I2C_M_RD));
+               }
+       } else {
+               trace_i2c("i2c refusing %d phase transfer",num);
+       }
+
+ done:
+       if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
+               unsigned int idx,offs,cnt;
+               for (idx = 0; idx < num; idx++) {
+                       cnt = msgs[idx].len;
+                       printk(KERN_INFO
+                              "pvrusb2 i2c xfer %u/%u:"
+                              " addr=0x%x len=%d %s%s",
+                              idx+1,num,
+                              msgs[idx].addr,
+                              cnt,
+                              (msgs[idx].flags & I2C_M_RD ?
+                               "read" : "write"),
+                              (msgs[idx].flags & I2C_M_NOSTART ?
+                               " nostart" : ""));
+                       if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
+                               if (cnt > 8) cnt = 8;
+                               printk(" [");
+                               for (offs = 0; offs < (cnt>8?8:cnt); offs++) {
+                                       if (offs) printk(" ");
+                                       printk("%02x",msgs[idx].buf[offs]);
+                               }
+                               if (offs < cnt) printk(" ...");
+                               printk("]");
+                       }
+                       if (idx+1 == num) {
+                               printk(" result=%d",ret);
+                       }
+                       printk("\n");
+               }
+               if (!num) {
+                       printk(KERN_INFO
+                              "pvrusb2 i2c xfer null transfer result=%d\n",
+                              ret);
+               }
+       }
+       return ret;
+}
+
+static int pvr2_i2c_control(struct i2c_adapter *adapter,
+                           unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static int pvr2_i2c_core_singleton(struct i2c_client *cp,
+                                  unsigned int cmd,void *arg)
+{
+       int stat;
+       if (!cp) return -EINVAL;
+       if (!(cp->driver)) return -EINVAL;
+       if (!(cp->driver->command)) return -EINVAL;
+       if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
+       stat = cp->driver->command(cp,cmd,arg);
+       module_put(cp->driver->driver.owner);
+       return stat;
+}
+
+int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
+{
+       int stat;
+       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+               char buf[100];
+               unsigned int cnt;
+               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+                                              buf,sizeof(buf));
+               pvr2_trace(PVR2_TRACE_I2C_CMD,
+                          "i2c COMMAND (code=%u 0x%x) to %.*s",
+                          cmd,cmd,cnt,buf);
+       }
+       stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
+       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+               char buf[100];
+               unsigned int cnt;
+               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+                                              buf,sizeof(buf));
+               pvr2_trace(PVR2_TRACE_I2C_CMD,
+                          "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
+       }
+       return stat;
+}
+
+int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
+{
+       struct list_head *item,*nc;
+       struct pvr2_i2c_client *cp;
+       int stat = -EINVAL;
+
+       if (!hdw) return stat;
+
+       mutex_lock(&hdw->i2c_list_lock);
+       list_for_each_safe(item,nc,&hdw->i2c_clients) {
+               cp = list_entry(item,struct pvr2_i2c_client,list);
+               if (!cp->recv_enable) continue;
+               mutex_unlock(&hdw->i2c_list_lock);
+               stat = pvr2_i2c_client_cmd(cp,cmd,arg);
+               mutex_lock(&hdw->i2c_list_lock);
+       }
+       mutex_unlock(&hdw->i2c_list_lock);
+       return stat;
+}
+
+
+static int handler_check(struct pvr2_i2c_client *cp)
+{
+       struct pvr2_i2c_handler *hp = cp->handler;
+       if (!hp) return 0;
+       if (!hp->func_table->check) return 0;
+       return hp->func_table->check(hp->func_data) != 0;
+}
+
+#define BUFSIZE 500
+
+void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
+{
+       unsigned long msk;
+       unsigned int idx;
+       struct list_head *item,*nc;
+       struct pvr2_i2c_client *cp;
+
+       if (!hdw->i2c_linked) return;
+       if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
+               return;
+       }
+       mutex_lock(&hdw->i2c_list_lock); do {
+               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
+                       /* One or more I2C clients have attached since we
+                          last synced.  So scan the list and identify the
+                          new clients. */
+                       char *buf;
+                       unsigned int cnt;
+                       unsigned long amask = 0;
+                       buf = kmalloc(BUFSIZE,GFP_KERNEL);
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
+                       list_for_each(item,&hdw->i2c_clients) {
+                               cp = list_entry(item,struct pvr2_i2c_client,
+                                               list);
+                               if (!cp->detected_flag) {
+                                       cp->ctl_mask = 0;
+                                       pvr2_i2c_probe(hdw,cp);
+                                       cp->detected_flag = !0;
+                                       msk = cp->ctl_mask;
+                                       cnt = 0;
+                                       if (buf) {
+                                               cnt = pvr2_i2c_client_describe(
+                                                       cp,
+                                                       PVR2_I2C_DETAIL_ALL,
+                                                       buf,BUFSIZE);
+                                       }
+                                       trace_i2c("Probed: %.*s",cnt,buf);
+                                       if (handler_check(cp)) {
+                                               hdw->i2c_pend_types |=
+                                                       PVR2_I2C_PEND_CLIENT;
+                                       }
+                                       cp->pend_mask = msk;
+                                       hdw->i2c_pend_mask |= msk;
+                                       hdw->i2c_pend_types |=
+                                               PVR2_I2C_PEND_REFRESH;
+                               }
+                               amask |= cp->ctl_mask;
+                       }
+                       hdw->i2c_active_mask = amask;
+                       if (buf) kfree(buf);
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
+                       /* Need to do one or more global updates.  Arrange
+                          for this to happen. */
+                       unsigned long m2;
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                  "i2c: PEND_STALE (0x%lx)",
+                                  hdw->i2c_stale_mask);
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
+                       list_for_each(item,&hdw->i2c_clients) {
+                               cp = list_entry(item,struct pvr2_i2c_client,
+                                               list);
+                               m2 = hdw->i2c_stale_mask;
+                               m2 &= cp->ctl_mask;
+                               m2 &= ~cp->pend_mask;
+                               if (m2) {
+                                       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                                  "i2c: cp=%p setting 0x%lx",
+                                                  cp,m2);
+                                       cp->pend_mask |= m2;
+                               }
+                       }
+                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+                       hdw->i2c_stale_mask = 0;
+                       hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
+                       /* One or more client handlers are asking for an
+                          update.  Run through the list of known clients
+                          and update each one. */
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
+                       list_for_each_safe(item,nc,&hdw->i2c_clients) {
+                               cp = list_entry(item,struct pvr2_i2c_client,
+                                               list);
+                               if (!cp->handler) continue;
+                               if (!cp->handler->func_table->update) continue;
+                               pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                          "i2c: cp=%p update",cp);
+                               mutex_unlock(&hdw->i2c_list_lock);
+                               cp->handler->func_table->update(
+                                       cp->handler->func_data);
+                               mutex_lock(&hdw->i2c_list_lock);
+                               /* If client's update function set some
+                                  additional pending bits, account for that
+                                  here. */
+                               if (cp->pend_mask & ~hdw->i2c_pend_mask) {
+                                       hdw->i2c_pend_mask |= cp->pend_mask;
+                                       hdw->i2c_pend_types |=
+                                               PVR2_I2C_PEND_REFRESH;
+                               }
+                       }
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
+                       const struct pvr2_i2c_op *opf;
+                       unsigned long pm;
+                       /* Some actual updates are pending.  Walk through
+                          each update type and perform it. */
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
+                                  " (0x%lx)",hdw->i2c_pend_mask);
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
+                       pm = hdw->i2c_pend_mask;
+                       hdw->i2c_pend_mask = 0;
+                       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+                               if (!(pm & msk)) continue;
+                               pm &= ~msk;
+                               list_for_each(item,&hdw->i2c_clients) {
+                                       cp = list_entry(item,
+                                                       struct pvr2_i2c_client,
+                                                       list);
+                                       if (cp->pend_mask & msk) {
+                                               cp->pend_mask &= ~msk;
+                                               cp->recv_enable = !0;
+                                       } else {
+                                               cp->recv_enable = 0;
+                                       }
+                               }
+                               opf = pvr2_i2c_get_op(idx);
+                               if (!opf) continue;
+                               mutex_unlock(&hdw->i2c_list_lock);
+                               opf->update(hdw);
+                               mutex_lock(&hdw->i2c_list_lock);
+                       }
+               }
+               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
+{
+       unsigned long msk,sm,pm;
+       unsigned int idx;
+       const struct pvr2_i2c_op *opf;
+       struct list_head *item;
+       struct pvr2_i2c_client *cp;
+       unsigned int pt = 0;
+
+       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
+
+       pm = hdw->i2c_active_mask;
+       sm = 0;
+       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+               if (!(msk & pm)) continue;
+               pm &= ~msk;
+               opf = pvr2_i2c_get_op(idx);
+               if (!opf) continue;
+               if (opf->check(hdw)) {
+                       sm |= msk;
+               }
+       }
+       if (sm) pt |= PVR2_I2C_PEND_STALE;
+
+       list_for_each(item,&hdw->i2c_clients) {
+               cp = list_entry(item,struct pvr2_i2c_client,list);
+               if (!handler_check(cp)) continue;
+               pt |= PVR2_I2C_PEND_CLIENT;
+       }
+
+       if (pt) {
+               mutex_lock(&hdw->i2c_list_lock); do {
+                       hdw->i2c_pend_types |= pt;
+                       hdw->i2c_stale_mask |= sm;
+                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+               } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       }
+
+       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                  "i2c: types=0x%x stale=0x%lx pend=0x%lx",
+                  hdw->i2c_pend_types,
+                  hdw->i2c_stale_mask,
+                  hdw->i2c_pend_mask);
+       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
+
+       return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
+}
+
+unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
+                                     unsigned int detail,
+                                     char *buf,unsigned int maxlen)
+{
+       unsigned int ccnt,bcnt;
+       int spcfl = 0;
+       const struct pvr2_i2c_op *opf;
+
+       ccnt = 0;
+       if (detail & PVR2_I2C_DETAIL_DEBUG) {
+               bcnt = scnprintf(buf,maxlen,
+                                "ctxt=%p ctl_mask=0x%lx",
+                                cp,cp->ctl_mask);
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               spcfl = !0;
+       }
+       bcnt = scnprintf(buf,maxlen,
+                        "%s%s @ 0x%x",
+                        (spcfl ? " " : ""),
+                        cp->client->name,
+                        cp->client->addr);
+       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
+           cp->handler && cp->handler->func_table->describe) {
+               bcnt = scnprintf(buf,maxlen," (");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               bcnt = cp->handler->func_table->describe(
+                       cp->handler->func_data,buf,maxlen);
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               bcnt = scnprintf(buf,maxlen,")");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       }
+       if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
+               unsigned int idx;
+               unsigned long msk,sm;
+               int spcfl;
+               bcnt = scnprintf(buf,maxlen," [");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               sm = 0;
+               spcfl = 0;
+               for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
+                       if (!(cp->ctl_mask & msk)) continue;
+                       opf = pvr2_i2c_get_op(idx);
+                       if (opf) {
+                               bcnt = scnprintf(buf,maxlen,"%s%s",
+                                                spcfl ? " " : "",
+                                                opf->name);
+                               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+                               spcfl = !0;
+                       } else {
+                               sm |= msk;
+                       }
+               }
+               if (sm) {
+                       bcnt = scnprintf(buf,maxlen,"%s%lx",
+                                        idx != 0 ? " " : "",sm);
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               }
+               bcnt = scnprintf(buf,maxlen,"]");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       }
+       return ccnt;
+}
+
+unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
+                            char *buf,unsigned int maxlen)
+{
+       unsigned int ccnt,bcnt;
+       struct list_head *item;
+       struct pvr2_i2c_client *cp;
+       ccnt = 0;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               list_for_each(item,&hdw->i2c_clients) {
+                       cp = list_entry(item,struct pvr2_i2c_client,list);
+                       bcnt = pvr2_i2c_client_describe(
+                               cp,
+                               (PVR2_I2C_DETAIL_HANDLER|
+                                PVR2_I2C_DETAIL_CTLMASK),
+                               buf,maxlen);
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+                       bcnt = scnprintf(buf,maxlen,"\n");
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               }
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       return ccnt;
+}
+
+static int pvr2_i2c_attach_inform(struct i2c_client *client)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+       struct pvr2_i2c_client *cp;
+       int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
+       cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+       trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
+                 client->name,
+                 client->addr,cp);
+       if (!cp) return -ENOMEM;
+       memset(cp,0,sizeof(*cp));
+       INIT_LIST_HEAD(&cp->list);
+       cp->client = client;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               list_add_tail(&cp->list,&hdw->i2c_clients);
+               hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);
+       return 0;
+}
+
+static int pvr2_i2c_detach_inform(struct i2c_client *client)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+       struct pvr2_i2c_client *cp;
+       struct list_head *item,*nc;
+       unsigned long amask = 0;
+       int foundfl = 0;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               list_for_each_safe(item,nc,&hdw->i2c_clients) {
+                       cp = list_entry(item,struct pvr2_i2c_client,list);
+                       if (cp->client == client) {
+                               trace_i2c("pvr2_i2c_detach"
+                                         " [client=%s @ 0x%x ctxt=%p]",
+                                         client->name,
+                                         client->addr,cp);
+                               if (cp->handler &&
+                                   cp->handler->func_table->detach) {
+                                       cp->handler->func_table->detach(
+                                               cp->handler->func_data);
+                               }
+                               list_del(&cp->list);
+                               kfree(cp);
+                               foundfl = !0;
+                               continue;
+                       }
+                       amask |= cp->ctl_mask;
+               }
+               hdw->i2c_active_mask = amask;
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       if (!foundfl) {
+               trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
+                         client->name,
+                         client->addr);
+       }
+       return 0;
+}
+
+static struct i2c_algorithm pvr2_i2c_algo_template = {
+       .master_xfer   = pvr2_i2c_xfer,
+       .algo_control  = pvr2_i2c_control,
+       .functionality = pvr2_i2c_functionality,
+};
+
+static struct i2c_adapter pvr2_i2c_adap_template = {
+       .owner         = THIS_MODULE,
+       .class     = I2C_CLASS_TV_ANALOG,
+       .id            = I2C_HW_B_BT848,
+       .client_register = pvr2_i2c_attach_inform,
+       .client_unregister = pvr2_i2c_detach_inform,
+};
+
+static void do_i2c_scan(struct pvr2_hdw *hdw)
+{
+       struct i2c_msg msg[1];
+       int i,rc;
+       msg[0].addr = 0;
+       msg[0].flags = I2C_M_RD;
+       msg[0].len = 0;
+       msg[0].buf = 0;
+       printk("%s: i2c scan beginning\n",hdw->name);
+       for (i = 0; i < 128; i++) {
+               msg[0].addr = i;
+               rc = i2c_transfer(&hdw->i2c_adap,msg,
+                                 sizeof(msg)/sizeof(msg[0]));
+               if (rc != 1) continue;
+               printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
+       }
+       printk("%s: i2c scan done.\n",hdw->name);
+}
+
+void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
+{
+       unsigned int idx;
+
+       // The default action for all possible I2C addresses is just to do
+       // the transfer normally.
+       for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
+               hdw->i2c_func[idx] = pvr2_i2c_basic_op;
+       }
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       // If however we're dealing with new hardware, insert some hacks in
+       // the I2C transfer stack to let things work better.
+       if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+               hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+               hdw->i2c_func[0x44] = i2c_hack_cx25840;
+       }
+#endif
+
+       // Configure the adapter and set up everything else related to it.
+       memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
+       memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
+       strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
+       hdw->i2c_adap.algo = &hdw->i2c_algo;
+       hdw->i2c_adap.algo_data = hdw;
+       hdw->i2c_pend_mask = 0;
+       hdw->i2c_stale_mask = 0;
+       hdw->i2c_active_mask = 0;
+       INIT_LIST_HEAD(&hdw->i2c_clients);
+       mutex_init(&hdw->i2c_list_lock);
+       hdw->i2c_linked = !0;
+       i2c_add_adapter(&hdw->i2c_adap);
+       if (i2c_scan) do_i2c_scan(hdw);
+}
+
+void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
+{
+       if (hdw->i2c_linked) {
+               i2c_del_adapter(&hdw->i2c_adap);
+               hdw->i2c_linked = 0;
+       }
+}
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
new file mode 100644 (file)
index 0000000..e8af5b0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_I2C_CORE_H
+#define __PVRUSB2_I2C_CORE_H
+
+#include <linux/list.h>
+#include <linux/i2c.h>
+
+struct pvr2_hdw;
+struct pvr2_i2c_client;
+struct pvr2_i2c_handler;
+struct pvr2_i2c_handler_functions;
+struct pvr2_i2c_op;
+struct pvr2_i2c_op_functions;
+
+struct pvr2_i2c_client {
+       struct i2c_client *client;
+       struct pvr2_i2c_handler *handler;
+       struct list_head list;
+       int detected_flag;
+       int recv_enable;
+       unsigned long pend_mask;
+       unsigned long ctl_mask;
+};
+
+struct pvr2_i2c_handler {
+       void *func_data;
+       const struct pvr2_i2c_handler_functions *func_table;
+};
+
+struct pvr2_i2c_handler_functions {
+       void (*detach)(void *);
+       int (*check)(void *);
+       void (*update)(void *);
+       unsigned int (*describe)(void *,char *,unsigned int);
+};
+
+struct pvr2_i2c_op {
+       int (*check)(struct pvr2_hdw *);
+       void (*update)(struct pvr2_hdw *);
+       const char *name;
+};
+
+void pvr2_i2c_core_init(struct pvr2_hdw *);
+void pvr2_i2c_core_done(struct pvr2_hdw *);
+
+int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
+int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
+
+int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
+void pvr2_i2c_core_sync(struct pvr2_hdw *);
+unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
+#define PVR2_I2C_DETAIL_DEBUG   0x0001
+#define PVR2_I2C_DETAIL_HANDLER 0x0002
+#define PVR2_I2C_DETAIL_CTLMASK 0x0004
+#define PVR2_I2C_DETAIL_ALL (\
+       PVR2_I2C_DETAIL_DEBUG |\
+       PVR2_I2C_DETAIL_HANDLER |\
+       PVR2_I2C_DETAIL_CTLMASK)
+unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *,
+                                     unsigned int detail_mask,
+                                     char *buf,unsigned int maxlen);
+
+void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
+const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
+
+#endif /* __PVRUSB2_I2C_CORE_H */
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
new file mode 100644 (file)
index 0000000..a984c91
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-io.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#define BUFFER_SIG 0x47653271
+
+// #define SANITY_CHECK_BUFFERS
+
+
+#ifdef SANITY_CHECK_BUFFERS
+#define BUFFER_CHECK(bp) do { \
+       if ((bp)->signature != BUFFER_SIG) { \
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS, \
+               "Buffer %p is bad at %s:%d", \
+               (bp),__FILE__,__LINE__); \
+               pvr2_buffer_describe(bp,"BadSig"); \
+               BUG(); \
+       } \
+} while (0)
+#else
+#define BUFFER_CHECK(bp) do {} while(0)
+#endif
+
+struct pvr2_stream {
+       /* Buffers queued for reading */
+       struct list_head queued_list;
+       unsigned int q_count;
+       unsigned int q_bcount;
+       /* Buffers with retrieved data */
+       struct list_head ready_list;
+       unsigned int r_count;
+       unsigned int r_bcount;
+       /* Buffers available for use */
+       struct list_head idle_list;
+       unsigned int i_count;
+       unsigned int i_bcount;
+       /* Pointers to all buffers */
+       struct pvr2_buffer **buffers;
+       /* Array size of buffers */
+       unsigned int buffer_slot_count;
+       /* Total buffers actually in circulation */
+       unsigned int buffer_total_count;
+       /* Designed number of buffers to be in circulation */
+       unsigned int buffer_target_count;
+       /* Executed when ready list become non-empty */
+       pvr2_stream_callback callback_func;
+       void *callback_data;
+       /* Context for transfer endpoint */
+       struct usb_device *dev;
+       int endpoint;
+       /* Overhead for mutex enforcement */
+       spinlock_t list_lock;
+       struct mutex mutex;
+       /* Tracking state for tolerating errors */
+       unsigned int fail_count;
+       unsigned int fail_tolerance;
+};
+
+struct pvr2_buffer {
+       int id;
+       int signature;
+       enum pvr2_buffer_state state;
+       void *ptr;               /* Pointer to storage area */
+       unsigned int max_count;  /* Size of storage area */
+       unsigned int used_count; /* Amount of valid data in storage area */
+       int status;              /* Transfer result status */
+       struct pvr2_stream *stream;
+       struct list_head list_overhead;
+       struct urb *purb;
+};
+
+const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st)
+{
+       switch (st) {
+       case pvr2_buffer_state_none: return "none";
+       case pvr2_buffer_state_idle: return "idle";
+       case pvr2_buffer_state_queued: return "queued";
+       case pvr2_buffer_state_ready: return "ready";
+       }
+       return "unknown";
+}
+
+void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg)
+{
+       pvr2_trace(PVR2_TRACE_INFO,
+                  "buffer%s%s %p state=%s id=%d status=%d"
+                  " stream=%p purb=%p sig=0x%x",
+                  (msg ? " " : ""),
+                  (msg ? msg : ""),
+                  bp,
+                  (bp ? pvr2_buffer_state_decode(bp->state) : "(invalid)"),
+                  (bp ? bp->id : 0),
+                  (bp ? bp->status : 0),
+                  (bp ? bp->stream : 0),
+                  (bp ? bp->purb : 0),
+                  (bp ? bp->signature : 0));
+}
+
+static void pvr2_buffer_remove(struct pvr2_buffer *bp)
+{
+       unsigned int *cnt;
+       unsigned int *bcnt;
+       unsigned int ccnt;
+       struct pvr2_stream *sp = bp->stream;
+       switch (bp->state) {
+       case pvr2_buffer_state_idle:
+               cnt = &sp->i_count;
+               bcnt = &sp->i_bcount;
+               ccnt = bp->max_count;
+               break;
+       case pvr2_buffer_state_queued:
+               cnt = &sp->q_count;
+               bcnt = &sp->q_bcount;
+               ccnt = bp->max_count;
+               break;
+       case pvr2_buffer_state_ready:
+               cnt = &sp->r_count;
+               bcnt = &sp->r_bcount;
+               ccnt = bp->used_count;
+               break;
+       default:
+               return;
+       }
+       list_del_init(&bp->list_overhead);
+       (*cnt)--;
+       (*bcnt) -= ccnt;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/"
+                  " bufferPool     %8s dec cap=%07d cnt=%02d",
+                  pvr2_buffer_state_decode(bp->state),*bcnt,*cnt);
+       bp->state = pvr2_buffer_state_none;
+}
+
+static void pvr2_buffer_set_none(struct pvr2_buffer *bp)
+{
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",
+                  bp,
+                  pvr2_buffer_state_decode(bp->state),
+                  pvr2_buffer_state_decode(pvr2_buffer_state_none));
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       pvr2_buffer_remove(bp);
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static int pvr2_buffer_set_ready(struct pvr2_buffer *bp)
+{
+       int fl;
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",
+                  bp,
+                  pvr2_buffer_state_decode(bp->state),
+                  pvr2_buffer_state_decode(pvr2_buffer_state_ready));
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       fl = (sp->r_count == 0);
+       pvr2_buffer_remove(bp);
+       list_add_tail(&bp->list_overhead,&sp->ready_list);
+       bp->state = pvr2_buffer_state_ready;
+       (sp->r_count)++;
+       sp->r_bcount += bp->used_count;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/"
+                  " bufferPool     %8s inc cap=%07d cnt=%02d",
+                  pvr2_buffer_state_decode(bp->state),
+                  sp->r_bcount,sp->r_count);
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       return fl;
+}
+
+static void pvr2_buffer_set_idle(struct pvr2_buffer *bp)
+{
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",
+                  bp,
+                  pvr2_buffer_state_decode(bp->state),
+                  pvr2_buffer_state_decode(pvr2_buffer_state_idle));
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       pvr2_buffer_remove(bp);
+       list_add_tail(&bp->list_overhead,&sp->idle_list);
+       bp->state = pvr2_buffer_state_idle;
+       (sp->i_count)++;
+       sp->i_bcount += bp->max_count;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/"
+                  " bufferPool     %8s inc cap=%07d cnt=%02d",
+                  pvr2_buffer_state_decode(bp->state),
+                  sp->i_bcount,sp->i_count);
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static void pvr2_buffer_set_queued(struct pvr2_buffer *bp)
+{
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",
+                  bp,
+                  pvr2_buffer_state_decode(bp->state),
+                  pvr2_buffer_state_decode(pvr2_buffer_state_queued));
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       pvr2_buffer_remove(bp);
+       list_add_tail(&bp->list_overhead,&sp->queued_list);
+       bp->state = pvr2_buffer_state_queued;
+       (sp->q_count)++;
+       sp->q_bcount += bp->max_count;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/"
+                  " bufferPool     %8s inc cap=%07d cnt=%02d",
+                  pvr2_buffer_state_decode(bp->state),
+                  sp->q_bcount,sp->q_count);
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static void pvr2_buffer_wipe(struct pvr2_buffer *bp)
+{
+       if (bp->state == pvr2_buffer_state_queued) {
+               usb_kill_urb(bp->purb);
+       }
+}
+
+static int pvr2_buffer_init(struct pvr2_buffer *bp,
+                           struct pvr2_stream *sp,
+                           unsigned int id)
+{
+       memset(bp,0,sizeof(*bp));
+       bp->signature = BUFFER_SIG;
+       bp->id = id;
+       pvr2_trace(PVR2_TRACE_BUF_POOL,
+                  "/*---TRACE_FLOW---*/ bufferInit     %p stream=%p",bp,sp);
+       bp->stream = sp;
+       bp->state = pvr2_buffer_state_none;
+       INIT_LIST_HEAD(&bp->list_overhead);
+       bp->purb = usb_alloc_urb(0,GFP_KERNEL);
+       if (! bp->purb) return -ENOMEM;
+#ifdef SANITY_CHECK_BUFFERS
+       pvr2_buffer_describe(bp,"create");
+#endif
+       return 0;
+}
+
+static void pvr2_buffer_done(struct pvr2_buffer *bp)
+{
+#ifdef SANITY_CHECK_BUFFERS
+       pvr2_buffer_describe(bp,"delete");
+#endif
+       pvr2_buffer_wipe(bp);
+       pvr2_buffer_set_none(bp);
+       bp->signature = 0;
+       bp->stream = 0;
+       if (bp->purb) usb_free_urb(bp->purb);
+       pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/"
+                  " bufferDone     %p",bp);
+}
+
+static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
+{
+       int ret;
+       unsigned int scnt;
+
+       /* Allocate buffers pointer array in multiples of 32 entries */
+       if (cnt == sp->buffer_total_count) return 0;
+
+       pvr2_trace(PVR2_TRACE_BUF_POOL,
+                  "/*---TRACE_FLOW---*/ poolResize    "
+                  " stream=%p cur=%d adj=%+d",
+                  sp,
+                  sp->buffer_total_count,
+                  cnt-sp->buffer_total_count);
+
+       scnt = cnt & ~0x1f;
+       if (cnt > scnt) scnt += 0x20;
+
+       if (cnt > sp->buffer_total_count) {
+               if (scnt > sp->buffer_slot_count) {
+                       struct pvr2_buffer **nb;
+                       nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+                       if (!nb) return -ENOMEM;
+                       if (sp->buffer_slot_count) {
+                               memcpy(nb,sp->buffers,
+                                      sp->buffer_slot_count * sizeof(*nb));
+                               kfree(sp->buffers);
+                       }
+                       sp->buffers = nb;
+                       sp->buffer_slot_count = scnt;
+               }
+               while (sp->buffer_total_count < cnt) {
+                       struct pvr2_buffer *bp;
+                       bp = kmalloc(sizeof(*bp),GFP_KERNEL);
+                       if (!bp) return -ENOMEM;
+                       ret = pvr2_buffer_init(bp,sp,sp->buffer_total_count);
+                       if (ret) {
+                               kfree(bp);
+                               return -ENOMEM;
+                       }
+                       sp->buffers[sp->buffer_total_count] = bp;
+                       (sp->buffer_total_count)++;
+                       pvr2_buffer_set_idle(bp);
+               }
+       } else {
+               while (sp->buffer_total_count > cnt) {
+                       struct pvr2_buffer *bp;
+                       bp = sp->buffers[sp->buffer_total_count - 1];
+                       /* Paranoia */
+                       sp->buffers[sp->buffer_total_count - 1] = 0;
+                       (sp->buffer_total_count)--;
+                       pvr2_buffer_done(bp);
+                       kfree(bp);
+               }
+               if (scnt < sp->buffer_slot_count) {
+                       struct pvr2_buffer **nb = 0;
+                       if (scnt) {
+                               nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+                               if (!nb) return -ENOMEM;
+                               memcpy(nb,sp->buffers,scnt * sizeof(*nb));
+                       }
+                       kfree(sp->buffers);
+                       sp->buffers = nb;
+                       sp->buffer_slot_count = scnt;
+               }
+       }
+       return 0;
+}
+
+static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp)
+{
+       struct pvr2_buffer *bp;
+       unsigned int cnt;
+
+       if (sp->buffer_total_count == sp->buffer_target_count) return 0;
+
+       pvr2_trace(PVR2_TRACE_BUF_POOL,
+                  "/*---TRACE_FLOW---*/"
+                  " poolCheck      stream=%p cur=%d tgt=%d",
+                  sp,sp->buffer_total_count,sp->buffer_target_count);
+
+       if (sp->buffer_total_count < sp->buffer_target_count) {
+               return pvr2_stream_buffer_count(sp,sp->buffer_target_count);
+       }
+
+       cnt = 0;
+       while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) {
+               bp = sp->buffers[sp->buffer_total_count - (cnt + 1)];
+               if (bp->state != pvr2_buffer_state_idle) break;
+               cnt++;
+       }
+       if (cnt) {
+               pvr2_stream_buffer_count(sp,sp->buffer_total_count - cnt);
+       }
+
+       return 0;
+}
+
+static void pvr2_stream_internal_flush(struct pvr2_stream *sp)
+{
+       struct list_head *lp;
+       struct pvr2_buffer *bp1;
+       while ((lp = sp->queued_list.next) != &sp->queued_list) {
+               bp1 = list_entry(lp,struct pvr2_buffer,list_overhead);
+               pvr2_buffer_wipe(bp1);
+               /* At this point, we should be guaranteed that no
+                  completion callback may happen on this buffer.  But it's
+                  possible that it might have completed after we noticed
+                  it but before we wiped it.  So double check its status
+                  here first. */
+               if (bp1->state != pvr2_buffer_state_queued) continue;
+               pvr2_buffer_set_idle(bp1);
+       }
+       if (sp->buffer_total_count != sp->buffer_target_count) {
+               pvr2_stream_achieve_buffer_count(sp);
+       }
+}
+
+static void pvr2_stream_init(struct pvr2_stream *sp)
+{
+       spin_lock_init(&sp->list_lock);
+       mutex_init(&sp->mutex);
+       INIT_LIST_HEAD(&sp->queued_list);
+       INIT_LIST_HEAD(&sp->ready_list);
+       INIT_LIST_HEAD(&sp->idle_list);
+}
+
+static void pvr2_stream_done(struct pvr2_stream *sp)
+{
+       mutex_lock(&sp->mutex); do {
+               pvr2_stream_internal_flush(sp);
+               pvr2_stream_buffer_count(sp,0);
+       } while (0); mutex_unlock(&sp->mutex);
+}
+
+static void buffer_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct pvr2_buffer *bp = urb->context;
+       struct pvr2_stream *sp;
+       unsigned long irq_flags;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       bp->used_count = 0;
+       bp->status = 0;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d",
+                  bp,urb->status,urb->actual_length);
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       if ((!(urb->status)) ||
+           (urb->status == -ENOENT) ||
+           (urb->status == -ECONNRESET) ||
+           (urb->status == -ESHUTDOWN)) {
+               bp->used_count = urb->actual_length;
+               if (sp->fail_count) {
+                       pvr2_trace(PVR2_TRACE_TOLERANCE,
+                                  "stream %p transfer ok"
+                                  " - fail count reset",sp);
+                       sp->fail_count = 0;
+               }
+       } else if (sp->fail_count < sp->fail_tolerance) {
+               // We can tolerate this error, because we're below the
+               // threshold...
+               (sp->fail_count)++;
+               pvr2_trace(PVR2_TRACE_TOLERANCE,
+                          "stream %p ignoring error %d"
+                          " - fail count increased to %u",
+                          sp,urb->status,sp->fail_count);
+       } else {
+               bp->status = urb->status;
+       }
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       pvr2_buffer_set_ready(bp);
+       if (sp && sp->callback_func) {
+               sp->callback_func(sp->callback_data);
+       }
+}
+
+struct pvr2_stream *pvr2_stream_create(void)
+{
+       struct pvr2_stream *sp;
+       sp = kmalloc(sizeof(*sp),GFP_KERNEL);
+       if (!sp) return sp;
+       memset(sp,0,sizeof(*sp));
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
+       pvr2_stream_init(sp);
+       return sp;
+}
+
+void pvr2_stream_destroy(struct pvr2_stream *sp)
+{
+       if (!sp) return;
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_destroy: sp=%p",sp);
+       pvr2_stream_done(sp);
+       kfree(sp);
+}
+
+void pvr2_stream_setup(struct pvr2_stream *sp,
+                      struct usb_device *dev,
+                      int endpoint,
+                      unsigned int tolerance)
+{
+       mutex_lock(&sp->mutex); do {
+               pvr2_stream_internal_flush(sp);
+               sp->dev = dev;
+               sp->endpoint = endpoint;
+               sp->fail_tolerance = tolerance;
+       } while(0); mutex_unlock(&sp->mutex);
+}
+
+void pvr2_stream_set_callback(struct pvr2_stream *sp,
+                             pvr2_stream_callback func,
+                             void *data)
+{
+       unsigned long irq_flags;
+       mutex_lock(&sp->mutex); do {
+               spin_lock_irqsave(&sp->list_lock,irq_flags);
+               sp->callback_data = data;
+               sp->callback_func = func;
+               spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       } while(0); mutex_unlock(&sp->mutex);
+}
+
+/* Query / set the nominal buffer count */
+int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
+{
+       return sp->buffer_target_count;
+}
+
+int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
+{
+       int ret;
+       if (sp->buffer_target_count == cnt) return 0;
+       mutex_lock(&sp->mutex); do {
+               sp->buffer_target_count = cnt;
+               ret = pvr2_stream_achieve_buffer_count(sp);
+       } while(0); mutex_unlock(&sp->mutex);
+       return ret;
+}
+
+struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp)
+{
+       struct list_head *lp = sp->idle_list.next;
+       if (lp == &sp->idle_list) return 0;
+       return list_entry(lp,struct pvr2_buffer,list_overhead);
+}
+
+struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp)
+{
+       struct list_head *lp = sp->ready_list.next;
+       if (lp == &sp->ready_list) return 0;
+       return list_entry(lp,struct pvr2_buffer,list_overhead);
+}
+
+struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id)
+{
+       if (id < 0) return 0;
+       if (id >= sp->buffer_total_count) return 0;
+       return sp->buffers[id];
+}
+
+int pvr2_stream_get_ready_count(struct pvr2_stream *sp)
+{
+       return sp->r_count;
+}
+
+int pvr2_stream_get_idle_count(struct pvr2_stream *sp)
+{
+       return sp->i_count;
+}
+
+void pvr2_stream_flush(struct pvr2_stream *sp)
+{
+       mutex_lock(&sp->mutex); do {
+               pvr2_stream_internal_flush(sp);
+       } while(0); mutex_unlock(&sp->mutex);
+}
+
+void pvr2_stream_kill(struct pvr2_stream *sp)
+{
+       struct pvr2_buffer *bp;
+       mutex_lock(&sp->mutex); do {
+               pvr2_stream_internal_flush(sp);
+               while ((bp = pvr2_stream_get_ready_buffer(sp)) != 0) {
+                       pvr2_buffer_set_idle(bp);
+               }
+               if (sp->buffer_total_count != sp->buffer_target_count) {
+                       pvr2_stream_achieve_buffer_count(sp);
+               }
+       } while(0); mutex_unlock(&sp->mutex);
+}
+
+int pvr2_buffer_queue(struct pvr2_buffer *bp)
+{
+#undef SEED_BUFFER
+#ifdef SEED_BUFFER
+       unsigned int idx;
+       unsigned int val;
+#endif
+       int ret = 0;
+       struct pvr2_stream *sp;
+       if (!bp) return -EINVAL;
+       sp = bp->stream;
+       mutex_lock(&sp->mutex); do {
+               pvr2_buffer_wipe(bp);
+               if (!sp->dev) {
+                       ret = -EIO;
+                       break;
+               }
+               pvr2_buffer_set_queued(bp);
+#ifdef SEED_BUFFER
+               for (idx = 0; idx < (bp->max_count) / 4; idx++) {
+                       val = bp->id << 24;
+                       val |= idx;
+                       ((unsigned int *)(bp->ptr))[idx] = val;
+               }
+#endif
+               bp->status = -EINPROGRESS;
+               usb_fill_bulk_urb(bp->purb,      // struct urb *urb
+                                 sp->dev,       // struct usb_device *dev
+                                 // endpoint (below)
+                                 usb_rcvbulkpipe(sp->dev,sp->endpoint),
+                                 bp->ptr,       // void *transfer_buffer
+                                 bp->max_count, // int buffer_length
+                                 buffer_complete,
+                                 bp);
+               usb_submit_urb(bp->purb,GFP_KERNEL);
+       } while(0); mutex_unlock(&sp->mutex);
+       return ret;
+}
+
+int pvr2_buffer_idle(struct pvr2_buffer *bp)
+{
+       struct pvr2_stream *sp;
+       if (!bp) return -EINVAL;
+       sp = bp->stream;
+       mutex_lock(&sp->mutex); do {
+               pvr2_buffer_wipe(bp);
+               pvr2_buffer_set_idle(bp);
+               if (sp->buffer_total_count != sp->buffer_target_count) {
+                       pvr2_stream_achieve_buffer_count(sp);
+               }
+       } while(0); mutex_unlock(&sp->mutex);
+       return 0;
+}
+
+int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt)
+{
+       int ret = 0;
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       if (!bp) return -EINVAL;
+       sp = bp->stream;
+       mutex_lock(&sp->mutex); do {
+               spin_lock_irqsave(&sp->list_lock,irq_flags);
+               if (bp->state != pvr2_buffer_state_idle) {
+                       ret = -EPERM;
+               } else {
+                       bp->ptr = ptr;
+                       bp->stream->i_bcount -= bp->max_count;
+                       bp->max_count = cnt;
+                       bp->stream->i_bcount += bp->max_count;
+                       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                                  "/*---TRACE_FLOW---*/ bufferPool    "
+                                  " %8s cap cap=%07d cnt=%02d",
+                                  pvr2_buffer_state_decode(
+                                          pvr2_buffer_state_idle),
+                                  bp->stream->i_bcount,bp->stream->i_count);
+               }
+               spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       } while(0); mutex_unlock(&sp->mutex);
+       return ret;
+}
+
+unsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp)
+{
+       return bp->used_count;
+}
+
+int pvr2_buffer_get_status(struct pvr2_buffer *bp)
+{
+       return bp->status;
+}
+
+enum pvr2_buffer_state pvr2_buffer_get_state(struct pvr2_buffer *bp)
+{
+       return bp->state;
+}
+
+int pvr2_buffer_get_id(struct pvr2_buffer *bp)
+{
+       return bp->id;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h
new file mode 100644 (file)
index 0000000..65e1138
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_IO_H
+#define __PVRUSB2_IO_H
+
+#include <linux/usb.h>
+#include <linux/list.h>
+
+typedef void (*pvr2_stream_callback)(void *);
+
+enum pvr2_buffer_state {
+       pvr2_buffer_state_none = 0,   // Not on any list
+       pvr2_buffer_state_idle = 1,   // Buffer is ready to be used again
+       pvr2_buffer_state_queued = 2, // Buffer has been queued for filling
+       pvr2_buffer_state_ready = 3,  // Buffer has data available
+};
+
+struct pvr2_stream;
+struct pvr2_buffer;
+
+const char *pvr2_buffer_state_decode(enum pvr2_buffer_state);
+
+/* Initialize / tear down stream structure */
+struct pvr2_stream *pvr2_stream_create(void);
+void pvr2_stream_destroy(struct pvr2_stream *);
+void pvr2_stream_setup(struct pvr2_stream *,
+                      struct usb_device *dev,int endpoint,
+                      unsigned int tolerance);
+void pvr2_stream_set_callback(struct pvr2_stream *,
+                             pvr2_stream_callback func,
+                             void *data);
+
+/* Query / set the nominal buffer count */
+int pvr2_stream_get_buffer_count(struct pvr2_stream *);
+int pvr2_stream_set_buffer_count(struct pvr2_stream *,unsigned int);
+
+/* Get a pointer to a buffer that is either idle, ready, or is specified
+   named. */
+struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *);
+struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *);
+struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id);
+
+/* Find out how many buffers are idle or ready */
+int pvr2_stream_get_idle_count(struct pvr2_stream *);
+int pvr2_stream_get_ready_count(struct pvr2_stream *);
+
+/* Kill all pending operations */
+void pvr2_stream_flush(struct pvr2_stream *);
+
+/* Kill all pending buffers and throw away any ready buffers as well */
+void pvr2_stream_kill(struct pvr2_stream *);
+
+/* Set up the actual storage for a buffer */
+int pvr2_buffer_set_buffer(struct pvr2_buffer *,void *ptr,unsigned int cnt);
+
+/* Find out size of data in the given ready buffer */
+unsigned int pvr2_buffer_get_count(struct pvr2_buffer *);
+
+/* Retrieve completion code for given ready buffer */
+int pvr2_buffer_get_status(struct pvr2_buffer *);
+
+/* Retrieve state of given buffer */
+enum pvr2_buffer_state pvr2_buffer_get_state(struct pvr2_buffer *);
+
+/* Retrieve ID of given buffer */
+int pvr2_buffer_get_id(struct pvr2_buffer *);
+
+/* Start reading into given buffer (kill it if needed) */
+int pvr2_buffer_queue(struct pvr2_buffer *);
+
+/* Move buffer back to idle pool (kill it if needed) */
+int pvr2_buffer_idle(struct pvr2_buffer *);
+
+#endif /* __PVRUSB2_IO_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
new file mode 100644 (file)
index 0000000..49da062
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-ioread.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+
+#define BUFFER_COUNT 32
+#define BUFFER_SIZE PAGE_ALIGN(0x4000)
+
+struct pvr2_ioread {
+       struct pvr2_stream *stream;
+       char *buffer_storage[BUFFER_COUNT];
+       char *sync_key_ptr;
+       unsigned int sync_key_len;
+       unsigned int sync_buf_offs;
+       unsigned int sync_state;
+       unsigned int sync_trashed_count;
+       int enabled;         // Streaming is on
+       int spigot_open;     // OK to pass data to client
+       int stream_running;  // Passing data to client now
+
+       /* State relevant to current buffer being read */
+       struct pvr2_buffer *c_buf;
+       char *c_data_ptr;
+       unsigned int c_data_len;
+       unsigned int c_data_offs;
+       struct mutex mutex;
+};
+
+static int pvr2_ioread_init(struct pvr2_ioread *cp)
+{
+       unsigned int idx;
+
+       cp->stream = 0;
+       mutex_init(&cp->mutex);
+
+       for (idx = 0; idx < BUFFER_COUNT; idx++) {
+               cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
+               if (!(cp->buffer_storage[idx])) break;
+       }
+
+       if (idx < BUFFER_COUNT) {
+               // An allocation appears to have failed
+               for (idx = 0; idx < BUFFER_COUNT; idx++) {
+                       if (!(cp->buffer_storage[idx])) continue;
+                       kfree(cp->buffer_storage[idx]);
+               }
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void pvr2_ioread_done(struct pvr2_ioread *cp)
+{
+       unsigned int idx;
+
+       pvr2_ioread_setup(cp,0);
+       for (idx = 0; idx < BUFFER_COUNT; idx++) {
+               if (!(cp->buffer_storage[idx])) continue;
+               kfree(cp->buffer_storage[idx]);
+       }
+}
+
+struct pvr2_ioread *pvr2_ioread_create(void)
+{
+       struct pvr2_ioread *cp;
+       cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+       if (!cp) return 0;
+       pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
+       memset(cp,0,sizeof(*cp));
+       if (pvr2_ioread_init(cp) < 0) {
+               kfree(cp);
+               return 0;
+       }
+       return cp;
+}
+
+void pvr2_ioread_destroy(struct pvr2_ioread *cp)
+{
+       if (!cp) return;
+       pvr2_ioread_done(cp);
+       pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
+       if (cp->sync_key_ptr) {
+               kfree(cp->sync_key_ptr);
+               cp->sync_key_ptr = 0;
+       }
+       kfree(cp);
+}
+
+void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
+                             const char *sync_key_ptr,
+                             unsigned int sync_key_len)
+{
+       if (!cp) return;
+
+       if (!sync_key_ptr) sync_key_len = 0;
+       if ((sync_key_len == cp->sync_key_len) &&
+           ((!sync_key_len) ||
+            (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
+
+       if (sync_key_len != cp->sync_key_len) {
+               if (cp->sync_key_ptr) {
+                       kfree(cp->sync_key_ptr);
+                       cp->sync_key_ptr = 0;
+               }
+               cp->sync_key_len = 0;
+               if (sync_key_len) {
+                       cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
+                       if (cp->sync_key_ptr) {
+                               cp->sync_key_len = sync_key_len;
+                       }
+               }
+       }
+       if (!cp->sync_key_len) return;
+       memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
+}
+
+static void pvr2_ioread_stop(struct pvr2_ioread *cp)
+{
+       if (!(cp->enabled)) return;
+       pvr2_trace(PVR2_TRACE_START_STOP,
+                  "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
+       pvr2_stream_kill(cp->stream);
+       cp->c_buf = 0;
+       cp->c_data_ptr = 0;
+       cp->c_data_len = 0;
+       cp->c_data_offs = 0;
+       cp->enabled = 0;
+       cp->stream_running = 0;
+       cp->spigot_open = 0;
+       if (cp->sync_state) {
+               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                          "/*---TRACE_READ---*/ sync_state <== 0");
+               cp->sync_state = 0;
+       }
+}
+
+static int pvr2_ioread_start(struct pvr2_ioread *cp)
+{
+       int stat;
+       struct pvr2_buffer *bp;
+       if (cp->enabled) return 0;
+       if (!(cp->stream)) return 0;
+       pvr2_trace(PVR2_TRACE_START_STOP,
+                  "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
+       while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != 0) {
+               stat = pvr2_buffer_queue(bp);
+               if (stat < 0) {
+                       pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                  "/*---TRACE_READ---*/"
+                                  " pvr2_ioread_start id=%p"
+                                  " error=%d",
+                                  cp,stat);
+                       pvr2_ioread_stop(cp);
+                       return stat;
+               }
+       }
+       cp->enabled = !0;
+       cp->c_buf = 0;
+       cp->c_data_ptr = 0;
+       cp->c_data_len = 0;
+       cp->c_data_offs = 0;
+       cp->stream_running = 0;
+       if (cp->sync_key_len) {
+               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                          "/*---TRACE_READ---*/ sync_state <== 1");
+               cp->sync_state = 1;
+               cp->sync_trashed_count = 0;
+               cp->sync_buf_offs = 0;
+       }
+       cp->spigot_open = 0;
+       return 0;
+}
+
+struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
+{
+       return cp->stream;
+}
+
+int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
+{
+       int ret;
+       unsigned int idx;
+       struct pvr2_buffer *bp;
+
+       mutex_lock(&cp->mutex); do {
+               if (cp->stream) {
+                       pvr2_trace(PVR2_TRACE_START_STOP,
+                                  "/*---TRACE_READ---*/"
+                                  " pvr2_ioread_setup (tear-down) id=%p",cp);
+                       pvr2_ioread_stop(cp);
+                       pvr2_stream_kill(cp->stream);
+                       pvr2_stream_set_buffer_count(cp->stream,0);
+                       cp->stream = 0;
+               }
+               if (sp) {
+                       pvr2_trace(PVR2_TRACE_START_STOP,
+                                  "/*---TRACE_READ---*/"
+                                  " pvr2_ioread_setup (setup) id=%p",cp);
+                       pvr2_stream_kill(sp);
+                       ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
+                       if (ret < 0) return ret;
+                       for (idx = 0; idx < BUFFER_COUNT; idx++) {
+                               bp = pvr2_stream_get_buffer(sp,idx);
+                               pvr2_buffer_set_buffer(bp,
+                                                      cp->buffer_storage[idx],
+                                                      BUFFER_SIZE);
+                       }
+                       cp->stream = sp;
+               }
+       } while (0); mutex_unlock(&cp->mutex);
+
+       return 0;
+}
+
+int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
+{
+       int ret = 0;
+       if ((!fl) == (!(cp->enabled))) return ret;
+
+       mutex_lock(&cp->mutex); do {
+               if (fl) {
+                       ret = pvr2_ioread_start(cp);
+               } else {
+                       pvr2_ioread_stop(cp);
+               }
+       } while (0); mutex_unlock(&cp->mutex);
+       return ret;
+}
+
+int pvr2_ioread_get_enabled(struct pvr2_ioread *cp)
+{
+       return cp->enabled != 0;
+}
+
+int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
+{
+       int stat;
+
+       while (cp->c_data_len <= cp->c_data_offs) {
+               if (cp->c_buf) {
+                       // Flush out current buffer first.
+                       stat = pvr2_buffer_queue(cp->c_buf);
+                       if (stat < 0) {
+                               // Streaming error...
+                               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                          "/*---TRACE_READ---*/"
+                                          " pvr2_ioread_read id=%p"
+                                          " queue_error=%d",
+                                          cp,stat);
+                               pvr2_ioread_stop(cp);
+                               return 0;
+                       }
+                       cp->c_buf = 0;
+                       cp->c_data_ptr = 0;
+                       cp->c_data_len = 0;
+                       cp->c_data_offs = 0;
+               }
+               // Now get a freshly filled buffer.
+               cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
+               if (!cp->c_buf) break; // Nothing ready; done.
+               cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
+               if (!cp->c_data_len) {
+                       // Nothing transferred.  Was there an error?
+                       stat = pvr2_buffer_get_status(cp->c_buf);
+                       if (stat < 0) {
+                               // Streaming error...
+                               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                          "/*---TRACE_READ---*/"
+                                          " pvr2_ioread_read id=%p"
+                                          " buffer_error=%d",
+                                          cp,stat);
+                               pvr2_ioread_stop(cp);
+                               // Give up.
+                               return 0;
+                       }
+                       // Start over...
+                       continue;
+               }
+               cp->c_data_offs = 0;
+               cp->c_data_ptr = cp->buffer_storage[
+                       pvr2_buffer_get_id(cp->c_buf)];
+       }
+       return !0;
+}
+
+void pvr2_ioread_filter(struct pvr2_ioread *cp)
+{
+       unsigned int idx;
+       if (!cp->enabled) return;
+       if (cp->sync_state != 1) return;
+
+       // Search the stream for our synchronization key.  This is made
+       // complicated by the fact that in order to be honest with
+       // ourselves here we must search across buffer boundaries...
+       mutex_lock(&cp->mutex); while (1) {
+               // Ensure we have a buffer
+               if (!pvr2_ioread_get_buffer(cp)) break;
+               if (!cp->c_data_len) break;
+
+               // Now walk the buffer contents until we match the key or
+               // run out of buffer data.
+               for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
+                       if (cp->sync_buf_offs >= cp->sync_key_len) break;
+                       if (cp->c_data_ptr[idx] ==
+                           cp->sync_key_ptr[cp->sync_buf_offs]) {
+                               // Found the next key byte
+                               (cp->sync_buf_offs)++;
+                       } else {
+                               // Whoops, mismatched.  Start key over...
+                               cp->sync_buf_offs = 0;
+                       }
+               }
+
+               // Consume what we've walked through
+               cp->c_data_offs += idx;
+               cp->sync_trashed_count += idx;
+
+               // If we've found the key, then update state and get out.
+               if (cp->sync_buf_offs >= cp->sync_key_len) {
+                       cp->sync_trashed_count -= cp->sync_key_len;
+                       pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                  "/*---TRACE_READ---*/"
+                                  " sync_state <== 2 (skipped %u bytes)",
+                                  cp->sync_trashed_count);
+                       cp->sync_state = 2;
+                       cp->sync_buf_offs = 0;
+                       break;
+               }
+
+               if (cp->c_data_offs < cp->c_data_len) {
+                       // Sanity check - should NEVER get here
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "ERROR: pvr2_ioread filter sync problem"
+                                  " len=%u offs=%u",
+                                  cp->c_data_len,cp->c_data_offs);
+                       // Get out so we don't get stuck in an infinite
+                       // loop.
+                       break;
+               }
+
+               continue; // (for clarity)
+       } mutex_unlock(&cp->mutex);
+}
+
+int pvr2_ioread_avail(struct pvr2_ioread *cp)
+{
+       int ret;
+       if (!(cp->enabled)) {
+               // Stream is not enabled; so this is an I/O error
+               return -EIO;
+       }
+
+       if (cp->sync_state == 1) {
+               pvr2_ioread_filter(cp);
+               if (cp->sync_state == 1) return -EAGAIN;
+       }
+
+       ret = 0;
+       if (cp->stream_running) {
+               if (!pvr2_stream_get_ready_count(cp->stream)) {
+                       // No data available at all right now.
+                       ret = -EAGAIN;
+               }
+       } else {
+               if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
+                       // Haven't buffered up enough yet; try again later
+                       ret = -EAGAIN;
+               }
+       }
+
+       if ((!(cp->spigot_open)) != (!(ret == 0))) {
+               cp->spigot_open = (ret == 0);
+               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                          "/*---TRACE_READ---*/ data is %s",
+                          cp->spigot_open ? "available" : "pending");
+       }
+
+       return ret;
+}
+
+int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
+{
+       unsigned int copied_cnt;
+       unsigned int bcnt;
+       const char *src;
+       int stat;
+       int ret = 0;
+       unsigned int req_cnt = cnt;
+
+       if (!cnt) {
+               pvr2_trace(PVR2_TRACE_TRAP,
+                          "/*---TRACE_READ---*/ pvr2_ioread_read id=%p"
+                          " ZERO Request? Returning zero.",cp);
+               return 0;
+       }
+
+       stat = pvr2_ioread_avail(cp);
+       if (stat < 0) return stat;
+
+       cp->stream_running = !0;
+
+       mutex_lock(&cp->mutex); do {
+
+               // Suck data out of the buffers and copy to the user
+               copied_cnt = 0;
+               if (!buf) cnt = 0;
+               while (1) {
+                       if (!pvr2_ioread_get_buffer(cp)) {
+                               ret = -EIO;
+                               break;
+                       }
+
+                       if (!cnt) break;
+
+                       if (cp->sync_state == 2) {
+                               // We're repeating the sync key data into
+                               // the stream.
+                               src = cp->sync_key_ptr + cp->sync_buf_offs;
+                               bcnt = cp->sync_key_len - cp->sync_buf_offs;
+                       } else {
+                               // Normal buffer copy
+                               src = cp->c_data_ptr + cp->c_data_offs;
+                               bcnt = cp->c_data_len - cp->c_data_offs;
+                       }
+
+                       if (!bcnt) break;
+
+                       // Don't run past user's buffer
+                       if (bcnt > cnt) bcnt = cnt;
+
+                       if (copy_to_user(buf,src,bcnt)) {
+                               // User supplied a bad pointer?
+                               // Give up - this *will* cause data
+                               // to be lost.
+                               ret = -EFAULT;
+                               break;
+                       }
+                       cnt -= bcnt;
+                       buf += bcnt;
+                       copied_cnt += bcnt;
+
+                       if (cp->sync_state == 2) {
+                               // Update offset inside sync key that we're
+                               // repeating back out.
+                               cp->sync_buf_offs += bcnt;
+                               if (cp->sync_buf_offs >= cp->sync_key_len) {
+                                       // Consumed entire key; switch mode
+                                       // to normal.
+                                       pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                                  "/*---TRACE_READ---*/"
+                                                  " sync_state <== 0");
+                                       cp->sync_state = 0;
+                               }
+                       } else {
+                               // Update buffer offset.
+                               cp->c_data_offs += bcnt;
+                       }
+               }
+
+       } while (0); mutex_unlock(&cp->mutex);
+
+       if (!ret) {
+               if (copied_cnt) {
+                       // If anything was copied, return that count
+                       ret = copied_cnt;
+               } else {
+                       // Nothing copied; suggest to caller that another
+                       // attempt should be tried again later
+                       ret = -EAGAIN;
+               }
+       }
+
+       pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                  "/*---TRACE_READ---*/ pvr2_ioread_read"
+                  " id=%p request=%d result=%d",
+                  cp,req_cnt,ret);
+       return ret;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.h b/drivers/media/video/pvrusb2/pvrusb2-ioread.h
new file mode 100644 (file)
index 0000000..6b00259
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_IOREAD_H
+#define __PVRUSB2_IOREAD_H
+
+#include "pvrusb2-io.h"
+
+struct pvr2_ioread;
+
+struct pvr2_ioread *pvr2_ioread_create(void);
+void pvr2_ioread_destroy(struct pvr2_ioread *);
+int pvr2_ioread_setup(struct pvr2_ioread *,struct pvr2_stream *);
+struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *);
+void pvr2_ioread_set_sync_key(struct pvr2_ioread *,
+                             const char *sync_key_ptr,
+                             unsigned int sync_key_len);
+int pvr2_ioread_set_enabled(struct pvr2_ioread *,int fl);
+int pvr2_ioread_get_enabled(struct pvr2_ioread *);
+int pvr2_ioread_read(struct pvr2_ioread *,void __user *buf,unsigned int cnt);
+int pvr2_ioread_avail(struct pvr2_ioread *);
+
+#endif /* __PVRUSB2_IOREAD_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
new file mode 100644 (file)
index 0000000..b952482
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-context.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-v4l2.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+#include "pvrusb2-sysfs.h"
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+#define DRIVER_AUTHOR "Mike Isely <isely@pobox.com>"
+#define DRIVER_DESC "Hauppauge WinTV-PVR-USB2 MPEG2 Encoder/Tuner"
+#define DRIVER_VERSION "V4L in-tree version"
+
+#define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \
+                           PVR2_TRACE_INFO| \
+                           PVR2_TRACE_TOLERANCE| \
+                           PVR2_TRACE_TRAP| \
+                           0)
+
+int pvrusb2_debug = DEFAULT_DEBUG_MASK;
+
+module_param_named(debug,pvrusb2_debug,int,S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug trace mask");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+static struct pvr2_sysfs_class *class_ptr = 0;
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+static void pvr_setup_attach(struct pvr2_context *pvr)
+{
+       /* Create association with v4l layer */
+       pvr2_v4l2_create(pvr);
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+       pvr2_sysfs_create(pvr,class_ptr);
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+}
+
+static int pvr_probe(struct usb_interface *intf,
+                    const struct usb_device_id *devid)
+{
+       struct pvr2_context *pvr;
+
+       /* Create underlying hardware interface */
+       pvr = pvr2_context_create(intf,devid,pvr_setup_attach);
+       if (!pvr) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to create hdw handler");
+               return -ENOMEM;
+       }
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_probe(pvr=%p)",pvr);
+
+       usb_set_intfdata(intf, pvr);
+
+       return 0;
+}
+
+/*
+ * pvr_disconnect()
+ *
+ */
+static void pvr_disconnect(struct usb_interface *intf)
+{
+       struct pvr2_context *pvr = usb_get_intfdata(intf);
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) BEGIN",pvr);
+
+       usb_set_intfdata (intf, NULL);
+       pvr2_context_disconnect(pvr);
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) DONE",pvr);
+
+}
+
+static struct usb_driver pvr_driver = {
+       name:           "pvrusb2",
+       id_table:       pvr2_device_table,
+       probe:          pvr_probe,
+       disconnect:     pvr_disconnect
+};
+
+/*
+ * pvr_init() / pvr_exit()
+ *
+ * This code is run to initialize/exit the driver.
+ *
+ */
+static int __init pvr_init(void)
+{
+       int ret;
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_init");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+       class_ptr = pvr2_sysfs_class_create();
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+       ret = usb_register(&pvr_driver);
+
+       if (ret == 0)
+               info(DRIVER_DESC " : " DRIVER_VERSION);
+       if (pvrusb2_debug) info("Debug mask is %d (0x%x)",
+                               pvrusb2_debug,pvrusb2_debug);
+
+       return ret;
+}
+
+static void __exit pvr_exit(void)
+{
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_exit");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+       pvr2_sysfs_class_destroy(class_ptr);
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+       usb_deregister(&pvr_driver);
+}
+
+module_init(pvr_init);
+module_exit(pvr_exit);
+
+/* Mike Isely <mcisely@pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for
+   MODULE_DEVICE_TABLE().  We have to declare that attribute there
+   because that's where the device table actually is now and it seems
+   that certain gcc configurations get angry if MODULE_DEVICE_TABLE()
+   is used on what ends up being an external symbol. */
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
new file mode 100644 (file)
index 0000000..1340636
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-std.h"
+#include "pvrusb2-debug.h"
+#include <asm/string.h>
+#include <linux/slab.h>
+
+struct std_name {
+       const char *name;
+       v4l2_std_id id;
+};
+
+
+#define CSTD_PAL \
+       (V4L2_STD_PAL_B| \
+        V4L2_STD_PAL_B1| \
+        V4L2_STD_PAL_G| \
+        V4L2_STD_PAL_H| \
+        V4L2_STD_PAL_I| \
+        V4L2_STD_PAL_D| \
+        V4L2_STD_PAL_D1| \
+        V4L2_STD_PAL_K| \
+        V4L2_STD_PAL_M| \
+        V4L2_STD_PAL_N| \
+        V4L2_STD_PAL_Nc| \
+        V4L2_STD_PAL_60)
+
+#define CSTD_NTSC \
+       (V4L2_STD_NTSC_M| \
+        V4L2_STD_NTSC_M_JP| \
+        V4L2_STD_NTSC_M_KR| \
+        V4L2_STD_NTSC_443)
+
+#define CSTD_SECAM \
+       (V4L2_STD_SECAM_B| \
+        V4L2_STD_SECAM_D| \
+        V4L2_STD_SECAM_G| \
+        V4L2_STD_SECAM_H| \
+        V4L2_STD_SECAM_K| \
+        V4L2_STD_SECAM_K1| \
+        V4L2_STD_SECAM_L| \
+        V4L2_STD_SECAM_LC)
+
+#define TSTD_B   (V4L2_STD_PAL_B|V4L2_STD_SECAM_B)
+#define TSTD_B1  (V4L2_STD_PAL_B1)
+#define TSTD_D   (V4L2_STD_PAL_D|V4L2_STD_SECAM_D)
+#define TSTD_D1  (V4L2_STD_PAL_D1)
+#define TSTD_G   (V4L2_STD_PAL_G|V4L2_STD_SECAM_G)
+#define TSTD_H   (V4L2_STD_PAL_H|V4L2_STD_SECAM_H)
+#define TSTD_I   (V4L2_STD_PAL_I)
+#define TSTD_K   (V4L2_STD_PAL_K|V4L2_STD_SECAM_K)
+#define TSTD_K1  (V4L2_STD_SECAM_K1)
+#define TSTD_L   (V4L2_STD_SECAM_L)
+#define TSTD_M   (V4L2_STD_PAL_M|V4L2_STD_NTSC_M)
+#define TSTD_N   (V4L2_STD_PAL_N)
+#define TSTD_Nc  (V4L2_STD_PAL_Nc)
+#define TSTD_60  (V4L2_STD_PAL_60)
+
+#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM)
+
+/* Mapping of standard bits to color system */
+const static struct std_name std_groups[] = {
+       {"PAL",CSTD_PAL},
+       {"NTSC",CSTD_NTSC},
+       {"SECAM",CSTD_SECAM},
+};
+
+/* Mapping of standard bits to modulation system */
+const static struct std_name std_items[] = {
+       {"B",TSTD_B},
+       {"B1",TSTD_B1},
+       {"D",TSTD_D},
+       {"D1",TSTD_D1},
+       {"G",TSTD_G},
+       {"H",TSTD_H},
+       {"I",TSTD_I},
+       {"K",TSTD_K},
+       {"K1",TSTD_K1},
+       {"L",TSTD_L},
+       {"LC",V4L2_STD_SECAM_LC},
+       {"M",TSTD_M},
+       {"Mj",V4L2_STD_NTSC_M_JP},
+       {"443",V4L2_STD_NTSC_443},
+       {"Mk",V4L2_STD_NTSC_M_KR},
+       {"N",TSTD_N},
+       {"Nc",TSTD_Nc},
+       {"60",TSTD_60},
+};
+
+
+// Search an array of std_name structures and return a pointer to the
+// element with the matching name.
+static const struct std_name *find_std_name(const struct std_name *arrPtr,
+                                           unsigned int arrSize,
+                                           const char *bufPtr,
+                                           unsigned int bufSize)
+{
+       unsigned int idx;
+       const struct std_name *p;
+       for (idx = 0; idx < arrSize; idx++) {
+               p = arrPtr + idx;
+               if (strlen(p->name) != bufSize) continue;
+               if (!memcmp(bufPtr,p->name,bufSize)) return p;
+       }
+       return 0;
+}
+
+
+int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
+                      unsigned int bufSize)
+{
+       v4l2_std_id id = 0;
+       v4l2_std_id cmsk = 0;
+       v4l2_std_id t;
+       int mMode = 0;
+       unsigned int cnt;
+       char ch;
+       const struct std_name *sp;
+
+       while (bufSize) {
+               if (!mMode) {
+                       cnt = 0;
+                       while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
+                       if (cnt >= bufSize) return 0; // No more characters
+                       sp = find_std_name(
+                               std_groups,
+                               sizeof(std_groups)/sizeof(std_groups[0]),
+                               bufPtr,cnt);
+                       if (!sp) return 0; // Illegal color system name
+                       cnt++;
+                       bufPtr += cnt;
+                       bufSize -= cnt;
+                       mMode = !0;
+                       cmsk = sp->id;
+                       continue;
+               }
+               cnt = 0;
+               while (cnt < bufSize) {
+                       ch = bufPtr[cnt];
+                       if (ch == ';') {
+                               mMode = 0;
+                               break;
+                       }
+                       if (ch == '/') break;
+                       cnt++;
+               }
+               sp = find_std_name(std_items,
+                                  sizeof(std_items)/sizeof(std_items[0]),
+                                  bufPtr,cnt);
+               if (!sp) return 0; // Illegal modulation system ID
+               t = sp->id & cmsk;
+               if (!t) return 0; // Specific color + modulation system illegal
+               id |= t;
+               if (cnt < bufSize) cnt++;
+               bufPtr += cnt;
+               bufSize -= cnt;
+       }
+
+       if (idPtr) *idPtr = id;
+       return !0;
+}
+
+
+unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
+                               v4l2_std_id id)
+{
+       unsigned int idx1,idx2;
+       const struct std_name *ip,*gp;
+       int gfl,cfl;
+       unsigned int c1,c2;
+       cfl = 0;
+       c1 = 0;
+       for (idx1 = 0;
+            idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
+            idx1++) {
+               gp = std_groups + idx1;
+               gfl = 0;
+               for (idx2 = 0;
+                    idx2 < sizeof(std_items)/sizeof(std_items[0]);
+                    idx2++) {
+                       ip = std_items + idx2;
+                       if (!(gp->id & ip->id & id)) continue;
+                       if (!gfl) {
+                               if (cfl) {
+                                       c2 = scnprintf(bufPtr,bufSize,";");
+                                       c1 += c2;
+                                       bufSize -= c2;
+                                       bufPtr += c2;
+                               }
+                               cfl = !0;
+                               c2 = scnprintf(bufPtr,bufSize,
+                                              "%s-",gp->name);
+                               gfl = !0;
+                       } else {
+                               c2 = scnprintf(bufPtr,bufSize,"/");
+                       }
+                       c1 += c2;
+                       bufSize -= c2;
+                       bufPtr += c2;
+                       c2 = scnprintf(bufPtr,bufSize,
+                                      ip->name);
+                       c1 += c2;
+                       bufSize -= c2;
+                       bufPtr += c2;
+               }
+       }
+       return c1;
+}
+
+
+// Template data for possible enumerated video standards.  Here we group
+// standards which share common frame rates and resolution.
+static struct v4l2_standard generic_standards[] = {
+       {
+               .id             = (TSTD_B|TSTD_B1|
+                                  TSTD_D|TSTD_D1|
+                                  TSTD_G|
+                                  TSTD_H|
+                                  TSTD_I|
+                                  TSTD_K|TSTD_K1|
+                                  TSTD_L|
+                                  V4L2_STD_SECAM_LC |
+                                  TSTD_N|TSTD_Nc),
+               .frameperiod    =
+               {
+                       .numerator  = 1,
+                       .denominator= 25
+               },
+               .framelines     = 625,
+               .reserved       = {0,0,0,0}
+       }, {
+               .id             = (TSTD_M|
+                                  V4L2_STD_NTSC_M_JP|
+                                  V4L2_STD_NTSC_M_KR),
+               .frameperiod    =
+               {
+                       .numerator  = 1001,
+                       .denominator= 30000
+               },
+               .framelines     = 525,
+               .reserved       = {0,0,0,0}
+       }, { // This is a total wild guess
+               .id             = (TSTD_60),
+               .frameperiod    =
+               {
+                       .numerator  = 1001,
+                       .denominator= 30000
+               },
+               .framelines     = 525,
+               .reserved       = {0,0,0,0}
+       }, { // This is total wild guess
+               .id             = V4L2_STD_NTSC_443,
+               .frameperiod    =
+               {
+                       .numerator  = 1001,
+                       .denominator= 30000
+               },
+               .framelines     = 525,
+               .reserved       = {0,0,0,0}
+       }
+};
+
+#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+
+static struct v4l2_standard *match_std(v4l2_std_id id)
+{
+       unsigned int idx;
+       for (idx = 0; idx < generic_standards_cnt; idx++) {
+               if (generic_standards[idx].id & id) {
+                       return generic_standards + idx;
+               }
+       }
+       return 0;
+}
+
+static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
+{
+       struct v4l2_standard *template;
+       int idx;
+       unsigned int bcnt;
+       template = match_std(id);
+       if (!template) return 0;
+       idx = std->index;
+       memcpy(std,template,sizeof(*template));
+       std->index = idx;
+       std->id = id;
+       bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
+       std->name[bcnt] = 0;
+       pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s",
+                  std->index,std->name);
+       return !0;
+}
+
+/* These are special cases of combined standards that we should enumerate
+   separately if the component pieces are present. */
+static v4l2_std_id std_mixes[] = {
+       V4L2_STD_PAL_B | V4L2_STD_PAL_G,
+       V4L2_STD_PAL_D | V4L2_STD_PAL_K,
+       V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
+       V4L2_STD_SECAM_D | V4L2_STD_SECAM_K,
+};
+
+struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
+                                          v4l2_std_id id)
+{
+       unsigned int std_cnt = 0;
+       unsigned int idx,bcnt,idx2;
+       v4l2_std_id idmsk,cmsk,fmsk;
+       struct v4l2_standard *stddefs;
+
+       if (pvrusb2_debug & PVR2_TRACE_INIT) {
+               char buf[50];
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
+               pvr2_trace(
+                       PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)",
+                       (int)id,bcnt,buf);
+       }
+
+       *countptr = 0;
+       std_cnt = 0;
+       fmsk = 0;
+       for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) {
+               if (!(idmsk & cmsk)) continue;
+               cmsk &= ~idmsk;
+               if (match_std(idmsk)) {
+                       std_cnt++;
+                       continue;
+               }
+               fmsk |= idmsk;
+       }
+
+       for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+               if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
+       }
+
+       if (fmsk) {
+               char buf[50];
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "WARNING:"
+                       " Failed to classify the following standard(s): %.*s",
+                       bcnt,buf);
+       }
+
+       pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)",
+                  std_cnt);
+       if (!std_cnt) return 0; // paranoia
+
+       stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+                         GFP_KERNEL);
+       memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt);
+       for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
+
+       idx = 0;
+
+       /* Enumerate potential special cases */
+       for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) &&
+                       (idx < std_cnt)); idx2++) {
+               if (!(id & std_mixes[idx2])) continue;
+               if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
+       }
+       /* Now enumerate individual pieces */
+       for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) {
+               if (!(idmsk & cmsk)) continue;
+               cmsk &= ~idmsk;
+               if (!pvr2_std_fill(stddefs+idx,idmsk)) continue;
+               idx++;
+       }
+
+       *countptr = std_cnt;
+       return stddefs;
+}
+
+v4l2_std_id pvr2_std_get_usable(void)
+{
+       return CSTD_ALL;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.h b/drivers/media/video/pvrusb2/pvrusb2-std.h
new file mode 100644 (file)
index 0000000..07c3993
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_STD_H
+#define __PVRUSB2_STD_H
+
+#include <linux/videodev2.h>
+
+// Convert string describing one or more video standards into a mask of V4L
+// standard bits.  Return true if conversion succeeds otherwise return
+// false.  String is expected to be of the form: C1-x/y;C2-a/b where C1 and
+// C2 are color system names (e.g. "PAL", "NTSC") and x, y, a, and b are
+// modulation schemes (e.g. "M", "B", "G", etc).
+int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
+                      unsigned int bufSize);
+
+// Convert any arbitrary set of video standard bits into an unambiguous
+// readable string.  Return value is the number of bytes consumed in the
+// buffer.  The formatted string is of a form that can be parsed by our
+// sibling std_std_to_id() function.
+unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
+                               v4l2_std_id id);
+
+// Create an array of suitable v4l2_standard structures given a bit mask of
+// video standards to support.  The array is allocated from the heap, and
+// the number of elements is returned in the first argument.
+struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
+                                          v4l2_std_id id);
+
+// Return mask of which video standard bits are valid
+v4l2_std_id pvr2_std_get_usable(void);
+
+#endif /* __PVRUSB2_STD_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
new file mode 100644 (file)
index 0000000..c6e6523
--- /dev/null
@@ -0,0 +1,865 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include "pvrusb2-sysfs.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+#include "pvrusb2-debugifc.h"
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__)
+
+struct pvr2_sysfs {
+       struct pvr2_channel channel;
+       struct class_device *class_dev;
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+       struct pvr2_sysfs_debugifc *debugifc;
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+       struct pvr2_sysfs_ctl_item *item_first;
+       struct pvr2_sysfs_ctl_item *item_last;
+       struct sysfs_ops kops;
+       struct kobj_type ktype;
+       struct class_device_attribute attr_v4l_minor_number;
+       struct class_device_attribute attr_unit_number;
+};
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+struct pvr2_sysfs_debugifc {
+       struct class_device_attribute attr_debugcmd;
+       struct class_device_attribute attr_debuginfo;
+};
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+struct pvr2_sysfs_ctl_item {
+       struct class_device_attribute attr_name;
+       struct class_device_attribute attr_type;
+       struct class_device_attribute attr_min;
+       struct class_device_attribute attr_max;
+       struct class_device_attribute attr_enum;
+       struct class_device_attribute attr_bits;
+       struct class_device_attribute attr_val;
+       struct class_device_attribute attr_custom;
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *chptr;
+       struct pvr2_sysfs_ctl_item *item_next;
+       struct attribute *attr_gen[7];
+       struct attribute_group grp;
+       char name[80];
+};
+
+struct pvr2_sysfs_class {
+       struct class class;
+};
+
+static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       const char *name;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+
+       name = pvr2_ctrl_get_desc(cptr);
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name);
+
+       if (!name) return -EINVAL;
+
+       return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+}
+
+static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       const char *name;
+       enum pvr2_ctl_type tp;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+
+       tp = pvr2_ctrl_get_type(cptr);
+       switch (tp) {
+       case pvr2_ctl_int: name = "integer"; break;
+       case pvr2_ctl_enum: name = "enum"; break;
+       case pvr2_ctl_bitmask: name = "bitmask"; break;
+       case pvr2_ctl_bool: name = "boolean"; break;
+       default: name = "?"; break;
+       }
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name);
+
+       if (!name) return -EINVAL;
+
+       return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+}
+
+static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       long val;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+       val = pvr2_ctrl_get_min(cptr);
+
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val);
+
+       return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+}
+
+static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       long val;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+       val = pvr2_ctrl_get_max(cptr);
+
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val);
+
+       return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+}
+
+static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       int val,ret;
+       unsigned int cnt = 0;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+
+       ret = pvr2_ctrl_get_value(cptr,&val);
+       if (ret < 0) return ret;
+
+       ret = pvr2_ctrl_value_to_sym(cptr,~0,val,
+                                    buf,PAGE_SIZE-1,&cnt);
+
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",
+                        sfp,id,cnt,buf,val);
+       buf[cnt] = '\n';
+       return cnt+1;
+}
+
+static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       int val,ret;
+       unsigned int cnt = 0;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+
+       ret = pvr2_ctrl_get_value(cptr,&val);
+       if (ret < 0) return ret;
+
+       ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val,
+                                           buf,PAGE_SIZE-1,&cnt);
+
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",
+                        sfp,id,cnt,buf,val);
+       buf[cnt] = '\n';
+       return cnt+1;
+}
+
+static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       long val;
+       unsigned int bcnt,ccnt,ecnt;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+       ecnt = pvr2_ctrl_get_cnt(cptr);
+       bcnt = 0;
+       for (val = 0; val < ecnt; val++) {
+               pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+               if (!ccnt) continue;
+               bcnt += ccnt;
+               if (bcnt >= PAGE_SIZE) break;
+               buf[bcnt] = '\n';
+               bcnt++;
+       }
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id);
+       return bcnt;
+}
+
+static ssize_t show_bits(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       int valid_bits,msk;
+       unsigned int bcnt,ccnt;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+       valid_bits = pvr2_ctrl_get_mask(cptr);
+       bcnt = 0;
+       for (msk = 1; valid_bits; msk <<= 1) {
+               if (!(msk & valid_bits)) continue;
+               valid_bits &= ~msk;
+               pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+               bcnt += ccnt;
+               if (bcnt >= PAGE_SIZE) break;
+               buf[bcnt] = '\n';
+               bcnt++;
+       }
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id);
+       return bcnt;
+}
+
+static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
+                        const char *buf,unsigned int count)
+{
+       struct pvr2_ctrl *cptr;
+       int ret;
+       int mask,val;
+
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (customfl) {
+               ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val);
+       } else {
+               ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val);
+       }
+       if (ret < 0) return ret;
+       ret = pvr2_ctrl_set_mask_value(cptr,mask,val);
+       pvr2_hdw_commit_ctl(sfp->channel.hdw);
+       return ret;
+}
+
+static ssize_t store_val_norm(int id,struct class_device *class_dev,
+                            const char *buf,size_t count)
+{
+       struct pvr2_sysfs *sfp;
+       int ret;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       ret = store_val_any(id,0,sfp,buf,count);
+       if (!ret) ret = count;
+       return ret;
+}
+
+static ssize_t store_val_custom(int id,struct class_device *class_dev,
+                               const char *buf,size_t count)
+{
+       struct pvr2_sysfs *sfp;
+       int ret;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       ret = store_val_any(id,1,sfp,buf,count);
+       if (!ret) ret = count;
+       return ret;
+}
+
+/*
+  Mike Isely <isely@pobox.com> 30-April-2005
+
+  This next batch of horrible preprocessor hackery is needed because the
+  kernel's class_device_attribute mechanism fails to pass the actual
+  attribute through to the show / store functions, which means we have no
+  way to package up any attribute-specific parameters, like for example the
+  control id.  So we work around this brain-damage by encoding the control
+  id into the show / store functions themselves and pick the function based
+  on the control id we're setting up.  These macros try to ease the pain.
+  Yuck.
+*/
+
+#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
+static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \
+{ return sf_name(ctl_id,class_dev,buf); }
+
+#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
+static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \
+{ return sf_name(ctl_id,class_dev,buf,count); }
+
+#define CREATE_BATCH(ctl_id) \
+CREATE_SHOW_INSTANCE(show_name,ctl_id) \
+CREATE_SHOW_INSTANCE(show_type,ctl_id) \
+CREATE_SHOW_INSTANCE(show_min,ctl_id) \
+CREATE_SHOW_INSTANCE(show_max,ctl_id) \
+CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \
+CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \
+CREATE_SHOW_INSTANCE(show_enum,ctl_id) \
+CREATE_SHOW_INSTANCE(show_bits,ctl_id) \
+CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \
+CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \
+
+CREATE_BATCH(0)
+CREATE_BATCH(1)
+CREATE_BATCH(2)
+CREATE_BATCH(3)
+CREATE_BATCH(4)
+CREATE_BATCH(5)
+CREATE_BATCH(6)
+CREATE_BATCH(7)
+CREATE_BATCH(8)
+CREATE_BATCH(9)
+CREATE_BATCH(10)
+CREATE_BATCH(11)
+CREATE_BATCH(12)
+CREATE_BATCH(13)
+CREATE_BATCH(14)
+CREATE_BATCH(15)
+CREATE_BATCH(16)
+CREATE_BATCH(17)
+CREATE_BATCH(18)
+CREATE_BATCH(19)
+CREATE_BATCH(20)
+CREATE_BATCH(21)
+CREATE_BATCH(22)
+CREATE_BATCH(23)
+CREATE_BATCH(24)
+CREATE_BATCH(25)
+CREATE_BATCH(26)
+CREATE_BATCH(27)
+CREATE_BATCH(28)
+CREATE_BATCH(29)
+CREATE_BATCH(30)
+CREATE_BATCH(31)
+CREATE_BATCH(32)
+CREATE_BATCH(33)
+CREATE_BATCH(34)
+CREATE_BATCH(35)
+CREATE_BATCH(36)
+CREATE_BATCH(37)
+CREATE_BATCH(38)
+CREATE_BATCH(39)
+CREATE_BATCH(40)
+CREATE_BATCH(41)
+CREATE_BATCH(42)
+CREATE_BATCH(43)
+CREATE_BATCH(44)
+CREATE_BATCH(45)
+CREATE_BATCH(46)
+CREATE_BATCH(47)
+CREATE_BATCH(48)
+CREATE_BATCH(49)
+CREATE_BATCH(50)
+CREATE_BATCH(51)
+CREATE_BATCH(52)
+CREATE_BATCH(53)
+CREATE_BATCH(54)
+CREATE_BATCH(55)
+CREATE_BATCH(56)
+CREATE_BATCH(57)
+CREATE_BATCH(58)
+CREATE_BATCH(59)
+
+struct pvr2_sysfs_func_set {
+       ssize_t (*show_name)(struct class_device *,char *);
+       ssize_t (*show_type)(struct class_device *,char *);
+       ssize_t (*show_min)(struct class_device *,char *);
+       ssize_t (*show_max)(struct class_device *,char *);
+       ssize_t (*show_enum)(struct class_device *,char *);
+       ssize_t (*show_bits)(struct class_device *,char *);
+       ssize_t (*show_val_norm)(struct class_device *,char *);
+       ssize_t (*store_val_norm)(struct class_device *,
+                                 const char *,size_t);
+       ssize_t (*show_val_custom)(struct class_device *,char *);
+       ssize_t (*store_val_custom)(struct class_device *,
+                                   const char *,size_t);
+};
+
+#define INIT_BATCH(ctl_id) \
+[ctl_id] = { \
+    .show_name = show_name_##ctl_id, \
+    .show_type = show_type_##ctl_id, \
+    .show_min = show_min_##ctl_id, \
+    .show_max = show_max_##ctl_id, \
+    .show_enum = show_enum_##ctl_id, \
+    .show_bits = show_bits_##ctl_id, \
+    .show_val_norm = show_val_norm_##ctl_id, \
+    .store_val_norm = store_val_norm_##ctl_id, \
+    .show_val_custom = show_val_custom_##ctl_id, \
+    .store_val_custom = store_val_custom_##ctl_id, \
+} \
+
+static struct pvr2_sysfs_func_set funcs[] = {
+       INIT_BATCH(0),
+       INIT_BATCH(1),
+       INIT_BATCH(2),
+       INIT_BATCH(3),
+       INIT_BATCH(4),
+       INIT_BATCH(5),
+       INIT_BATCH(6),
+       INIT_BATCH(7),
+       INIT_BATCH(8),
+       INIT_BATCH(9),
+       INIT_BATCH(10),
+       INIT_BATCH(11),
+       INIT_BATCH(12),
+       INIT_BATCH(13),
+       INIT_BATCH(14),
+       INIT_BATCH(15),
+       INIT_BATCH(16),
+       INIT_BATCH(17),
+       INIT_BATCH(18),
+       INIT_BATCH(19),
+       INIT_BATCH(20),
+       INIT_BATCH(21),
+       INIT_BATCH(22),
+       INIT_BATCH(23),
+       INIT_BATCH(24),
+       INIT_BATCH(25),
+       INIT_BATCH(26),
+       INIT_BATCH(27),
+       INIT_BATCH(28),
+       INIT_BATCH(29),
+       INIT_BATCH(30),
+       INIT_BATCH(31),
+       INIT_BATCH(32),
+       INIT_BATCH(33),
+       INIT_BATCH(34),
+       INIT_BATCH(35),
+       INIT_BATCH(36),
+       INIT_BATCH(37),
+       INIT_BATCH(38),
+       INIT_BATCH(39),
+       INIT_BATCH(40),
+       INIT_BATCH(41),
+       INIT_BATCH(42),
+       INIT_BATCH(43),
+       INIT_BATCH(44),
+       INIT_BATCH(45),
+       INIT_BATCH(46),
+       INIT_BATCH(47),
+       INIT_BATCH(48),
+       INIT_BATCH(49),
+       INIT_BATCH(50),
+       INIT_BATCH(51),
+       INIT_BATCH(52),
+       INIT_BATCH(53),
+       INIT_BATCH(54),
+       INIT_BATCH(55),
+       INIT_BATCH(56),
+       INIT_BATCH(57),
+       INIT_BATCH(58),
+       INIT_BATCH(59),
+};
+
+
+static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
+{
+       struct pvr2_sysfs_ctl_item *cip;
+       struct pvr2_sysfs_func_set *fp;
+       struct pvr2_ctrl *cptr;
+       unsigned int cnt,acnt;
+
+       if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
+               return;
+       }
+
+       fp = funcs + ctl_id;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
+       if (!cptr) return;
+
+       cip = kmalloc(sizeof(*cip),GFP_KERNEL);
+       if (!cip) return;
+       memset(cip,0,sizeof(*cip));
+       pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
+
+       cip->cptr = cptr;
+
+       cip->chptr = sfp;
+       cip->item_next = 0;
+       if (sfp->item_last) {
+               sfp->item_last->item_next = cip;
+       } else {
+               sfp->item_first = cip;
+       }
+       sfp->item_last = cip;
+
+       cip->attr_name.attr.owner = THIS_MODULE;
+       cip->attr_name.attr.name = "name";
+       cip->attr_name.attr.mode = S_IRUGO;
+       cip->attr_name.show = fp->show_name;
+
+       cip->attr_type.attr.owner = THIS_MODULE;
+       cip->attr_type.attr.name = "type";
+       cip->attr_type.attr.mode = S_IRUGO;
+       cip->attr_type.show = fp->show_type;
+
+       cip->attr_min.attr.owner = THIS_MODULE;
+       cip->attr_min.attr.name = "min_val";
+       cip->attr_min.attr.mode = S_IRUGO;
+       cip->attr_min.show = fp->show_min;
+
+       cip->attr_max.attr.owner = THIS_MODULE;
+       cip->attr_max.attr.name = "max_val";
+       cip->attr_max.attr.mode = S_IRUGO;
+       cip->attr_max.show = fp->show_max;
+
+       cip->attr_val.attr.owner = THIS_MODULE;
+       cip->attr_val.attr.name = "cur_val";
+       cip->attr_val.attr.mode = S_IRUGO;
+
+       cip->attr_custom.attr.owner = THIS_MODULE;
+       cip->attr_custom.attr.name = "custom_val";
+       cip->attr_custom.attr.mode = S_IRUGO;
+
+       cip->attr_enum.attr.owner = THIS_MODULE;
+       cip->attr_enum.attr.name = "enum_val";
+       cip->attr_enum.attr.mode = S_IRUGO;
+       cip->attr_enum.show = fp->show_enum;
+
+       cip->attr_bits.attr.owner = THIS_MODULE;
+       cip->attr_bits.attr.name = "bit_val";
+       cip->attr_bits.attr.mode = S_IRUGO;
+       cip->attr_bits.show = fp->show_bits;
+
+       if (pvr2_ctrl_is_writable(cptr)) {
+               cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;
+               cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP;
+       }
+
+       acnt = 0;
+       cip->attr_gen[acnt++] = &cip->attr_name.attr;
+       cip->attr_gen[acnt++] = &cip->attr_type.attr;
+       cip->attr_gen[acnt++] = &cip->attr_val.attr;
+       cip->attr_val.show = fp->show_val_norm;
+       cip->attr_val.store = fp->store_val_norm;
+       if (pvr2_ctrl_has_custom_symbols(cptr)) {
+               cip->attr_gen[acnt++] = &cip->attr_custom.attr;
+               cip->attr_custom.show = fp->show_val_custom;
+               cip->attr_custom.store = fp->store_val_custom;
+       }
+       switch (pvr2_ctrl_get_type(cptr)) {
+       case pvr2_ctl_enum:
+               // Control is an enumeration
+               cip->attr_gen[acnt++] = &cip->attr_enum.attr;
+               break;
+       case pvr2_ctl_int:
+               // Control is an integer
+               cip->attr_gen[acnt++] = &cip->attr_min.attr;
+               cip->attr_gen[acnt++] = &cip->attr_max.attr;
+               break;
+       case pvr2_ctl_bitmask:
+               // Control is an bitmask
+               cip->attr_gen[acnt++] = &cip->attr_bits.attr;
+               break;
+       default: break;
+       }
+
+       cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s",
+                       pvr2_ctrl_get_name(cptr));
+       cip->name[cnt] = 0;
+       cip->grp.name = cip->name;
+       cip->grp.attrs = cip->attr_gen;
+
+       sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
+}
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+static ssize_t debuginfo_show(struct class_device *,char *);
+static ssize_t debugcmd_show(struct class_device *,char *);
+static ssize_t debugcmd_store(struct class_device *,const char *,size_t count);
+
+static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
+{
+       struct pvr2_sysfs_debugifc *dip;
+       dip = kmalloc(sizeof(*dip),GFP_KERNEL);
+       if (!dip) return;
+       memset(dip,0,sizeof(*dip));
+       dip->attr_debugcmd.attr.owner = THIS_MODULE;
+       dip->attr_debugcmd.attr.name = "debugcmd";
+       dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
+       dip->attr_debugcmd.show = debugcmd_show;
+       dip->attr_debugcmd.store = debugcmd_store;
+       dip->attr_debuginfo.attr.owner = THIS_MODULE;
+       dip->attr_debuginfo.attr.name = "debuginfo";
+       dip->attr_debuginfo.attr.mode = S_IRUGO;
+       dip->attr_debuginfo.show = debuginfo_show;
+       sfp->debugifc = dip;
+       class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
+       class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+}
+
+
+static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
+{
+       if (!sfp->debugifc) return;
+       class_device_remove_file(sfp->class_dev,
+                                &sfp->debugifc->attr_debuginfo);
+       class_device_remove_file(sfp->class_dev,&sfp->debugifc->attr_debugcmd);
+       kfree(sfp->debugifc);
+       sfp->debugifc = 0;
+}
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+
+static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp)
+{
+       unsigned int idx,cnt;
+       cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw);
+       for (idx = 0; idx < cnt; idx++) {
+               pvr2_sysfs_add_control(sfp,idx);
+       }
+}
+
+
+static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp)
+{
+       struct pvr2_sysfs_ctl_item *cip1,*cip2;
+       for (cip1 = sfp->item_first; cip1; cip1 = cip2) {
+               cip2 = cip1->item_next;
+               sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
+               pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);
+               kfree(cip1);
+       }
+}
+
+
+static void pvr2_sysfs_class_release(struct class *class)
+{
+       struct pvr2_sysfs_class *clp;
+       clp = container_of(class,struct pvr2_sysfs_class,class);
+       pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp);
+       kfree(clp);
+}
+
+
+static void pvr2_sysfs_release(struct class_device *class_dev)
+{
+       pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);
+       kfree(class_dev);
+}
+
+
+static void class_dev_destroy(struct pvr2_sysfs *sfp)
+{
+       if (!sfp->class_dev) return;
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+       pvr2_sysfs_tear_down_debugifc(sfp);
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+       pvr2_sysfs_tear_down_controls(sfp);
+       class_device_remove_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
+       class_device_remove_file(sfp->class_dev,&sfp->attr_unit_number);
+       pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
+       sfp->class_dev->class_data = 0;
+       class_device_unregister(sfp->class_dev);
+       sfp->class_dev = 0;
+}
+
+
+static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       return scnprintf(buf,PAGE_SIZE,"%d\n",
+                        pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw));
+}
+
+
+static ssize_t unit_number_show(struct class_device *class_dev,char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       return scnprintf(buf,PAGE_SIZE,"%d\n",
+                        pvr2_hdw_get_unit_number(sfp->channel.hdw));
+}
+
+
+static void class_dev_create(struct pvr2_sysfs *sfp,
+                            struct pvr2_sysfs_class *class_ptr)
+{
+       struct usb_device *usb_dev;
+       struct class_device *class_dev;
+       usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
+       if (!usb_dev) return;
+       class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
+       if (!class_dev) return;
+       memset(class_dev,0,sizeof(*class_dev));
+
+       pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
+
+       class_dev->class = &class_ptr->class;
+       if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
+               snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu",
+                        pvr2_hdw_get_sn(sfp->channel.hdw));
+       } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
+               snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c",
+                        pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
+       } else {
+               kfree(class_dev);
+               return;
+       }
+
+       class_dev->dev = &usb_dev->dev;
+
+       sfp->class_dev = class_dev;
+       class_dev->class_data = sfp;
+       class_device_register(class_dev);
+
+       sfp->attr_v4l_minor_number.attr.owner = THIS_MODULE;
+       sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number";
+       sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
+       sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
+       sfp->attr_v4l_minor_number.store = 0;
+       class_device_create_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
+       sfp->attr_unit_number.attr.owner = THIS_MODULE;
+       sfp->attr_unit_number.attr.name = "unit_number";
+       sfp->attr_unit_number.attr.mode = S_IRUGO;
+       sfp->attr_unit_number.show = unit_number_show;
+       sfp->attr_unit_number.store = 0;
+       class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+
+       pvr2_sysfs_add_controls(sfp);
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+       pvr2_sysfs_add_debugifc(sfp);
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+}
+
+
+static void pvr2_sysfs_internal_check(struct pvr2_channel *chp)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = container_of(chp,struct pvr2_sysfs,channel);
+       if (!sfp->channel.mc_head->disconnect_flag) return;
+       pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp);
+       class_dev_destroy(sfp);
+       pvr2_channel_done(&sfp->channel);
+       kfree(sfp);
+}
+
+
+struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
+                                    struct pvr2_sysfs_class *class_ptr)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = kmalloc(sizeof(*sfp),GFP_KERNEL);
+       if (!sfp) return sfp;
+       memset(sfp,0,sizeof(*sfp));
+       pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
+       pvr2_channel_init(&sfp->channel,mp);
+       sfp->channel.check_func = pvr2_sysfs_internal_check;
+
+       class_dev_create(sfp,class_ptr);
+       return sfp;
+}
+
+
+static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
+                             int numenvp,char *buf,int size)
+{
+       /* Even though we don't do anything here, we still need this function
+          because sysfs will still try to call it. */
+       return 0;
+}
+
+struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
+{
+       struct pvr2_sysfs_class *clp;
+       clp = kmalloc(sizeof(*clp),GFP_KERNEL);
+       if (!clp) return clp;
+       memset(clp,0,sizeof(*clp));
+       pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
+       clp->class.name = "pvrusb2";
+       clp->class.class_release = pvr2_sysfs_class_release;
+       clp->class.release = pvr2_sysfs_release;
+       clp->class.uevent = pvr2_sysfs_hotplug;
+       if (class_register(&clp->class)) {
+               pvr2_sysfs_trace(
+                       "Registration failed for pvr2_sysfs_class id=%p",clp);
+               kfree(clp);
+               clp = 0;
+       }
+       return clp;
+}
+
+
+void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
+{
+       class_unregister(&clp->class);
+}
+
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+static ssize_t debuginfo_show(struct class_device *class_dev,char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       pvr2_hdw_trigger_module_log(sfp->channel.hdw);
+       return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
+}
+
+
+static ssize_t debugcmd_show(struct class_device *class_dev,char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
+}
+
+
+static ssize_t debugcmd_store(struct class_device *class_dev,
+                             const char *buf,size_t count)
+{
+       struct pvr2_sysfs *sfp;
+       int ret;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+
+       ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
+       if (ret < 0) return ret;
+       return count;
+}
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
new file mode 100644 (file)
index 0000000..ff9373b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_SYSFS_H
+#define __PVRUSB2_SYSFS_H
+
+#include <linux/list.h>
+#include <linux/sysfs.h>
+#include "pvrusb2-context.h"
+
+struct pvr2_sysfs;
+struct pvr2_sysfs_class;
+
+struct pvr2_sysfs_class *pvr2_sysfs_class_create(void);
+void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *);
+
+struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *,
+                                    struct pvr2_sysfs_class *);
+
+#endif /* __PVRUSB2_SYSFS_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
new file mode 100644 (file)
index 0000000..f4aba81
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2.h"
+#include "pvrusb2-util.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_tuner_handler {
+       struct pvr2_hdw *hdw;
+       struct pvr2_i2c_client *client;
+       struct pvr2_i2c_handler i2c_handler;
+       int type_update_fl;
+};
+
+
+static void set_type(struct pvr2_tuner_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       struct tuner_setup setup;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c tuner set_type(%d)",hdw->tuner_type);
+       if (((int)(hdw->tuner_type)) < 0) return;
+
+       setup.addr = ADDR_UNSET;
+       setup.type = hdw->tuner_type;
+       setup.mode_mask = T_RADIO | T_ANALOG_TV;
+       /* We may really want mode_mask to be T_ANALOG_TV for now */
+       pvr2_i2c_client_cmd(ctxt->client,TUNER_SET_TYPE_ADDR,&setup);
+       ctxt->type_update_fl = 0;
+}
+
+
+static int tuner_check(struct pvr2_tuner_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       if (hdw->tuner_updated) ctxt->type_update_fl = !0;
+       return ctxt->type_update_fl != 0;
+}
+
+
+static void tuner_update(struct pvr2_tuner_handler *ctxt)
+{
+       if (ctxt->type_update_fl) set_type(ctxt);
+}
+
+
+static void pvr2_tuner_detach(struct pvr2_tuner_handler *ctxt)
+{
+       ctxt->client->handler = 0;
+       kfree(ctxt);
+}
+
+
+static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-tuner");
+}
+
+
+const static struct pvr2_i2c_handler_functions tuner_funcs = {
+       .detach = (void (*)(void *))pvr2_tuner_detach,
+       .check = (int (*)(void *))tuner_check,
+       .update = (void (*)(void *))tuner_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_tuner_describe,
+};
+
+
+int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       struct pvr2_tuner_handler *ctxt;
+       if (cp->handler) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->i2c_handler.func_data = ctxt;
+       ctxt->i2c_handler.func_table = &tuner_funcs;
+       ctxt->type_update_fl = !0;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       cp->handler = &ctxt->i2c_handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tuner handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
new file mode 100644 (file)
index 0000000..556f12a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_TUNER_H
+#define __PVRUSB2_TUNER_H
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+#endif /* __PVRUSB2_TUNER_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-util.h b/drivers/media/video/pvrusb2/pvrusb2-util.h
new file mode 100644 (file)
index 0000000..e53aee4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_UTIL_H
+#define __PVRUSB2_UTIL_H
+
+#define PVR2_DECOMPOSE_LE(t,i,d) \
+    do {    \
+       (t)[i] = (d) & 0xff;\
+       (t)[i+1] = ((d) >> 8) & 0xff;\
+       (t)[i+2] = ((d) >> 16) & 0xff;\
+       (t)[i+3] = ((d) >> 24) & 0xff;\
+    } while(0)
+
+#define PVR2_DECOMPOSE_BE(t,i,d) \
+    do {    \
+       (t)[i+3] = (d) & 0xff;\
+       (t)[i+2] = ((d) >> 8) & 0xff;\
+       (t)[i+1] = ((d) >> 16) & 0xff;\
+       (t)[i] = ((d) >> 24) & 0xff;\
+    } while(0)
+
+#define PVR2_COMPOSE_LE(t,i) \
+    ((((u32)((t)[i+3])) << 24) | \
+     (((u32)((t)[i+2])) << 16) | \
+     (((u32)((t)[i+1])) << 8) | \
+     ((u32)((t)[i])))
+
+#define PVR2_COMPOSE_BE(t,i) \
+    ((((u32)((t)[i])) << 24) | \
+     (((u32)((t)[i+1])) << 16) | \
+     (((u32)((t)[i+2])) << 8) | \
+     ((u32)((t)[i+3])))
+
+
+#endif /* __PVRUSB2_UTIL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
new file mode 100644 (file)
index 0000000..9619510
--- /dev/null
@@ -0,0 +1,1126 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include "pvrusb2-context.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-v4l2.h"
+#include "pvrusb2-ioread.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_v4l2_dev;
+struct pvr2_v4l2_fh;
+struct pvr2_v4l2;
+
+/* V4L no longer provide the ability to set / get a private context pointer
+   (i.e. video_get_drvdata / video_set_drvdata), which means we have to
+   concoct our own context locating mechanism.  Supposedly this is intended
+   to simplify driver implementation.  It's not clear to me how that can
+   possibly be true.  Our solution here is to maintain a lookup table of
+   our context instances, indexed by the minor device number of the V4L
+   device.  See pvr2_v4l2_open() for some implications of this approach. */
+static struct pvr2_v4l2_dev *devices[256];
+static DEFINE_MUTEX(device_lock);
+
+struct pvr2_v4l2_dev {
+       struct pvr2_v4l2 *v4lp;
+       struct video_device *vdev;
+       struct pvr2_context_stream *stream;
+       int ctxt_idx;
+       enum pvr2_config config;
+};
+
+struct pvr2_v4l2_fh {
+       struct pvr2_channel channel;
+       struct pvr2_v4l2_dev *dev_info;
+       enum v4l2_priority prio;
+       struct pvr2_ioread *rhp;
+       struct file *file;
+       struct pvr2_v4l2 *vhead;
+       struct pvr2_v4l2_fh *vnext;
+       struct pvr2_v4l2_fh *vprev;
+       wait_queue_head_t wait_data;
+       int fw_mode_flag;
+};
+
+struct pvr2_v4l2 {
+       struct pvr2_channel channel;
+       struct pvr2_v4l2_fh *vfirst;
+       struct pvr2_v4l2_fh *vlast;
+
+       struct v4l2_prio_state prio;
+
+       /* streams */
+       struct pvr2_v4l2_dev video_dev;
+};
+
+static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "Offset for device's minor");
+
+struct v4l2_capability pvr_capability ={
+       .driver         = "pvrusb2",
+       .card           = "Hauppauge WinTV pvr-usb2",
+       .bus_info       = "usb",
+       .version        = KERNEL_VERSION(0,8,0),
+       .capabilities   = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+                          V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+                          V4L2_CAP_READWRITE),
+       .reserved       = {0,0,0,0}
+};
+
+static struct v4l2_tuner pvr_v4l2_tuners[]= {
+       {
+               .index      = 0,
+               .name       = "TV Tuner",
+               .type           = V4L2_TUNER_ANALOG_TV,
+               .capability     = (V4L2_TUNER_CAP_NORM |
+                                  V4L2_TUNER_CAP_STEREO |
+                                  V4L2_TUNER_CAP_LANG1 |
+                                  V4L2_TUNER_CAP_LANG2),
+               .rangelow   = 0,
+               .rangehigh  = 0,
+               .rxsubchans     = V4L2_TUNER_SUB_STEREO,
+               .audmode        = V4L2_TUNER_MODE_STEREO,
+               .signal         = 0,
+               .afc            = 0,
+               .reserved       = {0,0,0,0}
+       }
+};
+
+struct v4l2_fmtdesc pvr_fmtdesc [] = {
+       {
+               .index          = 0,
+               .type           = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               .flags          = V4L2_FMT_FLAG_COMPRESSED,
+               .description    = "MPEG1/2",
+               // This should really be V4L2_PIX_FMT_MPEG, but xawtv
+               // breaks when I do that.
+               .pixelformat    = 0, // V4L2_PIX_FMT_MPEG,
+               .reserved       = { 0, 0, 0, 0 }
+       }
+};
+
+#define PVR_FORMAT_PIX  0
+#define PVR_FORMAT_VBI  1
+
+struct v4l2_format pvr_format [] = {
+       [PVR_FORMAT_PIX] = {
+               .type   = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               .fmt    = {
+                       .pix        = {
+                               .width          = 720,
+                               .height             = 576,
+                               // This should really be V4L2_PIX_FMT_MPEG,
+                               // but xawtv breaks when I do that.
+                               .pixelformat    = 0, // V4L2_PIX_FMT_MPEG,
+                               .field          = V4L2_FIELD_INTERLACED,
+                               .bytesperline   = 0,  // doesn't make sense
+                                                     // here
+                               //FIXME : Don't know what to put here...
+                               .sizeimage          = (32*1024),
+                               .colorspace     = 0, // doesn't make sense here
+                               .priv           = 0
+                       }
+               }
+       },
+       [PVR_FORMAT_VBI] = {
+               .type   = V4L2_BUF_TYPE_VBI_CAPTURE,
+               .fmt    = {
+                       .vbi        = {
+                               .sampling_rate = 27000000,
+                               .offset = 248,
+                               .samples_per_line = 1443,
+                               .sample_format = V4L2_PIX_FMT_GREY,
+                               .start = { 0, 0 },
+                               .count = { 0, 0 },
+                               .flags = 0,
+                               .reserved = { 0, 0 }
+                       }
+               }
+       }
+};
+
+/*
+ * pvr_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ */
+static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, void *arg)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_v4l2 *vp = fh->vhead;
+       struct pvr2_v4l2_dev *dev_info = fh->dev_info;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int ret = -EINVAL;
+
+       if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
+       }
+
+       if (!pvr2_hdw_dev_ok(hdw)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "ioctl failed - bad or no context");
+               return -EFAULT;
+       }
+
+       /* check priority */
+       switch (cmd) {
+       case VIDIOC_S_CTRL:
+       case VIDIOC_S_STD:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_S_FREQUENCY:
+               ret = v4l2_prio_check(&vp->prio, &fh->prio);
+               if (ret)
+                       return ret;
+       }
+
+       switch (cmd) {
+       case VIDIOC_QUERYCAP:
+       {
+               struct v4l2_capability *cap = arg;
+
+               memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+
+               ret = 0;
+               break;
+       }
+
+       case VIDIOC_G_PRIORITY:
+       {
+               enum v4l2_priority *p = arg;
+
+               *p = v4l2_prio_max(&vp->prio);
+               ret = 0;
+               break;
+       }
+
+       case VIDIOC_S_PRIORITY:
+       {
+               enum v4l2_priority *prio = arg;
+
+               ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
+               break;
+       }
+
+       case VIDIOC_ENUMSTD:
+       {
+               struct v4l2_standard *vs = (struct v4l2_standard *)arg;
+               int idx = vs->index;
+               ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
+               break;
+       }
+
+       case VIDIOC_G_STD:
+       {
+               int val = 0;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
+               *(v4l2_std_id *)arg = val;
+               break;
+       }
+
+       case VIDIOC_S_STD:
+       {
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
+                       *(v4l2_std_id *)arg);
+               break;
+       }
+
+       case VIDIOC_ENUMINPUT:
+       {
+               struct pvr2_ctrl *cptr;
+               struct v4l2_input *vi = (struct v4l2_input *)arg;
+               struct v4l2_input tmp;
+               unsigned int cnt;
+
+               cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+
+               memset(&tmp,0,sizeof(tmp));
+               tmp.index = vi->index;
+               ret = 0;
+               switch (vi->index) {
+               case PVR2_CVAL_INPUT_TV:
+               case PVR2_CVAL_INPUT_RADIO:
+                       tmp.type = V4L2_INPUT_TYPE_TUNER;
+                       break;
+               case PVR2_CVAL_INPUT_SVIDEO:
+               case PVR2_CVAL_INPUT_COMPOSITE:
+                       tmp.type = V4L2_INPUT_TYPE_CAMERA;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               if (ret < 0) break;
+
+               cnt = 0;
+               pvr2_ctrl_get_valname(cptr,vi->index,
+                                     tmp.name,sizeof(tmp.name)-1,&cnt);
+               tmp.name[cnt] = 0;
+
+               /* Don't bother with audioset, since this driver currently
+                  always switches the audio whenever the video is
+                  switched. */
+
+               /* Handling std is a tougher problem.  It doesn't make
+                  sense in cases where a device might be multi-standard.
+                  We could just copy out the current value for the
+                  standard, but it can change over time.  For now just
+                  leave it zero. */
+
+               memcpy(vi, &tmp, sizeof(tmp));
+
+               ret = 0;
+               break;
+       }
+
+       case VIDIOC_G_INPUT:
+       {
+               struct pvr2_ctrl *cptr;
+               struct v4l2_input *vi = (struct v4l2_input *)arg;
+               int val;
+               cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+               val = 0;
+               ret = pvr2_ctrl_get_value(cptr,&val);
+               vi->index = val;
+               break;
+       }
+
+       case VIDIOC_S_INPUT:
+       {
+               struct v4l2_input *vi = (struct v4l2_input *)arg;
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+                       vi->index);
+               break;
+       }
+
+       case VIDIOC_ENUMAUDIO:
+       {
+               ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOC_G_AUDIO:
+       {
+               ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOC_S_AUDIO:
+       {
+               ret = -EINVAL;
+               break;
+       }
+       case VIDIOC_G_TUNER:
+       {
+               struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+               unsigned int status_mask;
+               int val;
+               if (vt->index !=0) break;
+
+               status_mask = pvr2_hdw_get_signal_status(hdw);
+
+               memcpy(vt, &pvr_v4l2_tuners[vt->index],
+                      sizeof(struct v4l2_tuner));
+
+               vt->signal = 0;
+               if (status_mask & PVR2_SIGNAL_OK) {
+                       if (status_mask & PVR2_SIGNAL_STEREO) {
+                               vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       } else {
+                               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       }
+                       if (status_mask & PVR2_SIGNAL_SAP) {
+                               vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
+                                                  V4L2_TUNER_SUB_LANG2);
+                       }
+                       vt->signal = 65535;
+               }
+
+               val = 0;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+                       &val);
+               vt->audmode = val;
+               break;
+       }
+
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
+
+               if (vt->index != 0)
+                       break;
+
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+                       vt->audmode);
+       }
+
+       case VIDIOC_S_FREQUENCY:
+       {
+               const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+                       vf->frequency * 62500);
+               break;
+       }
+
+       case VIDIOC_G_FREQUENCY:
+       {
+               struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+               int val = 0;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+                       &val);
+               val /= 62500;
+               vf->frequency = val;
+               break;
+       }
+
+       case VIDIOC_ENUM_FMT:
+       {
+               struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
+
+               /* Only one format is supported : mpeg.*/
+               if (fd->index != 0)
+                       break;
+
+               memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
+               ret = 0;
+               break;
+       }
+
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *vf = (struct v4l2_format *)arg;
+               int val;
+               switch(vf->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+                              sizeof(struct v4l2_format));
+                       val = 0;
+                       pvr2_ctrl_get_value(
+                               pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
+                               &val);
+                       vf->fmt.pix.width = val;
+                       val = 0;
+                       pvr2_ctrl_get_value(
+                               pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
+                               &val);
+                       vf->fmt.pix.height = val;
+                       ret = 0;
+                       break;
+               case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       // ????? Still need to figure out to do VBI correctly
+                       ret = -EINVAL;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       }
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *vf = (struct v4l2_format *)arg;
+
+               ret = 0;
+               switch(vf->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+                       int h = vf->fmt.pix.height;
+                       int w = vf->fmt.pix.width;
+
+                       if (h < 200) {
+                               h = 200;
+                       } else if (h > 625) {
+                               h = 625;
+                       }
+                       if (w < 320) {
+                               w = 320;
+                       } else if (w > 720) {
+                               w = 720;
+                       }
+
+                       memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+                              sizeof(struct v4l2_format));
+                       vf->fmt.pix.width = w;
+                       vf->fmt.pix.height = h;
+
+                       if (cmd == VIDIOC_S_FMT) {
+                               pvr2_ctrl_set_value(
+                                       pvr2_hdw_get_ctrl_by_id(hdw,
+                                                               PVR2_CID_HRES),
+                                       vf->fmt.pix.width);
+                               pvr2_ctrl_set_value(
+                                       pvr2_hdw_get_ctrl_by_id(hdw,
+                                                               PVR2_CID_VRES),
+                                       vf->fmt.pix.height);
+                       }
+               } break;
+               case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       // ????? Still need to figure out to do VBI correctly
+                       ret = -EINVAL;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       }
+
+       case VIDIOC_STREAMON:
+       {
+               ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
+               if (ret < 0) return ret;
+               ret = pvr2_hdw_set_streaming(hdw,!0);
+               break;
+       }
+
+       case VIDIOC_STREAMOFF:
+       {
+               ret = pvr2_hdw_set_streaming(hdw,0);
+               break;
+       }
+
+       case VIDIOC_QUERYCTRL:
+       {
+               struct pvr2_ctrl *cptr;
+               struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
+               ret = 0;
+               if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+                       cptr = pvr2_hdw_get_ctrl_nextv4l(
+                               hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
+                       if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
+               } else {
+                       cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
+               }
+               if (!cptr) {
+                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                  "QUERYCTRL id=0x%x not implemented here",
+                                  vc->id);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                          "QUERYCTRL id=0x%x mapping name=%s (%s)",
+                          vc->id,pvr2_ctrl_get_name(cptr),
+                          pvr2_ctrl_get_desc(cptr));
+               strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
+               vc->flags = pvr2_ctrl_get_v4lflags(cptr);
+               vc->default_value = pvr2_ctrl_get_def(cptr);
+               switch (pvr2_ctrl_get_type(cptr)) {
+               case pvr2_ctl_enum:
+                       vc->type = V4L2_CTRL_TYPE_MENU;
+                       vc->minimum = 0;
+                       vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
+                       vc->step = 1;
+                       break;
+               case pvr2_ctl_bool:
+                       vc->type = V4L2_CTRL_TYPE_BOOLEAN;
+                       vc->minimum = 0;
+                       vc->maximum = 1;
+                       vc->step = 1;
+                       break;
+               case pvr2_ctl_int:
+                       vc->type = V4L2_CTRL_TYPE_INTEGER;
+                       vc->minimum = pvr2_ctrl_get_min(cptr);
+                       vc->maximum = pvr2_ctrl_get_max(cptr);
+                       vc->step = 1;
+                       break;
+               default:
+                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                  "QUERYCTRL id=0x%x name=%s not mappable",
+                                  vc->id,pvr2_ctrl_get_name(cptr));
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       }
+
+       case VIDIOC_QUERYMENU:
+       {
+               struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
+               unsigned int cnt = 0;
+               ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
+                                           vm->index,
+                                           vm->name,sizeof(vm->name)-1,
+                                           &cnt);
+               vm->name[cnt] = 0;
+               break;
+       }
+
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *vc = (struct v4l2_control *)arg;
+               int val = 0;
+               ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
+                                         &val);
+               vc->value = val;
+               break;
+       }
+
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *vc = (struct v4l2_control *)arg;
+               ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
+                                         vc->value);
+               break;
+       }
+
+       case VIDIOC_G_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *ctls =
+                       (struct v4l2_ext_controls *)arg;
+               struct v4l2_ext_control *ctrl;
+               unsigned int idx;
+               int val;
+               for (idx = 0; idx < ctls->count; idx++) {
+                       ctrl = ctls->controls + idx;
+                       ret = pvr2_ctrl_get_value(
+                               pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
+                       if (ret) {
+                               ctls->error_idx = idx;
+                               break;
+                       }
+                       /* Ensure that if read as a 64 bit value, the user
+                          will still get a hopefully sane value */
+                       ctrl->value64 = 0;
+                       ctrl->value = val;
+               }
+               break;
+       }
+
+       case VIDIOC_S_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *ctls =
+                       (struct v4l2_ext_controls *)arg;
+               struct v4l2_ext_control *ctrl;
+               unsigned int idx;
+               for (idx = 0; idx < ctls->count; idx++) {
+                       ctrl = ctls->controls + idx;
+                       ret = pvr2_ctrl_set_value(
+                               pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
+                               ctrl->value);
+                       if (ret) {
+                               ctls->error_idx = idx;
+                               break;
+                       }
+               }
+               break;
+       }
+
+       case VIDIOC_TRY_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *ctls =
+                       (struct v4l2_ext_controls *)arg;
+               struct v4l2_ext_control *ctrl;
+               struct pvr2_ctrl *pctl;
+               unsigned int idx;
+               /* For the moment just validate that the requested control
+                  actually exists. */
+               for (idx = 0; idx < ctls->count; idx++) {
+                       ctrl = ctls->controls + idx;
+                       pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
+                       if (!pctl) {
+                               ret = -EINVAL;
+                               ctls->error_idx = idx;
+                               break;
+                       }
+               }
+               break;
+       }
+
+       case VIDIOC_LOG_STATUS:
+       {
+               pvr2_hdw_trigger_module_log(hdw);
+               ret = 0;
+               break;
+       }
+
+       default :
+               ret = v4l_compat_translate_ioctl(inode,file,cmd,
+                                                arg,pvr2_v4l2_do_ioctl);
+       }
+
+       pvr2_hdw_commit_ctl(hdw);
+
+       if (ret < 0) {
+               if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                  "pvr2_v4l2_do_ioctl failure, ret=%d",ret);
+               } else {
+                       if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+                               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                          "pvr2_v4l2_do_ioctl failure, ret=%d"
+                                          " command was:",ret);
+                               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
+                                               cmd);
+                       }
+               }
+       } else {
+               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                          "pvr2_v4l2_do_ioctl complete, ret=%d (0x%x)",
+                          ret,ret);
+       }
+       return ret;
+}
+
+
+static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
+{
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "unregistering device video%d [%s]",
+                  dip->vdev->minor,pvr2_config_get_name(dip->config));
+       if (dip->ctxt_idx >= 0) {
+               mutex_lock(&device_lock);
+               devices[dip->ctxt_idx] = NULL;
+               dip->ctxt_idx = -1;
+               mutex_unlock(&device_lock);
+       }
+       video_unregister_device(dip->vdev);
+}
+
+
+static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
+{
+       pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
+       pvr2_v4l2_dev_destroy(&vp->video_dev);
+
+       pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
+       pvr2_channel_done(&vp->channel);
+       kfree(vp);
+}
+
+
+void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
+{
+       struct pvr2_v4l2 *vp;
+       vp = container_of(chp,struct pvr2_v4l2,channel);
+       if (!vp->channel.mc_head->disconnect_flag) return;
+       if (vp->vfirst) return;
+       pvr2_v4l2_destroy_no_lock(vp);
+}
+
+
+int pvr2_v4l2_ioctl(struct inode *inode, struct file *file,
+                   unsigned int cmd, unsigned long arg)
+{
+
+/* Temporary hack : use ivtv api until a v4l2 one is available. */
+#define IVTV_IOC_G_CODEC        0xFFEE7703
+#define IVTV_IOC_S_CODEC        0xFFEE7704
+       if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;
+       return video_usercopy(inode, file, cmd, arg, pvr2_v4l2_do_ioctl);
+}
+
+
+int pvr2_v4l2_release(struct inode *inode, struct file *file)
+{
+       struct pvr2_v4l2_fh *fhp = file->private_data;
+       struct pvr2_v4l2 *vp = fhp->vhead;
+       struct pvr2_context *mp = fhp->vhead->channel.mc_head;
+
+       pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
+
+       if (fhp->rhp) {
+               struct pvr2_stream *sp;
+               struct pvr2_hdw *hdw;
+               hdw = fhp->channel.mc_head->hdw;
+               pvr2_hdw_set_streaming(hdw,0);
+               sp = pvr2_ioread_get_stream(fhp->rhp);
+               if (sp) pvr2_stream_set_callback(sp,0,0);
+               pvr2_ioread_destroy(fhp->rhp);
+               fhp->rhp = 0;
+       }
+       v4l2_prio_close(&vp->prio, &fhp->prio);
+       file->private_data = NULL;
+
+       pvr2_context_enter(mp); do {
+               if (fhp->vnext) {
+                       fhp->vnext->vprev = fhp->vprev;
+               } else {
+                       vp->vlast = fhp->vprev;
+               }
+               if (fhp->vprev) {
+                       fhp->vprev->vnext = fhp->vnext;
+               } else {
+                       vp->vfirst = fhp->vnext;
+               }
+               fhp->vnext = 0;
+               fhp->vprev = 0;
+               fhp->vhead = 0;
+               pvr2_channel_done(&fhp->channel);
+               pvr2_trace(PVR2_TRACE_STRUCT,
+                          "Destroying pvr_v4l2_fh id=%p",fhp);
+               kfree(fhp);
+               if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
+                       pvr2_v4l2_destroy_no_lock(vp);
+               }
+       } while (0); pvr2_context_exit(mp);
+       return 0;
+}
+
+
+int pvr2_v4l2_open(struct inode *inode, struct file *file)
+{
+       struct pvr2_v4l2_dev *dip = 0; /* Our own context pointer */
+       struct pvr2_v4l2_fh *fhp;
+       struct pvr2_v4l2 *vp;
+       struct pvr2_hdw *hdw;
+
+       mutex_lock(&device_lock);
+       /* MCI 7-Jun-2006 Even though we're just doing what amounts to an
+          atomic read of the device mapping array here, we still need the
+          mutex.  The problem is that there is a tiny race possible when
+          we register the device.  We can't update the device mapping
+          array until after the device has been registered, owing to the
+          fact that we can't know the minor device number until after the
+          registration succeeds.  And if another thread tries to open the
+          device in the window of time after registration but before the
+          map is updated, then it will get back an erroneous null pointer
+          and the open will result in a spurious failure.  The only way to
+          prevent that is to (a) be inside the mutex here before we access
+          the array, and (b) cover the entire registration process later
+          on with this same mutex.  Thus if we get inside the mutex here,
+          then we can be assured that the registration process actually
+          completed correctly.  This is an unhappy complication from the
+          use of global data in a driver that lives in a preemptible
+          environment.  It sure would be nice if the video device itself
+          had a means for storing and retrieving a local context pointer.
+          Oh wait.  It did.  But now it's gone.  Silly me. */
+       {
+               unsigned int midx = iminor(file->f_dentry->d_inode);
+               if (midx < sizeof(devices)/sizeof(devices[0])) {
+                       dip = devices[midx];
+               }
+       }
+       mutex_unlock(&device_lock);
+
+       if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */
+
+       vp = dip->v4lp;
+       hdw = vp->channel.hdw;
+
+       pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
+
+       if (!pvr2_hdw_dev_ok(hdw)) {
+               pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
+                          "pvr2_v4l2_open: hardware not ready");
+               return -EIO;
+       }
+
+       fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);
+       if (!fhp) {
+               return -ENOMEM;
+       }
+       memset(fhp,0,sizeof(*fhp));
+
+       init_waitqueue_head(&fhp->wait_data);
+       fhp->dev_info = dip;
+
+       pvr2_context_enter(vp->channel.mc_head); do {
+               pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
+               pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+               fhp->vnext = 0;
+               fhp->vprev = vp->vlast;
+               if (vp->vlast) {
+                       vp->vlast->vnext = fhp;
+               } else {
+                       vp->vfirst = fhp;
+               }
+               vp->vlast = fhp;
+               fhp->vhead = vp;
+       } while (0); pvr2_context_exit(vp->channel.mc_head);
+
+       fhp->file = file;
+       file->private_data = fhp;
+       v4l2_prio_open(&vp->prio,&fhp->prio);
+
+       fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
+
+       return 0;
+}
+
+
+static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
+{
+       wake_up(&fhp->wait_data);
+}
+
+static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
+{
+       int ret;
+       struct pvr2_stream *sp;
+       struct pvr2_hdw *hdw;
+       if (fh->rhp) return 0;
+
+       /* First read() attempt.  Try to claim the stream and start
+          it... */
+       if ((ret = pvr2_channel_claim_stream(&fh->channel,
+                                            fh->dev_info->stream)) != 0) {
+               /* Someone else must already have it */
+               return ret;
+       }
+
+       fh->rhp = pvr2_channel_create_mpeg_stream(fh->dev_info->stream);
+       if (!fh->rhp) {
+               pvr2_channel_claim_stream(&fh->channel,0);
+               return -ENOMEM;
+       }
+
+       hdw = fh->channel.mc_head->hdw;
+       sp = fh->dev_info->stream->stream;
+       pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
+       pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
+       pvr2_hdw_set_streaming(hdw,!0);
+       ret = pvr2_ioread_set_enabled(fh->rhp,!0);
+
+       return ret;
+}
+
+
+static ssize_t pvr2_v4l2_read(struct file *file,
+                             char __user *buff, size_t count, loff_t *ppos)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       int ret;
+
+       if (fh->fw_mode_flag) {
+               struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+               char *tbuf;
+               int c1,c2;
+               int tcnt = 0;
+               unsigned int offs = *ppos;
+
+               tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
+               if (!tbuf) return -ENOMEM;
+
+               while (count) {
+                       c1 = count;
+                       if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
+                       c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
+                       if (c2 < 0) {
+                               tcnt = c2;
+                               break;
+                       }
+                       if (!c2) break;
+                       if (copy_to_user(buff,tbuf,c2)) {
+                               tcnt = -EFAULT;
+                               break;
+                       }
+                       offs += c2;
+                       tcnt += c2;
+                       buff += c2;
+                       count -= c2;
+                       *ppos += c2;
+               }
+               kfree(tbuf);
+               return tcnt;
+       }
+
+       if (!fh->rhp) {
+               ret = pvr2_v4l2_iosetup(fh);
+               if (ret) {
+                       return ret;
+               }
+       }
+
+       for (;;) {
+               ret = pvr2_ioread_read(fh->rhp,buff,count);
+               if (ret >= 0) break;
+               if (ret != -EAGAIN) break;
+               if (file->f_flags & O_NONBLOCK) break;
+               /* Doing blocking I/O.  Wait here. */
+               ret = wait_event_interruptible(
+                       fh->wait_data,
+                       pvr2_ioread_avail(fh->rhp) >= 0);
+               if (ret < 0) break;
+       }
+
+       return ret;
+}
+
+
+static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       int ret;
+
+       if (fh->fw_mode_flag) {
+               mask |= POLLIN | POLLRDNORM;
+               return mask;
+       }
+
+       if (!fh->rhp) {
+               ret = pvr2_v4l2_iosetup(fh);
+               if (ret) return POLLERR;
+       }
+
+       poll_wait(file,&fh->wait_data,wait);
+
+       if (pvr2_ioread_avail(fh->rhp) >= 0) {
+               mask |= POLLIN | POLLRDNORM;
+       }
+
+       return mask;
+}
+
+
+static struct file_operations vdev_fops = {
+       .owner      = THIS_MODULE,
+       .open       = pvr2_v4l2_open,
+       .release    = pvr2_v4l2_release,
+       .read       = pvr2_v4l2_read,
+       .ioctl      = pvr2_v4l2_ioctl,
+       .llseek     = no_llseek,
+       .poll       = pvr2_v4l2_poll,
+};
+
+
+#define VID_HARDWARE_PVRUSB2    38  /* FIXME : need a good value */
+
+static struct video_device vdev_template = {
+       .owner      = THIS_MODULE,
+       .type       = VID_TYPE_CAPTURE | VID_TYPE_TUNER,
+       .type2      = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE
+                      | V4L2_CAP_TUNER | V4L2_CAP_AUDIO
+                      | V4L2_CAP_READWRITE),
+       .hardware   = VID_HARDWARE_PVRUSB2,
+       .fops       = &vdev_fops,
+};
+
+
+static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
+                              struct pvr2_v4l2 *vp,
+                              enum pvr2_config cfg)
+{
+       int mindevnum;
+       int unit_number;
+       int v4l_type;
+       dip->v4lp = vp;
+       dip->config = cfg;
+
+
+       switch (cfg) {
+       case pvr2_config_mpeg:
+               v4l_type = VFL_TYPE_GRABBER;
+               dip->stream = &vp->channel.mc_head->video_stream;
+               break;
+       case pvr2_config_vbi:
+               v4l_type = VFL_TYPE_VBI;
+               break;
+       case pvr2_config_radio:
+               v4l_type = VFL_TYPE_RADIO;
+               break;
+       default:
+               /* Bail out (this should be impossible) */
+               err("Failed to set up pvrusb2 v4l dev"
+                   " due to unrecognized config");
+               return;
+       }
+
+       if (!dip->stream) {
+               err("Failed to set up pvrusb2 v4l dev"
+                   " due to missing stream instance");
+               return;
+       }
+
+       dip->vdev = video_device_alloc();
+       if (!dip->vdev) {
+               err("Alloc of pvrusb2 v4l video device failed");
+               return;
+       }
+
+       memcpy(dip->vdev,&vdev_template,sizeof(vdev_template));
+       dip->vdev->release = video_device_release;
+       mutex_lock(&device_lock);
+
+       mindevnum = -1;
+       unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
+       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+               mindevnum = video_nr[unit_number];
+       }
+       if ((video_register_device(dip->vdev, v4l_type, mindevnum) < 0) &&
+           (video_register_device(dip->vdev, v4l_type, -1) < 0)) {
+               err("Failed to register pvrusb2 v4l video device");
+       } else {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "registered device video%d [%s]",
+                          dip->vdev->minor,pvr2_config_get_name(dip->config));
+       }
+
+       if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) &&
+           (devices[dip->vdev->minor] == NULL)) {
+               dip->ctxt_idx = dip->vdev->minor;
+               devices[dip->ctxt_idx] = dip;
+       }
+       mutex_unlock(&device_lock);
+
+       pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
+                                       dip->vdev->minor);
+}
+
+
+struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
+{
+       struct pvr2_v4l2 *vp;
+
+       vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+       if (!vp) return vp;
+       memset(vp,0,sizeof(*vp));
+       vp->video_dev.ctxt_idx = -1;
+       pvr2_channel_init(&vp->channel,mnp);
+       pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
+
+       vp->channel.check_func = pvr2_v4l2_internal_check;
+
+       /* register streams */
+       pvr2_v4l2_dev_init(&vp->video_dev,vp,pvr2_config_mpeg);
+
+
+       return vp;
+}
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
new file mode 100644 (file)
index 0000000..9a995e2
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_V4L2_H
+#define __PVRUSB2_V4L2_H
+
+#include "pvrusb2-context.h"
+
+struct pvr2_v4l2;
+
+struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *);
+
+#endif /* __PVRUSB2_V4L2_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
new file mode 100644 (file)
index 0000000..e4ec7f2
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+
+   This source file is specifically designed to interface with the
+   saa711x support that is available in the v4l available starting
+   with linux 2.6.15.
+
+*/
+
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/saa7115.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_decoder {
+       struct pvr2_i2c_handler handler;
+       struct pvr2_decoder_ctrl ctrl;
+       struct pvr2_i2c_client *client;
+       struct pvr2_hdw *hdw;
+       unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_decoder *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       struct v4l2_routing route;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
+       switch(hdw->input_val) {
+       case PVR2_CVAL_INPUT_TV:
+               route.input = SAA7115_COMPOSITE4;
+               break;
+       case PVR2_CVAL_INPUT_COMPOSITE:
+               route.input = SAA7115_COMPOSITE5;
+               break;
+       case PVR2_CVAL_INPUT_SVIDEO:
+               route.input = SAA7115_SVIDEO2;
+               break;
+       case PVR2_CVAL_INPUT_RADIO:
+               // ????? No idea yet what to do here
+       default:
+               return;
+       }
+       route.output = 0;
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+}
+
+
+static int check_input(struct pvr2_v4l_decoder *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->input_dirty != 0;
+}
+
+
+static void set_audio(struct pvr2_v4l_decoder *ctxt)
+{
+       u32 val;
+       struct pvr2_hdw *hdw = ctxt->hdw;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_audio %d",
+                  hdw->srate_val);
+       switch (hdw->srate_val) {
+       default:
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+               val = 48000;
+               break;
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+               val = 44100;
+               break;
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+               val = 32000;
+               break;
+       }
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+}
+
+
+static int check_audio(struct pvr2_v4l_decoder *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->srate_dirty != 0;
+}
+
+
+struct pvr2_v4l_decoder_ops {
+       void (*update)(struct pvr2_v4l_decoder *);
+       int (*check)(struct pvr2_v4l_decoder *);
+};
+
+
+static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
+       { .update = set_input, .check = check_input},
+       { .update = set_audio, .check = check_audio},
+};
+
+
+static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
+{
+       ctxt->client->handler = 0;
+       ctxt->hdw->decoder_ctrl = 0;
+       kfree(ctxt);
+}
+
+
+static int decoder_check(struct pvr2_v4l_decoder *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (ctxt->stale_mask & msk) continue;
+               if (decoder_ops[idx].check(ctxt)) {
+                       ctxt->stale_mask |= msk;
+               }
+       }
+       return ctxt->stale_mask != 0;
+}
+
+
+static void decoder_update(struct pvr2_v4l_decoder *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (!(ctxt->stale_mask & msk)) continue;
+               ctxt->stale_mask &= ~msk;
+               decoder_ops[idx].update(ctxt);
+       }
+}
+
+
+static int decoder_detect(struct pvr2_i2c_client *cp)
+{
+       /* Attempt to query the decoder - let's see if it will answer */
+       struct v4l2_tuner vt;
+       int ret;
+
+       memset(&vt,0,sizeof(vt));
+       ret = pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&vt);
+       return ret == 0; /* Return true if it answered */
+}
+
+
+static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
+{
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 decoder_enable(%d)",fl);
+       pvr2_v4l2_cmd_stream(ctxt->client,fl);
+}
+
+
+static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt)
+{
+       struct v4l2_tuner vt;
+       int ret;
+
+       memset(&vt,0,sizeof(vt));
+       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+       if (ret < 0) return -EINVAL;
+       return vt.signal ? 1 : 0;
+}
+
+
+static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+       .detach = (void (*)(void *))decoder_detach,
+       .check = (int (*)(void *))decoder_check,
+       .update = (void (*)(void *))decoder_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+};
+
+
+int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
+                              struct pvr2_i2c_client *cp)
+{
+       struct pvr2_v4l_decoder *ctxt;
+
+       if (hdw->decoder_ctrl) return 0;
+       if (cp->handler) return 0;
+       if (!decoder_detect(cp)) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->handler.func_data = ctxt;
+       ctxt->handler.func_table = &hfuncs;
+       ctxt->ctrl.ctxt = ctxt;
+       ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+       ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+       ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
+                                 sizeof(decoder_ops[0]))) - 1;
+       hdw->decoder_ctrl = &ctxt->ctrl;
+       cp->handler = &ctxt->handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
new file mode 100644 (file)
index 0000000..2b917fd
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_VIDEO_V4L_H
+#define __PVRUSB2_VIDEO_V4L_H
+
+/*
+
+   This module connects the pvrusb2 driver to the I2C chip level
+   driver which handles device video processing.  This interface is
+   used internally by the driver; higher level code should only
+   interact through the interface provided by pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_VIDEO_V4L_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
new file mode 100644 (file)
index 0000000..fcad346
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+
+   This source file is specifically designed to interface with the
+   wm8775.
+
+*/
+
+#include "pvrusb2-wm8775.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_wm8775 {
+       struct pvr2_i2c_handler handler;
+       struct pvr2_i2c_client *client;
+       struct pvr2_hdw *hdw;
+       unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_wm8775 *ctxt)
+{
+       struct v4l2_routing route;
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       int msk = 0;
+
+       memset(&route,0,sizeof(route));
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d msk=0x%x)",
+                  hdw->input_val,msk);
+
+       // Always point to input #1 no matter what
+       route.input = 2;
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+static int check_input(struct pvr2_v4l_wm8775 *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->input_dirty != 0;
+}
+
+
+struct pvr2_v4l_wm8775_ops {
+       void (*update)(struct pvr2_v4l_wm8775 *);
+       int (*check)(struct pvr2_v4l_wm8775 *);
+};
+
+
+static const struct pvr2_v4l_wm8775_ops wm8775_ops[] = {
+       { .update = set_input, .check = check_input},
+};
+
+
+static unsigned int wm8775_describe(struct pvr2_v4l_wm8775 *ctxt,
+                                    char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-wm8775");
+}
+
+
+static void wm8775_detach(struct pvr2_v4l_wm8775 *ctxt)
+{
+       ctxt->client->handler = 0;
+       kfree(ctxt);
+}
+
+
+static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (ctxt->stale_mask & msk) continue;
+               if (wm8775_ops[idx].check(ctxt)) {
+                       ctxt->stale_mask |= msk;
+               }
+       }
+       return ctxt->stale_mask != 0;
+}
+
+
+static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (!(ctxt->stale_mask & msk)) continue;
+               ctxt->stale_mask &= ~msk;
+               wm8775_ops[idx].update(ctxt);
+       }
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+       .detach = (void (*)(void *))wm8775_detach,
+       .check = (int (*)(void *))wm8775_check,
+       .update = (void (*)(void *))wm8775_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))wm8775_describe,
+};
+
+
+int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       struct pvr2_v4l_wm8775 *ctxt;
+
+       if (cp->handler) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->handler.func_data = ctxt;
+       ctxt->handler.func_table = &hfuncs;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/
+                                 sizeof(wm8775_ops[0]))) - 1;
+       cp->handler = &ctxt->handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
new file mode 100644 (file)
index 0000000..8aaeff4
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_WM8775_H
+#define __PVRUSB2_WM8775_H
+
+/*
+
+   This module connects the pvrusb2 driver to the I2C chip level
+   driver which performs analog -> digital audio conversion for
+   external audio inputs.  This interface is used internally by the
+   driver; higher level code should only interact through the
+   interface provided by pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_WM8775_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2.h b/drivers/media/video/pvrusb2/pvrusb2.h
new file mode 100644 (file)
index 0000000..074533e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_H
+#define __PVRUSB2_H
+
+/* Maximum number of pvrusb2 instances we can track at once.  You
+   might want to increase this - however the driver operation will not
+   be impaired if it is too small.  Instead additional units just
+   won't have an ID assigned and it might not be possible to specify
+   module paramters for those extra units. */
+#define PVR_NUM 20
+
+#endif /* __PVRUSB2_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
index de7b9e6e932a9b70aec1e53e2ff5d3ff985369c9..afc8f352b8e713ea66c9a15a50f0fcb05f24ba31 100644 (file)
@@ -432,10 +432,10 @@ static void saa6752hs_old_set_params(struct i2c_client* client,
 }
 
 static int handle_ctrl(struct saa6752hs_mpeg_params *params,
-               struct v4l2_ext_control *ctrl, int cmd)
+               struct v4l2_ext_control *ctrl, unsigned int cmd)
 {
        int old = 0, new;
-       int set = cmd == VIDIOC_S_EXT_CTRLS;
+       int set = (cmd == VIDIOC_S_EXT_CTRLS);
 
        new = ctrl->value;
        switch (ctrl->id) {
index f0c2111f14ad1f11c5bbe0575edd6aedd23420bd..da3007d2f4115df49b6a53ba01dec178a7292529 100644 (file)
@@ -871,9 +871,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
-              "latency: %d, mmio: 0x%lx\n", dev->name,
+              "latency: %d, mmio: 0x%llx\n", dev->name,
               pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
-              dev->pci_lat,pci_resource_start(pci_dev,0));
+              dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
        pci_set_master(pci_dev);
        if (!pci_dma_supported(pci_dev, DMA_32BIT_MASK)) {
                printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name);
@@ -905,8 +905,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
                                pci_resource_len(pci_dev,0),
                                dev->name)) {
                err = -EBUSY;
-               printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
-                      dev->name,pci_resource_start(pci_dev,0));
+               printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+                      dev->name,(unsigned long long)pci_resource_start(pci_dev,0));
                goto fail1;
        }
        dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000);
index 6be9c1131e1fc19898c74e9406e932b0e252a3f3..c18b31d9928c8d59f1e60906db240352dc105a65 100644 (file)
@@ -2190,7 +2190,7 @@ static struct pci_driver stradis_driver = {
        .remove = __devexit_p(stradis_remove)
 };
 
-int __init stradis_init(void)
+static int __init stradis_init(void)
 {
        int retval;
 
@@ -2203,7 +2203,7 @@ int __init stradis_init(void)
        return retval;
 }
 
-void __exit stradis_exit(void)
+static void __exit stradis_exit(void)
 {
        pci_unregister_driver(&stradis_driver);
        printk(KERN_INFO "stradis: module cleanup complete\n");
index b6ae969563b2ba9e3d6cefde6e51bcd21b7cbc43..2fadabf99688c766dc3aa170b4b0ead3afdea435 100644 (file)
 */
 
 #define tda9887_info(fmt, arg...) do {\
-       printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+       printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
                        i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 #define tda9887_dbg(fmt, arg...) do {\
        if (tuner_debug) \
-               printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+               printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
                        i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 
 
@@ -84,8 +84,7 @@ struct tvnorm {
 #define cAudioGain6             0x80    // bit c7
 
 #define cTopMask                0x1f    // bit c0:4
-#define cTopPalSecamDefault    0x14    // bit c0:4
-#define cTopNtscRadioDefault   0x10    // bit c0:4
+#define cTopDefault            0x10    // bit c0:4
 
 //// third reg (e)
 #define cAudioIF_4_5             0x00    // bit e0:1
@@ -123,7 +122,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopPalSecamDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_5_5   |
                           cVideoIF_38_90 ),
@@ -134,7 +133,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopPalSecamDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_0   |
                           cVideoIF_38_90 ),
@@ -145,7 +144,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopPalSecamDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_38_90 ),
@@ -156,7 +155,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis75  |
-                          cTopNtscRadioDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_4_5   |
                           cVideoIF_45_75 ),
@@ -165,7 +164,7 @@ static struct tvnorm tvnorms[] = {
                .name  = "SECAM-BGH",
                .b     = ( cPositiveAmTV  |
                           cQSS           ),
-               .c     = ( cTopPalSecamDefault),
+               .c     = ( cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_5_5   |
                           cVideoIF_38_90 ),
@@ -174,7 +173,7 @@ static struct tvnorm tvnorms[] = {
                .name  = "SECAM-L",
                .b     = ( cPositiveAmTV  |
                           cQSS           ),
-               .c     = ( cTopPalSecamDefault),
+               .c     = ( cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_38_90 ),
@@ -184,7 +183,7 @@ static struct tvnorm tvnorms[] = {
                .b     = ( cOutputPort2Inactive |
                           cPositiveAmTV  |
                           cQSS           ),
-               .c     = ( cTopPalSecamDefault),
+               .c     = ( cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_33_90 ),
@@ -195,7 +194,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopPalSecamDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_38_90 ),
@@ -206,7 +205,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis75  |
-                          cTopNtscRadioDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_4_5   |
                           cVideoIF_45_75 ),
@@ -217,7 +216,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopNtscRadioDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_4_5   |
                           cVideoIF_58_75 ),
@@ -230,7 +229,7 @@ static struct tvnorm radio_stereo = {
                  cQSS           ),
        .c    = ( cDeemphasisOFF |
                  cAudioGain6    |
-                 cTopNtscRadioDefault),
+                 cTopDefault),
        .e    = ( cTunerGainLow  |
                  cAudioIF_5_5   |
                  cRadioIF_38_90 ),
@@ -242,7 +241,7 @@ static struct tvnorm radio_mono = {
                  cQSS           ),
        .c    = ( cDeemphasisON  |
                  cDeemphasis75  |
-                 cTopNtscRadioDefault),
+                 cTopDefault),
        .e    = ( cTunerGainLow  |
                  cAudioIF_5_5   |
                  cRadioIF_38_90 ),
index a26ded7d6faef86d7ff23ee4b44b9786e099b784..011413cf34a8ad9fcdec570d636d2819edde0c77 100644 (file)
@@ -40,7 +40,6 @@ static unsigned int no_autodetect = 0;
 static unsigned int show_i2c = 0;
 
 /* insmod options used at runtime => read/write */
-static unsigned int tuner_debug_old = 0;
 int tuner_debug = 0;
 
 static unsigned int tv_range[2] = { 44, 958 };
@@ -54,8 +53,6 @@ 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_named(tuner_debug,tuner_debug_old, int, 0444);
 module_param_named(debug,tuner_debug, int, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
@@ -442,11 +439,6 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        t->audmode = V4L2_TUNER_MODE_STEREO;
        t->mode_mask = T_UNINITIALIZED;
        t->tuner_status = tuner_status;
-       if (tuner_debug_old) {
-               tuner_debug = tuner_debug_old;
-               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];
index f4b3d64ebf73ff7ff11958a8b2ac8cab6655d0b1..97f946db85978ae23e816b82b17d7ac84aa67e18 100644 (file)
@@ -1103,7 +1103,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
        };
        static const char *mpeg_stream_vbi_fmt[] = {
                "No VBI",
-               "VBI in private packets, IVTV format",
+               "Private packet, IVTV format",
                NULL
        };
 
index 74714e5bcf03299cc960529ab25c66ef3a061d0b..3ff8378ea660ad9aad1330122efd408f5faade01 100644 (file)
@@ -305,10 +305,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
        }
 
  out:
-       if (pp0_array)
-               kfree(pp0_array);
-       if (p0_array)
-               kfree(p0_array);
+       kfree(pp0_array);
+       kfree(p0_array);
        return rc;
 }
 
index af6ec553ff7ca54c3cf4ee14c7e43e32cd9e73a2..85689ab46cbc26fcc30db0e471cc5081abd5dc66 100644 (file)
@@ -1378,8 +1378,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
        return 0;
 
  out_free_port_info:
-       if (hba)
-               kfree(hba);
+       kfree(hba);
  out:
        return error;
 }
index febbdd4e0605ddeed250f534ebeda84ac77682ac..3305c12372a2f341c68fbca98f3ab5c58e2f7f9a 100644 (file)
@@ -683,9 +683,10 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                        c->mem_alloc = 1;
                        sb->current_mem_size = 1 + res->end - res->start;
                        sb->current_mem_base = res->start;
-                       osm_info("%s: allocated %ld bytes of PCI memory at "
-                                "0x%08lX.\n", c->name,
-                                1 + res->end - res->start, res->start);
+                       osm_info("%s: allocated %llu bytes of PCI memory at "
+                               "0x%016llX.\n", c->name,
+                               (unsigned long long)(1 + res->end - res->start),
+                               (unsigned long long)res->start);
                }
        }
 
@@ -704,9 +705,10 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                        c->io_alloc = 1;
                        sb->current_io_size = 1 + res->end - res->start;
                        sb->current_mem_base = res->start;
-                       osm_info("%s: allocated %ld bytes of PCI I/O at 0x%08lX"
-                                ".\n", c->name, 1 + res->end - res->start,
-                                res->start);
+                       osm_info("%s: allocated %llu bytes of PCI I/O at "
+                               "0x%016llX.\n", c->name,
+                               (unsigned long long)(1 + res->end - res->start),
+                               (unsigned long long)res->start);
                }
        }
 
@@ -1239,7 +1241,6 @@ EXPORT_SYMBOL(i2o_cntxt_list_remove);
 EXPORT_SYMBOL(i2o_cntxt_list_get_ptr);
 #endif
 EXPORT_SYMBOL(i2o_msg_get_wait);
-EXPORT_SYMBOL(i2o_msg_nop);
 EXPORT_SYMBOL(i2o_find_iop);
 EXPORT_SYMBOL(i2o_iop_find_device);
 EXPORT_SYMBOL(i2o_event_register);
index 1fdf03fd2da751181c1226d6441de7dab786b6e2..9706cc19134a1bc7b96e812e2717846ded951717 100644 (file)
@@ -85,7 +85,7 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
        }
        memset(sp, 0, sizeof(struct service_processor));
 
-       sp->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&sp->lock);
        INIT_LIST_HEAD(&sp->command_queue);
 
        pci_set_drvdata(pdev, (void *)sp);
index da8e4d7339cc42f6d2cc7c58106e6bf9604ffe40..8576a65ca1c3383fbdf2c74ff895fbc8b75e7ba7 100644 (file)
@@ -546,9 +546,9 @@ static int mmci_probe(struct amba_device *dev, void *id)
 
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n",
+       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
                mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
-               dev->res.start, dev->irq[0], dev->irq[1]);
+               (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
 
        init_timer(&host->timer);
        host->timer.data = (unsigned long)host;
index 0d435814aaa137aba3274696c0a118515f155fa4..39edb8250fbc13f85f23347f6aff7b9a0c20d6a4 100644 (file)
@@ -357,6 +357,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
        mtd->resume  = cfi_intelext_resume;
        mtd->flags   = MTD_CAP_NORFLASH;
        mtd->name    = map->name;
+       mtd->writesize = 1;
 
        mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
 
index c40b48dabed362c00a5bc2c001a75d2131a6b05c..2c3f019197c116463b74b04645dd6baf54e0dd65 100644 (file)
@@ -256,6 +256,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
    MTD->name = map->name;
    MTD->type = MTD_NORFLASH;
    MTD->flags = MTD_CAP_NORFLASH;
+   MTD->writesize = 1;
    MTD->erasesize = SectorSize*(map->buswidth);
    //   printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
    MTD->size = priv->size;
index a611de9b15159349116d78d28fdb2968b29f2c62..ac01a949b687a4513e7217c0c59ac1f492d06a45 100644 (file)
@@ -64,7 +64,8 @@ static struct mtd_info *map_absent_probe(struct map_info *map)
        mtd->write      = map_absent_write;
        mtd->sync       = map_absent_sync;
        mtd->flags      = 0;
-       mtd->erasesize = PAGE_SIZE;
+       mtd->erasesize  = PAGE_SIZE;
+       mtd->writesize  = 1;
 
        __module_get(THIS_MODULE);
        return mtd;
index 763925747db6f60a6701aad1b68e2fdecb801457..3a66680abfd06cc3b3c6b60e129e957d84e912a9 100644 (file)
@@ -71,6 +71,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
        mtd->write = mapram_write;
        mtd->sync = mapram_nop;
        mtd->flags = MTD_CAP_RAM;
+       mtd->writesize = 1;
 
        mtd->erasesize = PAGE_SIZE;
        while(mtd->size & (mtd->erasesize - 1))
index bc6ee9ef8a31ac8d6a44ef054d9d0a33d9dc9a23..1b328b1378fda2d9d288d535434a7113a7262d74 100644 (file)
@@ -47,6 +47,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
        mtd->sync = maprom_nop;
        mtd->flags = MTD_CAP_ROM;
        mtd->erasesize = map->size;
+       mtd->writesize = 1;
 
        __module_get(THIS_MODULE);
        return mtd;
index 0d98c223c5fc2e188d1f1e58ad0ea53ca0d1a506..be3f1c136d0211340a5b890b0f5648dd07c10777 100644 (file)
@@ -324,6 +324,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 
        dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
        dev->mtd.erasesize = erase_size;
+       dev->mtd.writesize = 1;
        dev->mtd.type = MTD_RAM;
        dev->mtd.flags = MTD_CAP_RAM;
        dev->mtd.erase = block2mtd_erase;
index 4ab7670770e43ff1cc9a0d855b872e1c22656f1e..08dfb899b27204ef036e693826643bd6452d8f38 100644 (file)
@@ -225,6 +225,7 @@ static int __init ms02nv_init_one(ulong addr)
        mtd->owner = THIS_MODULE;
        mtd->read = ms02nv_read;
        mtd->write = ms02nv_write;
+       mtd->writesize = 1;
 
        ret = -EIO;
        if (add_mtd_device(mtd)) {
index a19480d07888dfd043872b2e5d715755851a17e8..04271d02b6b6d990c1c32d363bea309792dbde4a 100644 (file)
@@ -478,6 +478,7 @@ add_dataflash(struct spi_device *spi, char *name,
        device->name = (pdata && pdata->name) ? pdata->name : priv->name;
        device->size = nr_pages * pagesize;
        device->erasesize = pagesize;
+       device->writesize = pagesize;
        device->owner = THIS_MODULE;
        device->type = MTD_DATAFLASH;
        device->flags = MTD_CAP_NORFLASH;
index e09e416667d38daea36e24b8034daa86597adb79..6c7337f9ebbbfce6edc1f204f1d1b58d6bff2be5 100644 (file)
@@ -151,6 +151,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
        new->mtd.owner = THIS_MODULE;
        new->mtd.type = MTD_RAM;
        new->mtd.erasesize = PAGE_SIZE;
+       new->mtd.writesize = 1;
 
        ret = -EAGAIN;
        if (add_mtd_device(&new->mtd)) {
index 666cce1bf60c0dddea6df065f47c89cd22330ef9..30f07b473ae2ad55b026c4f2ea23d30520c03957 100644 (file)
@@ -551,11 +551,11 @@ static u32 fixup_pmc551 (struct pci_dev *dev)
         /*
          * Some screen fun
          */
-        printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%lx\n",
+        printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%llx\n",
               (size<1024)?size:(size<1048576)?size>>10:size>>20,
                (size<1024)?'B':(size<1048576)?'K':'M',
               size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
-               (dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK );
+               (unsigned long long)((dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK));
 
         /*
          * Check to see the state of the memory
@@ -685,8 +685,8 @@ static int __init init_pmc551(void)
                         break;
                 }
 
-                printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%lX\n",
-                                   PCI_Device->resource[0].start);
+                printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%llx\n",
+                                   (unsigned long long)PCI_Device->resource[0].start);
 
                 /*
                  * The PMC551 device acts VERY weird if you don't init it
@@ -778,7 +778,8 @@ static int __init init_pmc551(void)
                 mtd->type      = MTD_RAM;
                 mtd->name      = "PMC551 RAM board";
                 mtd->erasesize         = 0x10000;
-               mtd->owner = THIS_MODULE;
+                mtd->writesize  = 1;
+                mtd->owner = THIS_MODULE;
 
                 if (add_mtd_device(mtd)) {
                         printk(KERN_NOTICE "pmc551: Failed to register new device\n");
index b3f665e3c38bfeec5fade51e3c4fb77ee61bc7b4..542a0c009006d4b682d30c03fa437a4f0b62a2aa 100644 (file)
@@ -209,6 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
        (*curmtd)->mtdinfo->owner = THIS_MODULE;
        (*curmtd)->mtdinfo->type = MTD_RAM;
        (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
+       (*curmtd)->mtdinfo->writesize = 1;
 
        if (add_mtd_device((*curmtd)->mtdinfo)) {
                E("slram: Failed to register new device\n");
index c350878d4592978ffece3fe1b1e97cb4caae5187..a505870052635b6acc253b42c565e41099cc7ec6 100644 (file)
@@ -123,9 +123,10 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
                window->rsrc.parent = NULL;
                printk(KERN_ERR MOD_NAME
                        " %s(): Unable to register resource"
-                       " 0x%.08lx-0x%.08lx - kernel bug?\n",
+                       " 0x%.16llx-0x%.16llx - kernel bug?\n",
                        __func__,
-                       window->rsrc.start, window->rsrc.end);
+                       (unsigned long long)window->rsrc.start,
+                       (unsigned long long)window->rsrc.end);
        }
 
 #if 0
index ea5073781b3a38265053e2710606d5ef26464854..16732794edf31b8ebb522528f3bb330a97f7ea22 100644 (file)
@@ -177,9 +177,10 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
                window->rsrc.parent = NULL;
                printk(KERN_DEBUG MOD_NAME
                        ": %s(): Unable to register resource"
-                       " 0x%.08lx-0x%.08lx - kernel bug?\n",
+                       " 0x%.16llx-0x%.16llx - kernel bug?\n",
                        __func__,
-                       window->rsrc.start, window->rsrc.end);
+                       (unsigned long long)window->rsrc.start,
+                       (unsigned long long)window->rsrc.end);
        }
 
        /* Map the firmware hub into my address space. */
index 2c9cc7f37e9216fcf5cae2d8e526514114e178b1..c26488a1793abd769ede3be3083afb5562c98925 100644 (file)
@@ -42,7 +42,6 @@ struct ixp2000_flash_info {
        struct          map_info map;
        struct          mtd_partition *partitions;
        struct          resource *res;
-       int             nr_banks;
 };
 
 static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
@@ -183,7 +182,6 @@ static int ixp2000_flash_probe(struct platform_device *dev)
         */
        info->map.phys = NO_XIP;
 
-       info->nr_banks = ixp_data->nr_banks;
        info->map.size = ixp_data->nr_banks * window_size;
        info->map.bankwidth = 1;
 
index 433c3cac3ca959285e0cd87e33829e2540c53acc..d6301f08906dffd0b769643a55a3281b13f2dcb6 100644 (file)
@@ -182,7 +182,7 @@ static struct physmap_flash_data physmap_flash_data = {
 
 static struct resource physmap_flash_resource = {
        .start          = CONFIG_MTD_PHYSMAP_START,
-       .end            = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN,
+       .end            = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
        .flags          = IORESOURCE_MEM,
 };
 
index 28b8a571a91a4ff60f133b5de4ed127684d5d78c..331a15859d710df20354f143e5f34a98ae17e22e 100644 (file)
@@ -164,8 +164,9 @@ static int __init init_scx200_docflash(void)
                outl(pmr, scx200_cb_base + SCx200_PMR);
        }
 
-               printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n",
-              docmem.start, docmem.end, width);
+               printk(KERN_INFO NAME ": DOCCS mapped at 0x%llx-0x%llx, width %d\n",
+                       (unsigned long long)docmem.start,
+                       (unsigned long long)docmem.end, width);
 
        scx200_docflash_map.size = size;
        if (width == 8)
index 24a03152d196fc494cc0605827fbd66347699401..4db2055cee31ef9e68967e9d56a3e4c7d4b731c6 100644 (file)
@@ -62,9 +62,10 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
                /* Non-CFI userflash device-- once I find one we
                 * can work on supporting it.
                 */
-               printk("%s: unsupported device at 0x%lx (%d regs): " \
+               printk("%s: unsupported device at 0x%llx (%d regs): " \
                        "email ebrower@usa.net\n",
-                      dp->full_name, res->start, edev->num_addrs);
+                      dp->full_name, (unsigned long long)res->start,
+                      edev->num_addrs);
 
                return -ENODEV;
        }
index aa18d45b264bb2d3aef9c71792401ac1d7ccece5..9a4b59d925252a554c4840455b6e00455e6aa7df 100644 (file)
@@ -78,7 +78,7 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
                return -EINVAL;
        }
 
-       if (offset >= 0 && offset < mtd->size)
+       if (offset >= 0 && offset <= mtd->size)
                return file->f_pos = offset;
 
        return -EINVAL;
index 27083ed0a017a6af2da8d41ad48d466e7b98a86d..80a76654d963749a18d2c9a79a5df29f1093159c 100644 (file)
@@ -1176,7 +1176,7 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 
        status = chip->waitfunc(mtd, chip);
 
-       return status;
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
 }
 
 /**
@@ -1271,10 +1271,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
                buf = nand_transfer_oob(chip, buf, ops);
 
-               readlen -= ops->ooblen;
-               if (!readlen)
-                       break;
-
                if (!(chip->options & NAND_NO_READRDY)) {
                        /*
                         * Apply delay or wait for ready/busy pin. Do this
@@ -1288,6 +1284,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                                nand_wait_ready(mtd);
                }
 
+               readlen -= ops->ooblen;
+               if (!readlen)
+                       break;
+
                /* Increment page address */
                realpage++;
 
@@ -1610,13 +1610,13 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        if (!writelen)
                return 0;
 
+       chipnr = (int)(to >> chip->chip_shift);
+       chip->select_chip(mtd, chipnr);
+
        /* Check, if it is write protected */
        if (nand_check_wp(mtd))
                return -EIO;
 
-       chipnr = (int)(to >> chip->chip_shift);
-       chip->select_chip(mtd, chipnr);
-
        realpage = (int)(to >> chip->page_shift);
        page = realpage & chip->pagemask;
        blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
index fe8d38514ba655ce79e8b4bc788726a5e6e060d5..e5bd88f2d560ae3966fe5169c6885c5c0d4d235f 100644 (file)
@@ -61,15 +61,15 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
 
 static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = &ndfc_ctrl;
 
        if (cmd == NAND_CMD_NONE)
                return;
 
        if (ctrl & NAND_CLE)
-               writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD);
+               writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD);
        else
-               writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE);
+               writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
 }
 
 static int ndfc_ready(struct mtd_info *mtd)
index 2c262fe03d8af60a93bd6cda681246bf4b7d9ce6..ff5cef24d5bb3ccbfc9ce0476e6db222c43af160 100644 (file)
@@ -63,8 +63,6 @@
 #include <asm/arch/regs-nand.h>
 #include <asm/arch/nand.h>
 
-#define PFX "s3c2410-nand: "
-
 #ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int hardware_ecc = 1;
 #else
@@ -99,6 +97,12 @@ struct s3c2410_nand_mtd {
        int                             scan_res;
 };
 
+enum s3c_cpu_type {
+       TYPE_S3C2410,
+       TYPE_S3C2412,
+       TYPE_S3C2440,
+};
+
 /* overview of the s3c2410 nand state */
 
 struct s3c2410_nand_info {
@@ -112,9 +116,11 @@ struct s3c2410_nand_info {
        struct resource                 *area;
        struct clk                      *clk;
        void __iomem                    *regs;
+       void __iomem                    *sel_reg;
+       int                             sel_bit;
        int                             mtd_count;
 
-       unsigned char                   is_s3c2440;
+       enum s3c_cpu_type               cpu_type;
 };
 
 /* conversion functions */
@@ -148,7 +154,7 @@ static inline int allow_clk_stop(struct s3c2410_nand_info *info)
 
 #define NS_IN_KHZ 1000000
 
-static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
+static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
 {
        int result;
 
@@ -172,53 +178,58 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
 
 /* controller setup */
 
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_device *pdev)
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
+                              struct platform_device *pdev)
 {
        struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
        unsigned long clkrate = clk_get_rate(info->clk);
+       int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
        int tacls, twrph0, twrph1;
-       unsigned long cfg;
+       unsigned long cfg = 0;
 
        /* calculate the timing information for the controller */
 
        clkrate /= 1000;        /* turn clock into kHz for ease of use */
 
        if (plat != NULL) {
-               tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
-               twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
-               twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
+               tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
+               twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
+               twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
        } else {
                /* default timings */
-               tacls = 4;
+               tacls = tacls_max;
                twrph0 = 8;
                twrph1 = 8;
        }
 
        if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
-               printk(KERN_ERR PFX "cannot get timings suitable for board\n");
+               dev_err(info->device, "cannot get suitable timings\n");
                return -EINVAL;
        }
 
-       printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
+       dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
               tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
 
-       if (!info->is_s3c2440) {
+       switch (info->cpu_type) {
+       case TYPE_S3C2410:
                cfg = S3C2410_NFCONF_EN;
                cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
                cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
                cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
-       } else {
+               break;
+
+       case TYPE_S3C2440:
+       case TYPE_S3C2412:
                cfg = S3C2440_NFCONF_TACLS(tacls - 1);
                cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
                cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
 
                /* enable the controller and de-assert nFCE */
 
-               writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE,
-                      info->regs + S3C2440_NFCONT);
+               writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
        }
 
-       pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
+       dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
 
        writel(cfg, info->regs + S3C2410_NFCONF);
        return 0;
@@ -231,26 +242,21 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
        struct s3c2410_nand_info *info;
        struct s3c2410_nand_mtd *nmtd;
        struct nand_chip *this = mtd->priv;
-       void __iomem *reg;
        unsigned long cur;
-       unsigned long bit;
 
        nmtd = this->priv;
        info = nmtd->info;
 
-       bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
-       reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF);
-
        if (chip != -1 && allow_clk_stop(info))
                clk_enable(info->clk);
 
-       cur = readl(reg);
+       cur = readl(info->sel_reg);
 
        if (chip == -1) {
-               cur |= bit;
+               cur |= info->sel_bit;
        } else {
                if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
-                       printk(KERN_ERR PFX "chip %d out of range\n", chip);
+                       dev_err(info->device, "invalid chip %d\n", chip);
                        return;
                }
 
@@ -259,10 +265,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
                                (info->platform->select_chip) (nmtd->set, chip);
                }
 
-               cur &= ~bit;
+               cur &= ~info->sel_bit;
        }
 
-       writel(cur, reg);
+       writel(cur, info->sel_reg);
 
        if (chip == -1 && allow_clk_stop(info))
                clk_disable(info->clk);
@@ -311,15 +317,25 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
 static int s3c2410_nand_devready(struct mtd_info *mtd)
 {
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
-       if (info->is_s3c2440)
-               return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
        return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
 }
 
+static int s3c2440_nand_devready(struct mtd_info *mtd)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
+}
+
+static int s3c2412_nand_devready(struct mtd_info *mtd)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
+}
+
 /* ECC handling functions */
 
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+                                    u_char *read_ecc, u_char *calc_ecc)
 {
        pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc);
 
@@ -487,11 +503,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
                                   struct s3c2410_nand_set *set)
 {
        struct nand_chip *chip = &nmtd->chip;
+       void __iomem *regs = info->regs;
 
-       chip->IO_ADDR_R    = info->regs + S3C2410_NFDATA;
-       chip->IO_ADDR_W    = info->regs + S3C2410_NFDATA;
-       chip->cmd_ctrl     = s3c2410_nand_hwcontrol;
-       chip->dev_ready    = s3c2410_nand_devready;
        chip->write_buf    = s3c2410_nand_write_buf;
        chip->read_buf     = s3c2410_nand_read_buf;
        chip->select_chip  = s3c2410_nand_select_chip;
@@ -500,11 +513,37 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        chip->options      = 0;
        chip->controller   = &info->controller;
 
-       if (info->is_s3c2440) {
-               chip->IO_ADDR_R  = info->regs + S3C2440_NFDATA;
-               chip->IO_ADDR_W  = info->regs + S3C2440_NFDATA;
-               chip->cmd_ctrl   = s3c2440_nand_hwcontrol;
-       }
+       switch (info->cpu_type) {
+       case TYPE_S3C2410:
+               chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+               info->sel_reg   = regs + S3C2410_NFCONF;
+               info->sel_bit   = S3C2410_NFCONF_nFCE;
+               chip->cmd_ctrl  = s3c2410_nand_hwcontrol;
+               chip->dev_ready = s3c2410_nand_devready;
+               break;
+
+       case TYPE_S3C2440:
+               chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+               info->sel_reg   = regs + S3C2440_NFCONT;
+               info->sel_bit   = S3C2440_NFCONT_nFCE;
+               chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+               chip->dev_ready = s3c2440_nand_devready;
+               break;
+
+       case TYPE_S3C2412:
+               chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+               info->sel_reg   = regs + S3C2440_NFCONT;
+               info->sel_bit   = S3C2412_NFCONT_nFCE0;
+               chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+               chip->dev_ready = s3c2412_nand_devready;
+
+               if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
+                       dev_info(info->device, "System booted from NAND\n");
+
+               break;
+       }
+
+       chip->IO_ADDR_R = chip->IO_ADDR_W;
 
        nmtd->info         = info;
        nmtd->mtd.priv     = chip;
@@ -512,17 +551,25 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        nmtd->set          = set;
 
        if (hardware_ecc) {
-               chip->ecc.correct   = s3c2410_nand_correct_data;
-               chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
                chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+               chip->ecc.correct   = s3c2410_nand_correct_data;
                chip->ecc.mode      = NAND_ECC_HW;
                chip->ecc.size      = 512;
                chip->ecc.bytes     = 3;
                chip->ecc.layout    = &nand_hw_eccoob;
 
-               if (info->is_s3c2440) {
-                       chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-                       chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+               switch (info->cpu_type) {
+               case TYPE_S3C2410:
+                       chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+                       break;
+
+               case TYPE_S3C2412:
+               case TYPE_S3C2440:
+                       chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+                       break;
+
                }
        } else {
                chip->ecc.mode      = NAND_ECC_SOFT;
@@ -537,7 +584,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
  * nand layer to look for devices
 */
 
-static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
+static int s3c24xx_nand_probe(struct platform_device *pdev,
+                             enum s3c_cpu_type cpu_type)
 {
        struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
        struct s3c2410_nand_info *info;
@@ -592,7 +640,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
        info->device     = &pdev->dev;
        info->platform   = plat;
        info->regs       = ioremap(res->start, size);
-       info->is_s3c2440 = is_s3c2440;
+       info->cpu_type   = cpu_type;
 
        if (info->regs == NULL) {
                dev_err(&pdev->dev, "cannot reserve register region\n");
@@ -699,12 +747,17 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
 
 static int s3c2410_nand_probe(struct platform_device *dev)
 {
-       return s3c24xx_nand_probe(dev, 0);
+       return s3c24xx_nand_probe(dev, TYPE_S3C2410);
 }
 
 static int s3c2440_nand_probe(struct platform_device *dev)
 {
-       return s3c24xx_nand_probe(dev, 1);
+       return s3c24xx_nand_probe(dev, TYPE_S3C2440);
+}
+
+static int s3c2412_nand_probe(struct platform_device *dev)
+{
+       return s3c24xx_nand_probe(dev, TYPE_S3C2412);
 }
 
 static struct platform_driver s3c2410_nand_driver = {
@@ -729,16 +782,29 @@ static struct platform_driver s3c2440_nand_driver = {
        },
 };
 
+static struct platform_driver s3c2412_nand_driver = {
+       .probe          = s3c2412_nand_probe,
+       .remove         = s3c2410_nand_remove,
+       .suspend        = s3c24xx_nand_suspend,
+       .resume         = s3c24xx_nand_resume,
+       .driver         = {
+               .name   = "s3c2412-nand",
+               .owner  = THIS_MODULE,
+       },
+};
+
 static int __init s3c2410_nand_init(void)
 {
        printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
 
+       platform_driver_register(&s3c2412_nand_driver);
        platform_driver_register(&s3c2440_nand_driver);
        return platform_driver_register(&s3c2410_nand_driver);
 }
 
 static void __exit s3c2410_nand_exit(void)
 {
+       platform_driver_unregister(&s3c2412_nand_driver);
        platform_driver_unregister(&s3c2440_nand_driver);
        platform_driver_unregister(&s3c2410_nand_driver);
 }
index a0b4b1edcb0d10739ab6bca0f30cc85e9c62d635..f40081069ab2c6fa0f2a5705eaad7c9e698c28af 100644 (file)
@@ -97,7 +97,7 @@ static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
                unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE;
                unsigned char bits;
 
-               bits = (ctrl & NAND_CNE) << 2;
+               bits = (ctrl & NAND_NCE) << 2;
                bits |= ctrl & NAND_CLE;
                bits |= (ctrl & NAND_ALE) >> 2;
 
index e27778926eba502acb78e7fb63c19a27a154cf60..d2f808979a2b5a9a598f45310f6fdd9ef5905b95 100644 (file)
@@ -375,8 +375,7 @@ limit of 4K.
    of the drivers, and will likely be provided by some future kernel.
 */
 enum pci_flags_bit {
-       PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-       PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+       PCI_USES_MASTER=4,
 };
 
 enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
@@ -446,95 +445,95 @@ static struct vortex_chip_info {
        int io_size;
 } vortex_info_tbl[] __devinitdata = {
        {"3c590 Vortex 10Mbps",
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c592 EISA 10Mbps Demon/Vortex",                                      /* AKPM: from Don's 3c59x_cb.c 0.49H */
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c597 EISA Fast Demon/Vortex",                                        /* AKPM: from Don's 3c59x_cb.c 0.49H */
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c595 Vortex 100baseTx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c595 Vortex 100baseT4",
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
 
        {"3c595 Vortex 100base-MII",
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c900 Boomerang 10baseT",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
+        PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
        {"3c900 Boomerang 10Mbps Combo",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
+        PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
        {"3c900 Cyclone 10Mbps TPO",                                            /* AKPM: from Don's 0.99M */
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c900 Cyclone 10Mbps Combo",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 
        {"3c900 Cyclone 10Mbps TPC",                                            /* AKPM: from Don's 0.99M */
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c900B-FL Cyclone 10base-FL",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c905 Boomerang 100baseTx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
+        PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
        {"3c905 Boomerang 100baseT4",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
+        PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
        {"3c905B Cyclone 100baseTx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
 
        {"3c905B Cyclone 10/100/BNC",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c905B-FX Cyclone 100baseFx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c905C Tornado",
-       PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+       PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
        {"3c920B-EMB-WNM (ATI Radeon 9100 IGP)",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
        {"3c980 Cyclone",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 
        {"3c980C Python-T",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3cSOHO100-TX Hurricane",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c555 Laptop Hurricane",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
        {"3c556 Laptop Tornado",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
                                                                        HAS_HWCKSM, 128, },
        {"3c556B Laptop Hurricane",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
                                        WNO_XCVR_PWR|HAS_HWCKSM, 128, },
 
        {"3c575 [Megahertz] 10/100 LAN  CardBus",
-       PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+       PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
        {"3c575 Boomerang CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+        PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
        {"3CCFE575BT Cyclone CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
                                                                        INVERT_LED_PWR|HAS_HWCKSM, 128, },
        {"3CCFE575CT Tornado CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
        {"3CCFE656 Cyclone CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        INVERT_LED_PWR|HAS_HWCKSM, 128, },
 
        {"3CCFEM656B Cyclone+Winmodem CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        INVERT_LED_PWR|HAS_HWCKSM, 128, },
        {"3CXFEM656C Tornado+Winmodem CardBus",                 /* From pcmcia-cs-3.1.5 */
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
        {"3c450 HomePNA Tornado",                                               /* AKPM: from Don's 0.99Q */
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c920 Tornado",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c982 Hydra Dual Port A",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
 
        {"3c982 Hydra Dual Port B",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
        {"3c905B-T4",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
        {"3c920B-EMB-WNM Tornado",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
 
        {NULL,}, /* NULL terminated list. */
 };
@@ -1408,8 +1407,10 @@ static int __devinit vortex_probe1(struct device *gendev,
                }
 
                if (print_info) {
-                       printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
-                               print_name, pci_resource_start(pdev, 2),
+                       printk(KERN_INFO "%s: CardBus functions mapped "
+                               "%16.16llx->%p\n",
+                               print_name,
+                               (unsigned long long)pci_resource_start(pdev, 2),
                                vp->cb_fn_base);
                }
                EL3WINDOW(2);
index 0cdc830449d8e58e29b772fa3cbe5f4bf8da2cb0..d26dd6a7062dcd2e72cb05a973fe1e78962fb7b4 100644 (file)
@@ -1823,7 +1823,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        struct cp_private *cp;
        int rc;
        void __iomem *regs;
-       long pciaddr;
+       resource_size_t pciaddr;
        unsigned int addr_len, i, pci_using_dac;
        u8 pci_rev;
 
@@ -1883,8 +1883,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
                rc = -EIO;
-               printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
-                      pci_resource_len(pdev, 1), pci_name(pdev));
+               printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
+                      (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
                goto err_out_res;
        }
 
@@ -1916,8 +1916,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        regs = ioremap(pciaddr, CP_REGS_SIZE);
        if (!regs) {
                rc = -EIO;
-               printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
-                      pci_resource_len(pdev, 1), pciaddr, pci_name(pdev));
+               printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%llx) on pci dev %s\n",
+                       (unsigned long long)pci_resource_len(pdev, 1),
+                       (unsigned long long)pciaddr, pci_name(pdev));
                goto err_out_res;
        }
        dev->base_addr = (unsigned long) regs;
index abd6261465f16e2692c45033ab81e3263dc6716e..ed2e3c03bc880678307b42a73b4fa61b005655c9 100644 (file)
@@ -1341,9 +1341,9 @@ static int rtl8139_open (struct net_device *dev)
        netif_start_queue (dev);
 
        if (netif_msg_ifup(tp))
-               printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
-                       " GP Pins %2.2x %s-duplex.\n",
-                       dev->name, pci_resource_start (tp->pci_dev, 1),
+               printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#llx IRQ %d"
+                       " GP Pins %2.2x %s-duplex.\n", dev->name,
+                       (unsigned long long)pci_resource_start (tp->pci_dev, 1),
                        dev->irq, RTL_R8 (MediaStatus),
                        tp->mii.full_duplex ? "full" : "half");
 
index 6e75482d75f266e7b81b0637343785e1b096a683..53449207e53b167f17c36567bd8de48ea03f580c 100644 (file)
@@ -683,11 +683,6 @@ struct netdev_private {
 };
 
 /* The station address location in the EEPROM. */
-#ifdef MEM_MAPPING
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-#else
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
-#endif
 /* The struct pci_device_id consist of:
         vendor, device          Vendor and device ID to match (or PCI_ANY_ID)
         subvendor, subdevice    Subsystem vendor and device ID to match (or PCI_ANY_ID)
@@ -695,9 +690,10 @@ struct netdev_private {
         class_mask              of the class are honored during the comparison.
         driver_data             Data private to the driver.
 */
-static struct pci_device_id rio_pci_tbl[] = {
-       {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {0,}
+
+static const struct pci_device_id rio_pci_tbl[] = {
+       {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
+       { }
 };
 MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
 #define TX_TIMEOUT  (4*HZ)
index 24996da4c1c44f9919b3a6277422c158c0312232..7965a9b08e797fc3e0878422ebc989c4af28b728 100644 (file)
@@ -410,10 +410,7 @@ dm9000_probe(struct platform_device *pdev)
        if (pdev->num_resources < 2) {
                ret = -ENODEV;
                goto out;
-       }
-
-       switch (pdev->num_resources) {
-       case 2:
+       } else if (pdev->num_resources == 2) {
                base = pdev->resource[0].start;
 
                if (!request_mem_region(base, 4, ndev->name)) {
@@ -423,17 +420,16 @@ dm9000_probe(struct platform_device *pdev)
 
                ndev->base_addr = base;
                ndev->irq = pdev->resource[1].start;
-               db->io_addr = (void *)base;
-               db->io_data = (void *)(base + 4);
-
-               break;
+               db->io_addr = (void __iomem *)base;
+               db->io_data = (void __iomem *)(base + 4);
 
-       case 3:
+       } else {
                db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
                db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
-               if (db->addr_res == NULL || db->data_res == NULL) {
+               if (db->addr_res == NULL || db->data_res == NULL ||
+                   db->irq_res == NULL) {
                        printk(KERN_ERR PFX "insufficient resources\n");
                        ret = -ENOENT;
                        goto out;
@@ -482,7 +478,6 @@ dm9000_probe(struct platform_device *pdev)
 
                /* ensure at least we have a default set of IO routines */
                dm9000_set_io(db, iosize);
-
        }
 
        /* check to see if anything is being over-ridden */
@@ -564,6 +559,13 @@ dm9000_probe(struct platform_device *pdev)
        for (i = 0; i < 6; i++)
                ndev->dev_addr[i] = db->srom[i];
 
+       if (!is_valid_ether_addr(ndev->dev_addr)) {
+               /* try reading from mac */
+
+               for (i = 0; i < 6; i++)
+                       ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
+       }
+
        if (!is_valid_ether_addr(ndev->dev_addr))
                printk("%s: Invalid ethernet MAC address.  Please "
                       "set using ifconfig\n", ndev->name);
@@ -663,7 +665,6 @@ dm9000_init_dm9000(struct net_device *dev)
        db->tx_pkt_cnt = 0;
        db->queue_pkt_len = 0;
        dev->trans_start = 0;
-       spin_lock_init(&db->lock);
 }
 
 /*
@@ -767,7 +768,7 @@ dm9000_stop(struct net_device *ndev)
  * receive the packet to upper layer, free the transmitted packet
  */
 
-void
+static void
 dm9000_tx_done(struct net_device *dev, board_info_t * db)
 {
        int tx_status = ior(db, DM9000_NSR);    /* Got TX status */
@@ -1187,13 +1188,14 @@ dm9000_drv_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver dm9000_driver = {
+       .driver = {
+               .name    = "dm9000",
+               .owner   = THIS_MODULE,
+       },
        .probe   = dm9000_probe,
        .remove  = dm9000_drv_remove,
        .suspend = dm9000_drv_suspend,
        .resume  = dm9000_drv_resume,
-       .driver = {
-               .name   = "dm9000",
-       },
 };
 
 static int __init
index f37170cc1a377fb3b05a17622c28c27f048fe043..93a286570923c523e118022a8024ddec68755843 100644 (file)
@@ -2678,9 +2678,9 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                goto err_out_free;
        }
 
-       DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, "
+       DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
                "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
-               pci_resource_start(pdev, 0), pdev->irq,
+               (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
                netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
                netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
 
index 467fc861360d6857aa2f3828f018bbd413739e94..ecf5ad85a6847e32ac7ecb3d1eee398033cffc66 100644 (file)
@@ -278,11 +278,6 @@ having to sign an Intel NDA when I'm helping Intel sell their own product!
 
 static int speedo_found1(struct pci_dev *pdev, void __iomem *ioaddr, int fnd_cnt, int acpi_idle_state);
 
-enum pci_flags_bit {
-       PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-       PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
-};
-
 /* Offsets to the various registers.
    All accesses need not be longword aligned. */
 enum speedo_offsets {
index 724d7dc35fa3afbca55b44cd170aa2b51ecb30de..ee34a16eb4e24b8feb2667b774d5627e8168a139 100644 (file)
@@ -191,23 +191,10 @@ IVc. Errata
 */
 
 
-enum pci_id_flags_bits {
-        /* Set PCI command register bits before calling probe1(). */
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-        /* Read and map the single following PCI BAR. */
-        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
-
 enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 };
 
 #define EPIC_TOTAL_SIZE 0x100
 #define USE_IO_OPS 1
-#ifdef USE_IO_OPS
-#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0
-#else
-#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
-#endif
 
 typedef enum {
        SMSC_83C170_0,
@@ -218,7 +205,6 @@ typedef enum {
 
 struct epic_chip_info {
        const char *name;
-       enum pci_id_flags_bits pci_flags;
         int io_size;                            /* Needed for I/O region check or ioremap(). */
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
@@ -227,11 +213,11 @@ struct epic_chip_info {
 /* indexed by chip_t */
 static const struct epic_chip_info pci_id_tbl[] = {
        { "SMSC EPIC/100 83c170",
-        EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
+         EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
        { "SMSC EPIC/100 83c170",
-        EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR },
+         EPIC_TOTAL_SIZE, TYPE2_INTR },
        { "SMSC EPIC/C 83c175",
-        EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
+         EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
 };
 
 
index a8449265e5fd5a2dbae2ffb2ee9b6ec297a3d79c..13eca7ede2af8175d524b541fd74ec60900dd5cb 100644 (file)
@@ -126,16 +126,6 @@ MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
 
 #define MIN_REGION_SIZE 136
 
-enum pci_flags_bit {
-       PCI_USES_IO = 1,
-       PCI_USES_MEM = 2,
-       PCI_USES_MASTER = 4,
-       PCI_ADDR0 = 0x10 << 0,
-       PCI_ADDR1 = 0x10 << 1,
-       PCI_ADDR2 = 0x10 << 2,
-       PCI_ADDR3 = 0x10 << 3,
-};
-
 /* A chip capabilities table, matching the entries in pci_tbl[] above. */
 enum chip_capability_flags {
        HAS_MII_XCVR,
index bd6983d1afbac77ed852c8991cb7b653d4272128..db694c83298961ad4630e2764cf0f7f8833098e2 100644 (file)
@@ -22,7 +22,7 @@
  * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com)
  *
  * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
- * Copyright (c) 2004-2005 Macq Electronique SA.
+ * Copyright (c) 2004-2006 Macq Electronique SA.
  */
 
 #include <linux/config.h>
@@ -51,7 +51,7 @@
 
 #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
     defined(CONFIG_M5272) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x)
+    defined(CONFIG_M520x) || defined(CONFIG_M532x)
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include "fec.h"
@@ -80,6 +80,8 @@ static unsigned int fec_hw[] = {
        (MCF_MBAR + 0x1000),
 #elif defined(CONFIG_M520x)
        (MCF_MBAR+0x30000),
+#elif defined(CONFIG_M532x)
+       (MCF_MBAR+0xfc030000),
 #else
        &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec),
 #endif
@@ -143,7 +145,7 @@ typedef struct {
 #define TX_RING_MOD_MASK       15      /*   for this to work */
 
 #if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
-#error "FEC: descriptor ring size contants too large"
+#error "FEC: descriptor ring size constants too large"
 #endif
 
 /* Interrupt events/masks.
@@ -167,12 +169,12 @@ typedef struct {
 
 
 /*
- * The 5270/5271/5280/5282 RX control register also contains maximum frame
+ * The 5270/5271/5280/5282/532x RX control register also contains maximum frame
  * size bits. Other FEC hardware does not, so we need to take that into
  * account when setting it.
  */
 #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x)
+    defined(CONFIG_M520x) || defined(CONFIG_M532x)
 #define        OPT_FRAME_SIZE  (PKT_MAXBUF_SIZE << 16)
 #else
 #define        OPT_FRAME_SIZE  0
@@ -308,6 +310,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct fec_enet_private *fep;
        volatile fec_t  *fecp;
        volatile cbd_t  *bdp;
+       unsigned short  status;
 
        fep = netdev_priv(dev);
        fecp = (volatile fec_t*)dev->base_addr;
@@ -320,8 +323,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Fill in a Tx ring entry */
        bdp = fep->cur_tx;
 
+       status = bdp->cbd_sc;
 #ifndef final_version
-       if (bdp->cbd_sc & BD_ENET_TX_READY) {
+       if (status & BD_ENET_TX_READY) {
                /* Ooops.  All transmit buffers are full.  Bail out.
                 * This should not happen, since dev->tbusy should be set.
                 */
@@ -332,7 +336,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Clear all of the status flags.
         */
-       bdp->cbd_sc &= ~BD_ENET_TX_STATS;
+       status &= ~BD_ENET_TX_STATS;
 
        /* Set buffer length and buffer pointer.
        */
@@ -366,21 +370,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_lock_irq(&fep->lock);
 
-       /* Send it on its way.  Tell FEC its ready, interrupt when done,
-        * its the last BD of the frame, and to put the CRC on the end.
+       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
+        * it's the last BD of the frame, and to put the CRC on the end.
         */
 
-       bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
                        | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+       bdp->cbd_sc = status;
 
        dev->trans_start = jiffies;
 
        /* Trigger transmission start */
-       fecp->fec_x_des_active = 0x01000000;
+       fecp->fec_x_des_active = 0;
 
        /* If this was the last BD in the ring, start at the beginning again.
        */
-       if (bdp->cbd_sc & BD_ENET_TX_WRAP) {
+       if (status & BD_ENET_TX_WRAP) {
                bdp = fep->tx_bd_base;
        } else {
                bdp++;
@@ -491,43 +496,44 @@ fec_enet_tx(struct net_device *dev)
 {
        struct  fec_enet_private *fep;
        volatile cbd_t  *bdp;
+       unsigned short status;
        struct  sk_buff *skb;
 
        fep = netdev_priv(dev);
        spin_lock(&fep->lock);
        bdp = fep->dirty_tx;
 
-       while ((bdp->cbd_sc&BD_ENET_TX_READY) == 0) {
+       while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
                if (bdp == fep->cur_tx && fep->tx_full == 0) break;
 
                skb = fep->tx_skbuff[fep->skb_dirty];
                /* Check for errors. */
-               if (bdp->cbd_sc & (BD_ENET_TX_HB | BD_ENET_TX_LC |
+               if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
                                   BD_ENET_TX_RL | BD_ENET_TX_UN |
                                   BD_ENET_TX_CSL)) {
                        fep->stats.tx_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_HB)  /* No heartbeat */
+                       if (status & BD_ENET_TX_HB)  /* No heartbeat */
                                fep->stats.tx_heartbeat_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_LC)  /* Late collision */
+                       if (status & BD_ENET_TX_LC)  /* Late collision */
                                fep->stats.tx_window_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_RL)  /* Retrans limit */
+                       if (status & BD_ENET_TX_RL)  /* Retrans limit */
                                fep->stats.tx_aborted_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_UN)  /* Underrun */
+                       if (status & BD_ENET_TX_UN)  /* Underrun */
                                fep->stats.tx_fifo_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */
+                       if (status & BD_ENET_TX_CSL) /* Carrier lost */
                                fep->stats.tx_carrier_errors++;
                } else {
                        fep->stats.tx_packets++;
                }
 
 #ifndef final_version
-               if (bdp->cbd_sc & BD_ENET_TX_READY)
+               if (status & BD_ENET_TX_READY)
                        printk("HEY! Enet xmit interrupt and TX_READY.\n");
 #endif
                /* Deferred means some collisions occurred during transmit,
                 * but we eventually sent the packet OK.
                 */
-               if (bdp->cbd_sc & BD_ENET_TX_DEF)
+               if (status & BD_ENET_TX_DEF)
                        fep->stats.collisions++;
            
                /* Free the sk buffer associated with this last transmit.
@@ -538,7 +544,7 @@ fec_enet_tx(struct net_device *dev)
            
                /* Update pointer to next buffer descriptor to be transmitted.
                 */
-               if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+               if (status & BD_ENET_TX_WRAP)
                        bdp = fep->tx_bd_base;
                else
                        bdp++;
@@ -568,9 +574,14 @@ fec_enet_rx(struct net_device *dev)
        struct  fec_enet_private *fep;
        volatile fec_t  *fecp;
        volatile cbd_t *bdp;
+       unsigned short status;
        struct  sk_buff *skb;
        ushort  pkt_len;
        __u8 *data;
+       
+#ifdef CONFIG_M532x
+       flush_cache_all();
+#endif 
 
        fep = netdev_priv(dev);
        fecp = (volatile fec_t*)dev->base_addr;
@@ -580,13 +591,13 @@ fec_enet_rx(struct net_device *dev)
         */
        bdp = fep->cur_rx;
 
-while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
+while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
 #ifndef final_version
        /* Since we have allocated space to hold a complete frame,
         * the last indicator should be set.
         */
-       if ((bdp->cbd_sc & BD_ENET_RX_LAST) == 0)
+       if ((status & BD_ENET_RX_LAST) == 0)
                printk("FEC ENET: rcv is not +last\n");
 #endif
 
@@ -594,26 +605,26 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
                goto rx_processing_done;
 
        /* Check for errors. */
-       if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
+       if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
                           BD_ENET_RX_CR | BD_ENET_RX_OV)) {
                fep->stats.rx_errors++;       
-               if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
+               if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
                /* Frame too long or too short. */
                        fep->stats.rx_length_errors++;
                }
-               if (bdp->cbd_sc & BD_ENET_RX_NO)        /* Frame alignment */
+               if (status & BD_ENET_RX_NO)     /* Frame alignment */
                        fep->stats.rx_frame_errors++;
-               if (bdp->cbd_sc & BD_ENET_RX_CR)        /* CRC Error */
-                       fep->stats.rx_crc_errors++;
-               if (bdp->cbd_sc & BD_ENET_RX_OV)        /* FIFO overrun */
+               if (status & BD_ENET_RX_CR)     /* CRC Error */
                        fep->stats.rx_crc_errors++;
+               if (status & BD_ENET_RX_OV)     /* FIFO overrun */
+                       fep->stats.rx_fifo_errors++;
        }
 
        /* Report late collisions as a frame error.
         * On this error, the BD is closed, but we don't know what we
         * have in the buffer.  So, just drop this frame on the floor.
         */
-       if (bdp->cbd_sc & BD_ENET_RX_CL) {
+       if (status & BD_ENET_RX_CL) {
                fep->stats.rx_errors++;
                fep->stats.rx_frame_errors++;
                goto rx_processing_done;
@@ -639,9 +650,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
        } else {
                skb->dev = dev;
                skb_put(skb,pkt_len-4); /* Make room */
-               eth_copy_and_sum(skb,
-                                (unsigned char *)__va(bdp->cbd_bufaddr),
-                                pkt_len-4, 0);
+               eth_copy_and_sum(skb, data, pkt_len-4, 0);
                skb->protocol=eth_type_trans(skb,dev);
                netif_rx(skb);
        }
@@ -649,15 +658,16 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
 
        /* Clear the status flags for this buffer.
        */
-       bdp->cbd_sc &= ~BD_ENET_RX_STATS;
+       status &= ~BD_ENET_RX_STATS;
 
        /* Mark the buffer empty.
        */
-       bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+       status |= BD_ENET_RX_EMPTY;
+       bdp->cbd_sc = status;
 
        /* Update BD pointer to next entry.
        */
-       if (bdp->cbd_sc & BD_ENET_RX_WRAP)
+       if (status & BD_ENET_RX_WRAP)
                bdp = fep->rx_bd_base;
        else
                bdp++;
@@ -667,9 +677,9 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
         * incoming frames.  On a heavily loaded network, we should be
         * able to keep up at the expense of system resources.
         */
-       fecp->fec_r_des_active = 0x01000000;
+       fecp->fec_r_des_active = 0;
 #endif
-   } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */
+   } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
        fep->cur_rx = (cbd_t *)bdp;
 
 #if 0
@@ -680,11 +690,12 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
         * our way back to the interrupt return only to come right back
         * here.
         */
-       fecp->fec_r_des_active = 0x01000000;
+       fecp->fec_r_des_active = 0;
 #endif
 }
 
 
+/* called from interrupt context */
 static void
 fec_enet_mii(struct net_device *dev)
 {
@@ -696,10 +707,12 @@ fec_enet_mii(struct net_device *dev)
        fep = netdev_priv(dev);
        ep = fep->hwp;
        mii_reg = ep->fec_mii_data;
+
+       spin_lock(&fep->lock);
        
        if ((mip = mii_head) == NULL) {
                printk("MII and no head!\n");
-               return;
+               goto unlock;
        }
 
        if (mip->mii_func != NULL)
@@ -711,6 +724,9 @@ fec_enet_mii(struct net_device *dev)
 
        if ((mip = mii_head) != NULL)
                ep->fec_mii_data = mip->mii_regval;
+
+unlock:
+       spin_unlock(&fep->lock);
 }
 
 static int
@@ -728,8 +744,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
 
        retval = 0;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&fep->lock,flags);
 
        if ((mip = mii_free) != NULL) {
                mii_free = mip->mii_next;
@@ -749,7 +764,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
                retval = 1;
        }
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&fep->lock,flags);
 
        return(retval);
 }
@@ -1216,7 +1231,7 @@ static phy_info_t const * const phy_info[] = {
 };
 
 /* ------------------------------------------------------------------------- */
-
+#if !defined(CONFIG_M532x)
 #ifdef CONFIG_RPXCLASSIC
 static void
 mii_link_interrupt(void *dev_id);
@@ -1224,6 +1239,7 @@ mii_link_interrupt(void *dev_id);
 static irqreturn_t
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs);
 #endif
+#endif
 
 #if defined(CONFIG_M5272)
 
@@ -1384,13 +1400,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
        {
                volatile unsigned char  *icrp;
                volatile unsigned long  *imrp;
-               int i;
+               int i, ilip;
 
                b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0;
                icrp = (volatile unsigned char *) (MCF_IPSBAR + b +
                        MCFINTC_ICR0);
-               for (i = 23; (i < 36); i++)
-                       icrp[i] = 0x23;
+               for (i = 23, ilip = 0x28; (i < 36); i++)
+                       icrp[i] = ilip--;
 
                imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
                        MCFINTC_IMRH);
@@ -1618,6 +1634,159 @@ static void __inline__ fec_uncache(unsigned long addr)
 
 /* ------------------------------------------------------------------------- */
 
+#elif defined(CONFIG_M532x)
+/*
+ * Code specific for M532x
+ */
+static void __inline__ fec_request_intrs(struct net_device *dev)
+{
+       struct fec_enet_private *fep;
+       int b;
+       static const struct idesc {
+               char *name;
+               unsigned short irq;
+       } *idp, id[] = {
+           { "fec(TXF)", 36 },
+           { "fec(TXB)", 37 },
+           { "fec(TXFIFO)", 38 },
+           { "fec(TXCR)", 39 },
+           { "fec(RXF)", 40 },
+           { "fec(RXB)", 41 },
+           { "fec(MII)", 42 },
+           { "fec(LC)", 43 },
+           { "fec(HBERR)", 44 },
+           { "fec(GRA)", 45 },
+           { "fec(EBERR)", 46 },
+           { "fec(BABT)", 47 },
+           { "fec(BABR)", 48 },
+           { NULL },
+       };
+
+       fep = netdev_priv(dev);
+       b = (fep->index) ? 128 : 64;
+
+       /* Setup interrupt handlers. */
+       for (idp = id; idp->name; idp++) {
+               if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0)
+                       printk("FEC: Could not allocate %s IRQ(%d)!\n", 
+                               idp->name, b+idp->irq);
+       }
+
+       /* Unmask interrupts */
+       MCF_INTC0_ICR36 = 0x2;
+       MCF_INTC0_ICR37 = 0x2;
+       MCF_INTC0_ICR38 = 0x2;
+       MCF_INTC0_ICR39 = 0x2;
+       MCF_INTC0_ICR40 = 0x2;
+       MCF_INTC0_ICR41 = 0x2;
+       MCF_INTC0_ICR42 = 0x2;
+       MCF_INTC0_ICR43 = 0x2;
+       MCF_INTC0_ICR44 = 0x2;
+       MCF_INTC0_ICR45 = 0x2;
+       MCF_INTC0_ICR46 = 0x2;
+       MCF_INTC0_ICR47 = 0x2;
+       MCF_INTC0_ICR48 = 0x2;
+
+       MCF_INTC0_IMRH &= ~(
+               MCF_INTC_IMRH_INT_MASK36 |
+               MCF_INTC_IMRH_INT_MASK37 |
+               MCF_INTC_IMRH_INT_MASK38 |
+               MCF_INTC_IMRH_INT_MASK39 |
+               MCF_INTC_IMRH_INT_MASK40 |
+               MCF_INTC_IMRH_INT_MASK41 |
+               MCF_INTC_IMRH_INT_MASK42 |
+               MCF_INTC_IMRH_INT_MASK43 |
+               MCF_INTC_IMRH_INT_MASK44 |
+               MCF_INTC_IMRH_INT_MASK45 |
+               MCF_INTC_IMRH_INT_MASK46 |
+               MCF_INTC_IMRH_INT_MASK47 |
+               MCF_INTC_IMRH_INT_MASK48 );
+
+       /* Set up gpio outputs for MII lines */
+       MCF_GPIO_PAR_FECI2C |= (0 |
+               MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
+               MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
+       MCF_GPIO_PAR_FEC = (0 |
+               MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
+               MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
+}
+
+static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
+{
+       volatile fec_t *fecp;
+
+       fecp = fep->hwp;
+       fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
+       fecp->fec_x_cntrl = 0x00;
+
+       /*
+        * Set MII speed to 2.5 MHz
+        */
+       fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
+       fecp->fec_mii_speed = fep->phy_speed;
+
+       fec_restart(dev, 0);
+}
+
+static void __inline__ fec_get_mac(struct net_device *dev)
+{
+       struct fec_enet_private *fep = netdev_priv(dev);
+       volatile fec_t *fecp;
+       unsigned char *iap, tmpaddr[ETH_ALEN];
+
+       fecp = fep->hwp;
+
+       if (FEC_FLASHMAC) {
+               /*
+                * Get MAC address from FLASH.
+                * If it is all 1's or 0's, use the default.
+                */
+               iap = FEC_FLASHMAC;
+               if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+                   (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+                       iap = fec_mac_default;
+               if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+                   (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+                       iap = fec_mac_default;
+       } else {
+               *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
+               *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
+               iap = &tmpaddr[0];
+       }
+
+       memcpy(dev->dev_addr, iap, ETH_ALEN);
+
+       /* Adjust MAC if using default MAC address */
+       if (iap == fec_mac_default)
+               dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
+}
+
+static void __inline__ fec_enable_phy_intr(void)
+{
+}
+
+static void __inline__ fec_disable_phy_intr(void)
+{
+}
+
+static void __inline__ fec_phy_ack_intr(void)
+{
+}
+
+static void __inline__ fec_localhw_setup(void)
+{
+}
+
+/*
+ *     Do not need to make region uncached on 532x.
+ */
+static void __inline__ fec_uncache(unsigned long addr)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+
+
 #else
 
 /*
@@ -1985,9 +2154,12 @@ fec_enet_open(struct net_device *dev)
                mii_do_cmd(dev, fep->phy->config);
                mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
 
-               /* FIXME: use netif_carrier_{on,off} ; this polls
-                * until link is up which is wrong...  could be
-                * 30 seconds or more we are trapped in here. -jgarzik
+               /* Poll until the PHY tells us its configuration
+                * (not link state).
+                * Request is initiated by mii_do_cmd above, but answer
+                * comes by interrupt.
+                * This should take about 25 usec per register at 2.5 MHz,
+                * and we read approximately 5 registers.
                 */
                while(!fep->sequence_done)
                        schedule();
@@ -2253,15 +2425,11 @@ int __init fec_enet_init(struct net_device *dev)
        */
        fec_request_intrs(dev);
 
-       /* Clear and enable interrupts */
-       fecp->fec_ievent = 0xffc00000;
-       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
-               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
        fecp->fec_hash_table_high = 0;
        fecp->fec_hash_table_low = 0;
        fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
        fecp->fec_ecntrl = 2;
-       fecp->fec_r_des_active = 0x01000000;
+       fecp->fec_r_des_active = 0;
 
        dev->base_addr = (unsigned long)fecp;
 
@@ -2281,6 +2449,11 @@ int __init fec_enet_init(struct net_device *dev)
        /* setup MII interface */
        fec_set_mii(dev, fep);
 
+       /* Clear and enable interrupts */
+       fecp->fec_ievent = 0xffc00000;
+       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
+               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+
        /* Queue up command to detect the PHY and initialize the
         * remainder of the interface.
         */
@@ -2312,11 +2485,6 @@ fec_restart(struct net_device *dev, int duplex)
        fecp->fec_ecntrl = 1;
        udelay(10);
 
-       /* Enable interrupts we wish to service.
-       */
-       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
-                               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
-
        /* Clear any outstanding interrupt.
        */
        fecp->fec_ievent = 0xffc00000;
@@ -2408,7 +2576,12 @@ fec_restart(struct net_device *dev, int duplex)
        /* And last, enable the transmit and receive processing.
        */
        fecp->fec_ecntrl = 2;
-       fecp->fec_r_des_active = 0x01000000;
+       fecp->fec_r_des_active = 0;
+
+       /* Enable interrupts we wish to service.
+       */
+       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
+               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
 }
 
 static void
@@ -2420,9 +2593,16 @@ fec_stop(struct net_device *dev)
        fep = netdev_priv(dev);
        fecp = fep->hwp;
 
-       fecp->fec_x_cntrl = 0x01;       /* Graceful transmit stop */
-
-       while(!(fecp->fec_ievent & FEC_ENET_GRA));
+       /*
+       ** We cannot expect a graceful transmit stop without link !!!
+       */
+       if (fep->link)
+               {
+               fecp->fec_x_cntrl = 0x01;       /* Graceful transmit stop */
+               udelay(10);
+               if (!(fecp->fec_ievent & FEC_ENET_GRA))
+                       printk("fec_stop : Graceful transmit stop did not complete !\n");
+               }
 
        /* Whack a reset.  We should wait for this.
        */
index c6770377ef8746c384d815d5067a469d872a3b59..0cd07150bf4aeee6e3add86d7e6e5e23544c3288 100644 (file)
@@ -431,8 +431,7 @@ static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi)
        return bus;
 
 err:
-       if (bus)
-               kfree(bus);
+       kfree(bus);
        return ERR_PTR(ret);
 }
 
index 0d5fccc984bb2cf888b785447c43c4fcc19282eb..c9a46b89942af382ec10ac71f7a3710343fd0944 100644 (file)
@@ -436,7 +436,7 @@ static int __init dmascc_init(void)
 module_init(dmascc_init);
 module_exit(dmascc_exit);
 
-static void dev_setup(struct net_device *dev)
+static void __init dev_setup(struct net_device *dev)
 {
        dev->type = ARPHRD_AX25;
        dev->hard_header_len = AX25_MAX_HEADER_LEN;
index 2e4ecedba0572cc655b3827a39c88d0ddebb139b..5657049c216041faea5c59f61e37898643f14447 100644 (file)
@@ -226,7 +226,6 @@ static int full_duplex[MAX_UNITS];
                                 NATSEMI_PG1_NREGS)
 #define NATSEMI_REGS_VER       1 /* v1 added RFDR registers */
 #define NATSEMI_REGS_SIZE      (NATSEMI_NREGS * sizeof(u32))
-#define NATSEMI_DEF_EEPROM_SIZE        24 /* 12 16-bit values */
 
 /* Buffer sizes:
  * The nic writes 32-bit values, even if the upper bytes of
@@ -344,18 +343,6 @@ None characterised.
 
 
 
-enum pcistuff {
-       PCI_USES_IO = 0x01,
-       PCI_USES_MEM = 0x02,
-       PCI_USES_MASTER = 0x04,
-       PCI_ADDR0 = 0x08,
-       PCI_ADDR1 = 0x10,
-};
-
-/* MMIO operations required */
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-
-
 /*
  * Support for fibre connections on Am79C874:
  * This phy needs a special setup when connected to a fibre cable.
@@ -363,22 +350,25 @@ enum pcistuff {
  */
 #define PHYID_AM79C874 0x0022561b
 
-#define MII_MCTRL      0x15    /* mode control register */
-#define MII_FX_SEL     0x0001  /* 100BASE-FX (fiber) */
-#define MII_EN_SCRM    0x0004  /* enable scrambler (tp) */
+enum {
+       MII_MCTRL       = 0x15,         /* mode control register */
+       MII_FX_SEL      = 0x0001,       /* 100BASE-FX (fiber) */
+       MII_EN_SCRM     = 0x0004,       /* enable scrambler (tp) */
+};
 
  
 /* array of board data directly indexed by pci_tbl[x].driver_data */
 static const struct {
        const char *name;
        unsigned long flags;
+       unsigned int eeprom_size;
 } natsemi_pci_info[] __devinitdata = {
-       { "NatSemi DP8381[56]", PCI_IOTYPE },
+       { "NatSemi DP8381[56]", 0, 24 },
 };
 
-static struct pci_device_id natsemi_pci_tbl[] = {
-       { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815, PCI_ANY_ID, PCI_ANY_ID, },
-       { 0, },
+static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { }     /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl);
 
@@ -813,6 +803,42 @@ static void move_int_phy(struct net_device *dev, int addr)
        udelay(1);
 }
 
+static void __devinit natsemi_init_media (struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       u32 tmp;
+
+       netif_carrier_off(dev);
+
+       /* get the initial settings from hardware */
+       tmp            = mdio_read(dev, MII_BMCR);
+       np->speed      = (tmp & BMCR_SPEED100)? SPEED_100     : SPEED_10;
+       np->duplex     = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL   : DUPLEX_HALF;
+       np->autoneg    = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE;
+       np->advertising= mdio_read(dev, MII_ADVERTISE);
+
+       if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL
+        && netif_msg_probe(np)) {
+               printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s "
+                       "10%s %s duplex.\n",
+                       pci_name(np->pci_dev),
+                       (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)?
+                         "enabled, advertise" : "disabled, force",
+                       (np->advertising &
+                         (ADVERTISE_100FULL|ADVERTISE_100HALF))?
+                           "0" : "",
+                       (np->advertising &
+                         (ADVERTISE_100FULL|ADVERTISE_10FULL))?
+                           "full" : "half");
+       }
+       if (netif_msg_probe(np))
+               printk(KERN_INFO
+                       "natsemi %s: Transceiver status %#04x advertising %#04x.\n",
+                       pci_name(np->pci_dev), mdio_read(dev, MII_BMSR),
+                       np->advertising);
+
+}
+
 static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        const struct pci_device_id *ent)
 {
@@ -852,8 +878,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        iosize = pci_resource_len(pdev, pcibar);
        irq = pdev->irq;
 
-       if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER)
-               pci_set_master(pdev);
+       pci_set_master(pdev);
 
        dev = alloc_etherdev(sizeof (struct netdev_private));
        if (!dev)
@@ -892,7 +917,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
        np->hands_off = 0;
        np->intr_status = 0;
-       np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE;
+       np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size;
 
        /* Initial port:
         * - If the nic was configured to use an external phy and if find_mii
@@ -957,34 +982,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        if (mtu)
                dev->mtu = mtu;
 
-       netif_carrier_off(dev);
-
-       /* get the initial settings from hardware */
-       tmp            = mdio_read(dev, MII_BMCR);
-       np->speed      = (tmp & BMCR_SPEED100)? SPEED_100     : SPEED_10;
-       np->duplex     = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL   : DUPLEX_HALF;
-       np->autoneg    = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE;
-       np->advertising= mdio_read(dev, MII_ADVERTISE);
-
-       if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL
-        && netif_msg_probe(np)) {
-               printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s "
-                       "10%s %s duplex.\n",
-                       pci_name(np->pci_dev),
-                       (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)?
-                         "enabled, advertise" : "disabled, force",
-                       (np->advertising &
-                         (ADVERTISE_100FULL|ADVERTISE_100HALF))?
-                           "0" : "",
-                       (np->advertising &
-                         (ADVERTISE_100FULL|ADVERTISE_10FULL))?
-                           "full" : "half");
-       }
-       if (netif_msg_probe(np))
-               printk(KERN_INFO
-                       "natsemi %s: Transceiver status %#04x advertising %#04x.\n",
-                       pci_name(np->pci_dev), mdio_read(dev, MII_BMSR),
-                       np->advertising);
+       natsemi_init_media(dev);
 
        /* save the silicon revision for later querying */
        np->srr = readl(ioaddr + SiliconRev);
index fc08c4af506ca8194b7f4d3854181fdc5eed43b4..0e01c75da4296647884603414f9002fea6834e2a 100644 (file)
@@ -309,12 +309,6 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name);
 static void pcnet32_free_ring(struct net_device *dev);
 static void pcnet32_check_media(struct net_device *dev, int verbose);
 
-enum pci_flags_bit {
-       PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4,
-       PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 =
-           0x10 << 2, PCI_ADDR3 = 0x10 << 3,
-};
-
 static u16 pcnet32_wio_read_csr(unsigned long addr, int index)
 {
        outw(index, addr + PCNET32_WIO_RAP);
index bef79e454c337c0c3d9bf5b1f365be56470b94a9..3f702c503afe9377aeddb835c9c9eb7c8707665a 100644 (file)
@@ -123,9 +123,9 @@ static int lxt971_config_intr(struct phy_device *phydev)
 }
 
 static struct phy_driver lxt970_driver = {
-       .phy_id         = 0x07810000,
+       .phy_id         = 0x78100000,
        .name           = "LXT970",
-       .phy_id_mask    = 0x0fffffff,
+       .phy_id_mask    = 0xfffffff0,
        .features       = PHY_BASIC_FEATURES,
        .flags          = PHY_HAS_INTERRUPT,
        .config_init    = lxt970_config_init,
@@ -137,9 +137,9 @@ static struct phy_driver lxt970_driver = {
 };
 
 static struct phy_driver lxt971_driver = {
-       .phy_id         = 0x0001378e,
+       .phy_id         = 0x001378e0,
        .name           = "LXT971",
-       .phy_id_mask    = 0x0fffffff,
+       .phy_id_mask    = 0xfffffff0,
        .features       = PHY_BASIC_FEATURES,
        .flags          = PHY_HAS_INTERRUPT,
        .config_aneg    = genphy_config_aneg,
index 19a4a16055dc2435e13a0103d90663dde5485ac4..1608efab4e3de39c914dfb964dfbd767a2ccea4b 100644 (file)
@@ -3354,8 +3354,8 @@ static int __devinit skge_probe(struct pci_dev *pdev,
        if (err)
                goto err_out_free_irq;
 
-       printk(KERN_INFO PFX DRV_VERSION " addr 0x%lx irq %d chip %s rev %d\n",
-              pci_resource_start(pdev, 0), pdev->irq,
+       printk(KERN_INFO PFX DRV_VERSION " addr 0x%llx irq %d chip %s rev %d\n",
+              (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
               skge_board_name(hw), hw->chip_rev);
 
        if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
index d3577871be28ddc3897d835a59f5f83fbc6b3c0f..e122007e16da08b599d5644a503f34b2f359758f 100644 (file)
@@ -3311,9 +3311,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        if (err)
                goto err_out_iounmap;
 
-       printk(KERN_INFO PFX "v%s addr 0x%lx irq %d Yukon-%s (0x%x) rev %d\n",
-              DRV_VERSION, pci_resource_start(pdev, 0), pdev->irq,
-              yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+       printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+              DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
+              pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
               hw->chip_id, hw->chip_rev);
 
        dev = sky2_init_netdev(hw, 0, using_dac);
index 5f743b972949930929335ed20fb55288d47b1dd1..fc2468ecce0b1db743e8158d07468c15f1eca80c 100644 (file)
@@ -2007,8 +2007,8 @@ static int __init de_init_one (struct pci_dev *pdev,
        }
        if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
                rc = -EIO;
-               printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
-                      pci_resource_len(pdev, 1), pci_name(pdev));
+               printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
+                      (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
                goto err_out_res;
        }
 
@@ -2016,8 +2016,9 @@ static int __init de_init_one (struct pci_dev *pdev,
        regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
        if (!regs) {
                rc = -EIO;
-               printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
-                      pci_resource_len(pdev, 1), pciaddr, pci_name(pdev));
+               printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
+                       (unsigned long long)pci_resource_len(pdev, 1),
+                       pciaddr, pci_name(pdev));
                goto err_out_res;
        }
        dev->base_addr = (unsigned long) regs;
index e0de66739a422744616ae3205e89db5504f2036c..53fd9b56d0bd7967b51cbf794128c1c15918979b 100644 (file)
@@ -1350,10 +1350,10 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
        if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
-               printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "
+               printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, "
                        "aborting\n", pci_name(pdev),
-                       pci_resource_len (pdev, 0),
-                       pci_resource_start (pdev, 0));
+                       (unsigned long long)pci_resource_len (pdev, 0),
+                       (unsigned long long)pci_resource_start (pdev, 0));
                goto err_out_free_netdev;
        }
 
index 8fea2aa455d4690a10763f7a4dc070c755a9c3d0..602a6e5002a076fcefb64a04742535c2012e8b4d 100644 (file)
@@ -212,26 +212,15 @@ Test with 'ping -s 10000' on a fast computer.
 /*
   PCI probe table.
 */
-enum pci_id_flags_bits {
-        /* Set PCI command register bits before calling probe1(). */
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-        /* Read and map the single following PCI BAR. */
-        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
 enum chip_capability_flags {
-       CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,};
-#ifdef USE_IO_OPS
-#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
-#else
-#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
-#endif
+       CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,
+};
 
-static struct pci_device_id w840_pci_tbl[] = {
+static const struct pci_device_id w840_pci_tbl[] = {
        { 0x1050, 0x0840, PCI_ANY_ID, 0x8153,     0, 0, 0 },
        { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
        { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
-       { 0, }
+       { }
 };
 MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
 
@@ -241,18 +230,17 @@ struct pci_id_info {
                 int     pci, pci_mask, subsystem, subsystem_mask;
                 int revision, revision_mask;                            /* Only 8 bits. */
         } id;
-        enum pci_id_flags_bits pci_flags;
         int io_size;                            /* Needed for I/O region check or ioremap(). */
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 static struct pci_id_info pci_id_tbl[] = {
        {"Winbond W89c840",                     /* Sometime a Level-One switch card. */
         { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
-        W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
+          128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
        {"Winbond W89c840", { 0x08401050, 0xffffffff, },
-        W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
+          128, CanHaveMII | HasBrokenTx},
        {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
-        W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
+          128, CanHaveMII | HasBrokenTx},
        {NULL,},                                        /* 0 terminated list. */
 };
 
index e49e8b520c28120f9aaa346d80b310a5b6e2814b..e24d2dafcf6c3695662c4ea3cdb8ece7cd672e38 100644 (file)
@@ -2568,9 +2568,10 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_drvdata(pdev, dev);
 
-       printk(KERN_INFO "%s: %s at %s 0x%lx, ",
+       printk(KERN_INFO "%s: %s at %s 0x%llx, ",
               dev->name, typhoon_card_info[card_id].name,
-              use_mmio ? "MMIO" : "IO", pci_resource_start(pdev, use_mmio));
+              use_mmio ? "MMIO" : "IO",
+              (unsigned long long)pci_resource_start(pdev, use_mmio));
        for(i = 0; i < 5; i++)
                printk("%2.2x:", dev->dev_addr[i]);
        printk("%2.2x\n", dev->dev_addr[i]);
index b60ef02db7b06b6a8868fce2e4ec44fb304b6eb9..c92ac9fde0831ff6175f17bc45bfdb1876c158e3 100644 (file)
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Sources of information:
  *    Hitachi HD64570 SCA User's Manual
index 4505540e3c591611182645433ac5dbc353e07a2a..04a376ec0ed84ab737c373342914ed172a4b1129 100644 (file)
@@ -732,15 +732,15 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev,
        ioaddr = ioremap(pci_resource_start(pdev, 0),
                                        pci_resource_len(pdev, 0));
        if (!ioaddr) {
-               printk(KERN_ERR "%s: cannot remap MMIO region %lx @ %lx\n",
-                       DRV_NAME, pci_resource_len(pdev, 0),
-                       pci_resource_start(pdev, 0));
+               printk(KERN_ERR "%s: cannot remap MMIO region %llx @ %llx\n",
+                       DRV_NAME, (unsigned long long)pci_resource_len(pdev, 0),
+                       (unsigned long long)pci_resource_start(pdev, 0));
                rc = -EIO;
                goto err_free_mmio_regions_2;
        }
-       printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d\n",
-               pci_resource_start(pdev, 0),
-               pci_resource_start(pdev, 1), pdev->irq);
+       printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#llx (regs), %#llx (lbi), IRQ %d\n",
+               (unsigned long long)pci_resource_start(pdev, 0),
+               (unsigned long long)pci_resource_start(pdev, 1), pdev->irq);
 
        /* Cf errata DS5 p.2 */
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
index b7d88db89a5c7918e5a827aeb6465cab7b5411a7..e013b817cab8dbb22fd1df3f426b45d3d260e223 100644 (file)
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Note: integrated CSU/DSU/DDS are not supported by this driver
  *
index a3e65d1bc19bbcddda71bd74f2ec707a6a0bf5f1..d7897ae89f904dc906250c67cdde073f2243e7ed 100644 (file)
@@ -3445,9 +3445,9 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        card = (pc300_t *) kmalloc(sizeof(pc300_t), GFP_KERNEL);
        if (card == NULL) {
-               printk("PC300 found at RAM 0x%08lx, "
+               printk("PC300 found at RAM 0x%016llx, "
                       "but could not allocate card structure.\n",
-                      pci_resource_start(pdev, 3));
+                      (unsigned long long)pci_resource_start(pdev, 3));
                err = -ENOMEM;
                goto err_disable_dev;
        }
index 670e8bd2245c7fef651df170cf889fc8e33c4f51..24c3c57c13c933d90f50933d1540791425d61f13 100644 (file)
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Sources of information:
  *    Hitachi HD64572 SCA-II User's Manual
index 081a8999666e7e168404141073c687d0af2dfe0b..a8a8f975432fe1e32a3fb04aa0a4bc2d59d94e24 100644 (file)
@@ -1229,12 +1229,6 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
        return error;
 }
 
-static void ipw_free_error_log(struct ipw_fw_error *error)
-{
-       if (error)
-               kfree(error);
-}
-
 static ssize_t show_event_log(struct device *d,
                              struct device_attribute *attr, char *buf)
 {
@@ -1296,10 +1290,9 @@ static ssize_t clear_error(struct device *d,
                           const char *buf, size_t count)
 {
        struct ipw_priv *priv = dev_get_drvdata(d);
-       if (priv->error) {
-               ipw_free_error_log(priv->error);
-               priv->error = NULL;
-       }
+
+       kfree(priv->error);
+       priv->error = NULL;
        return count;
 }
 
@@ -1970,8 +1963,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
                                struct ipw_fw_error *error =
                                    ipw_alloc_error_log(priv);
                                ipw_dump_error_log(priv, error);
-                               if (error)
-                                       ipw_free_error_log(error);
+                               kfree(error);
                        }
 #endif
                } else {
@@ -11693,10 +11685,8 @@ static void ipw_pci_remove(struct pci_dev *pdev)
                }
        }
 
-       if (priv->error) {
-               ipw_free_error_log(priv->error);
-               priv->error = NULL;
-       }
+       kfree(priv->error);
+       priv->error = NULL;
 
 #ifdef CONFIG_IPW2200_PROMISCUOUS
        ipw_prom_free(priv);
index ecec8e5db786e66dc4128edd216d8cb8a0072eb8..569305f57561fd5304a3ae73b490f78edebfe380 100644 (file)
@@ -234,14 +234,6 @@ See Packet Engines confidential appendix (prototype chips only).
 
 \f
 
-enum pci_id_flags_bits {
-       /* Set PCI command register bits before calling probe1(). */
-       PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-       /* Read and map the single following PCI BAR. */
-       PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-       PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-       PCI_UNUSED_IRQ=0x800,
-};
 enum capability_flags {
        HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
        HasMACAddrBug=32, /* Only on early revs.  */
@@ -249,11 +241,6 @@ enum capability_flags {
 };
 /* The PCI I/O space extent. */
 #define YELLOWFIN_SIZE 0x100
-#ifdef USE_IO_OPS
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
-#else
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-#endif
 
 struct pci_id_info {
         const char *name;
@@ -261,24 +248,23 @@ struct pci_id_info {
                 int     pci, pci_mask, subsystem, subsystem_mask;
                 int revision, revision_mask;                            /* Only 8 bits. */
         } id;
-        enum pci_id_flags_bits pci_flags;
         int io_size;                            /* Needed for I/O region check or ioremap(). */
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 
 static const struct pci_id_info pci_id_tbl[] = {
        {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
-        PCI_IOTYPE, YELLOWFIN_SIZE,
+        YELLOWFIN_SIZE,
         FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
        {"Symbios SYM83C885", { 0x07011000, 0xffffffff},
-        PCI_IOTYPE, YELLOWFIN_SIZE, HasMII | DontUseEeprom },
-       {NULL,},
+        YELLOWFIN_SIZE, HasMII | DontUseEeprom },
+       { }
 };
 
-static struct pci_device_id yellowfin_pci_tbl[] = {
+static const struct pci_device_id yellowfin_pci_tbl[] = {
        { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
-       { 0, }
+       { }
 };
 MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl);
 
index 3f5de867acd7cb4b9dd7229194e8c14f7bdea840..1d3b84b4af3fc5fb0937763098f7f65e57fb80fd 100644 (file)
@@ -140,18 +140,37 @@ config CHASSIS_LCD_LED
          If unsure, say Y.
 
 config PDC_CHASSIS
-       bool "PDC chassis State Panel support"
+       bool "PDC chassis state codes support"
        default y
        help
-         Say Y here if you want to enable support for the LED State front
-         panel as found on E class, and support for the GSP Virtual Front
-         Panel (LED State and message logging)  as found on high end
-         servers such as A, L and N-class.
-         
-         This has nothing to do with Chassis LCD and LED support.
+         Say Y here if you want to enable support for Chassis codes.
+         That includes support for LED State front panel as found on E
+         class, and support for the GSP Virtual Front Panel (LED State and
+         message logging)  as found on high end servers such as A, L and
+         N-class.
+         This driver will also display progress messages on LCD display,
+         such as "INI", "RUN" and "FLT", and might thus clobber messages
+         shown by the LED/LCD driver.
+         This driver updates the state panel (LED and/or LCD) upon system
+         state change (eg: boot, shutdown or panic).
          
          If unsure, say Y.
 
+
+config PDC_CHASSIS_WARN
+       bool "PDC chassis warnings support"
+       depends on PROC_FS
+       default y
+       help
+         Say Y here if you want to enable support for Chassis warnings.
+         This will add a proc entry '/proc/chassis' giving some information
+         about the overall health state of the system.
+         This includes NVRAM battery level, overtemp or failures such as
+         fans or power units.
+
+         If unsure, say Y.
+
+
 config PDC_STABLE
        tristate "PDC Stable Storage support"
        depends on SYSFS
index 6e8ed0c81a6cbd5883fafa74b940e77077d9cee7..ce0a6ebcff15dfa74a4ff8e8812878078a8e46a9 100644 (file)
@@ -299,7 +299,7 @@ struct pci_port_ops dino_port_ops = {
 
 static void dino_disable_irq(unsigned int irq)
 {
-       struct dino_device *dino_dev = irq_desc[irq].handler_data;
+       struct dino_device *dino_dev = irq_desc[irq].chip_data;
        int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
 
        DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq);
@@ -311,7 +311,7 @@ static void dino_disable_irq(unsigned int irq)
 
 static void dino_enable_irq(unsigned int irq)
 {
-       struct dino_device *dino_dev = irq_desc[irq].handler_data;
+       struct dino_device *dino_dev = irq_desc[irq].chip_data;
        int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
        u32 tmp;
 
index 9d3bd15bf53be98c071b2c7d7585ba689974b6f9..58f0ce8d78e066c2f75fb63371924db5f41f549f 100644 (file)
@@ -350,7 +350,7 @@ static int __devinit eisa_probe(struct parisc_device *dev)
        irq_desc[2].action = &irq2_action;
        
        for (i = 0; i < 16; i++) {
-               irq_desc[i].handler = &eisa_interrupt_type;
+               irq_desc[i].chip = &eisa_interrupt_type;
        }
        
        EISA_bus = 1;
index 16d40f95978d135d8cf310efff612094c1e6d451..5476ba7709b3cc4a9a7aec1612d74be7898a0f83 100644 (file)
@@ -109,7 +109,7 @@ int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
 
 static void gsc_asic_disable_irq(unsigned int irq)
 {
-       struct gsc_asic *irq_dev = irq_desc[irq].handler_data;
+       struct gsc_asic *irq_dev = irq_desc[irq].chip_data;
        int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
        u32 imr;
 
@@ -124,7 +124,7 @@ static void gsc_asic_disable_irq(unsigned int irq)
 
 static void gsc_asic_enable_irq(unsigned int irq)
 {
-       struct gsc_asic *irq_dev = irq_desc[irq].handler_data;
+       struct gsc_asic *irq_dev = irq_desc[irq].chip_data;
        int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
        u32 imr;
 
@@ -164,8 +164,8 @@ int gsc_assign_irq(struct hw_interrupt_type *type, void *data)
        if (irq > GSC_IRQ_MAX)
                return NO_IRQ;
 
-       irq_desc[irq].handler = type;
-       irq_desc[irq].handler_data = data;
+       irq_desc[irq].chip = type;
+       irq_desc[irq].chip_data = data;
        return irq++;
 }
 
index 7a458d5bc75134d925aa272b34af805f1646384e..1fbda77cefc29bfb0bbe820314feabce0d2c9700 100644 (file)
@@ -619,7 +619,7 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
 
 static struct vector_info *iosapic_get_vector(unsigned int irq)
 {
-       return irq_desc[irq].handler_data;
+       return irq_desc[irq].chip_data;
 }
 
 static void iosapic_disable_irq(unsigned int irq)
index bbeabe3fc4c6788984f3bd9567b3543681c1bf5a..ea1b7a63598e1c4fc87ee001a66293cb2fe92b37 100644 (file)
  *    following code can deal with just 96 bytes of Stable Storage, and all
  *    sizes between 96 and 192 bytes (provided they are multiple of struct
  *    device_path size, eg: 128, 160 and 192) to provide full information.
- *    The code makes no use of data above 192 bytes. One last word: there's one
- *    path we can always count on: the primary path.
+ *    One last word: there's one path we can always count on: the primary path.
+ *    Anything above 224 bytes is used for 'osdep2' OS-dependent storage area.
+ *
+ *    The first OS-dependent area should always be available. Obviously, this is
+ *    not true for the other one. Also bear in mind that reading/writing from/to
+ *    osdep2 is much more expensive than from/to osdep1.
+ *    NOTE: We do not handle the 2 bytes OS-dep area at 0x5D, nor the first
+ *    2 bytes of storage available right after OSID. That's a total of 4 bytes
+ *    sacrificed: -ETOOLAZY :P
  *
  *    The current policy wrt file permissions is:
  *     - write: root only
 #include <asm/uaccess.h>
 #include <asm/hardware.h>
 
-#define PDCS_VERSION   "0.22"
+#define PDCS_VERSION   "0.30"
 #define PDCS_PREFIX    "PDC Stable Storage"
 
 #define PDCS_ADDR_PPRI 0x00
 #define PDCS_ADDR_OSID 0x40
+#define PDCS_ADDR_OSD1 0x48
+#define PDCS_ADDR_DIAG 0x58
 #define PDCS_ADDR_FSIZ 0x5C
 #define PDCS_ADDR_PCON 0x60
 #define PDCS_ADDR_PALT 0x80
 #define PDCS_ADDR_PKBD 0xA0
+#define PDCS_ADDR_OSD2 0xE0
 
 MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>");
 MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
@@ -82,6 +92,9 @@ MODULE_VERSION(PDCS_VERSION);
 /* holds Stable Storage size. Initialized once and for all, no lock needed */
 static unsigned long pdcs_size __read_mostly;
 
+/* holds OS ID. Initialized once and for all, hopefully to 0x0006 */
+static u16 pdcs_osid __read_mostly;
+
 /* This struct defines what we need to deal with a parisc pdc path entry */
 struct pdcspath_entry {
        rwlock_t rw_lock;               /* to protect path entry access */
@@ -609,27 +622,64 @@ static ssize_t
 pdcs_osid_read(struct subsystem *entry, char *buf)
 {
        char *out = buf;
-       __u32 result;
-       char *tmpstr = NULL;
 
        if (!entry || !buf)
                return -EINVAL;
 
-       /* get OSID */
-       if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+       out += sprintf(out, "%s dependent data (0x%.4x)\n",
+               os_id_to_string(pdcs_osid), pdcs_osid);
+
+       return out - buf;
+}
+
+/**
+ * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This can hold 16 bytes of OS-Dependent data.
+ */
+static ssize_t
+pdcs_osdep1_read(struct subsystem *entry, char *buf)
+{
+       char *out = buf;
+       u32 result[4];
+
+       if (!entry || !buf)
+               return -EINVAL;
+
+       if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
                return -EIO;
 
-       /* the actual result is 16 bits away */
-       switch (result >> 16) {
-               case 0x0000:    tmpstr = "No OS-dependent data"; break;
-               case 0x0001:    tmpstr = "HP-UX dependent data"; break;
-               case 0x0002:    tmpstr = "MPE-iX dependent data"; break;
-               case 0x0003:    tmpstr = "OSF dependent data"; break;
-               case 0x0004:    tmpstr = "HP-RT dependent data"; break;
-               case 0x0005:    tmpstr = "Novell Netware dependent data"; break;
-               default:        tmpstr = "Unknown"; break;
-       }
-       out += sprintf(out, "%s (0x%.4x)\n", tmpstr, (result >> 16));
+       out += sprintf(out, "0x%.8x\n", result[0]);
+       out += sprintf(out, "0x%.8x\n", result[1]);
+       out += sprintf(out, "0x%.8x\n", result[2]);
+       out += sprintf(out, "0x%.8x\n", result[3]);
+
+       return out - buf;
+}
+
+/**
+ * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * I have NFC how to interpret the content of that register ;-).
+ */
+static ssize_t
+pdcs_diagnostic_read(struct subsystem *entry, char *buf)
+{
+       char *out = buf;
+       u32 result;
+
+       if (!entry || !buf)
+               return -EINVAL;
+
+       /* get diagnostic */
+       if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK)
+               return -EIO;
+
+       out += sprintf(out, "0x%.4x\n", (result >> 16));
 
        return out - buf;
 }
@@ -645,7 +695,7 @@ static ssize_t
 pdcs_fastsize_read(struct subsystem *entry, char *buf)
 {
        char *out = buf;
-       __u32 result;
+       u32 result;
 
        if (!entry || !buf)
                return -EINVAL;
@@ -663,6 +713,39 @@ pdcs_fastsize_read(struct subsystem *entry, char *buf)
        return out - buf;
 }
 
+/**
+ * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
+ */
+static ssize_t
+pdcs_osdep2_read(struct subsystem *entry, char *buf)
+{
+       char *out = buf;
+       unsigned long size;
+       unsigned short i;
+       u32 result;
+
+       if (unlikely(pdcs_size <= 224))
+               return -ENODATA;
+
+       size = pdcs_size - 224;
+
+       if (!entry || !buf)
+               return -EINVAL;
+
+       for (i=0; i<size; i+=4) {
+               if (unlikely(pdc_stable_read(PDCS_ADDR_OSD2 + i, &result,
+                                       sizeof(result)) != PDC_OK))
+                       return -EIO;
+               out += sprintf(out, "0x%.8x\n", result);
+       }
+
+       return out - buf;
+}
+
 /**
  * pdcs_auto_write - This function handles autoboot/search flag modifying.
  * @entry: An allocated and populated subsytem struct. We don't use it tho.
@@ -770,13 +853,100 @@ pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count)
        return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH);
 }
 
+/**
+ * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * This can store 16 bytes of OS-Dependent data. We use a byte-by-byte
+ * write approach. It's up to userspace to deal with it when constructing
+ * its input buffer.
+ */
+static ssize_t
+pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
+{
+       u8 in[16];
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (!entry || !buf || !count)
+               return -EINVAL;
+
+       if (unlikely(pdcs_osid != OS_ID_LINUX))
+               return -EPERM;
+
+       if (count > 16)
+               return -EMSGSIZE;
+
+       /* We'll use a local copy of buf */
+       memset(in, 0, 16);
+       memcpy(in, buf, count);
+
+       if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK)
+               return -EIO;
+
+       return count;
+}
+
+/**
+ * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * This can store pdcs_size - 224 bytes of OS-Dependent data. We use a
+ * byte-by-byte write approach. It's up to userspace to deal with it when
+ * constructing its input buffer.
+ */
+static ssize_t
+pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count)
+{
+       unsigned long size;
+       unsigned short i;
+       u8 in[4];
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (!entry || !buf || !count)
+               return -EINVAL;
+
+       if (unlikely(pdcs_size <= 224))
+               return -ENOSYS;
+
+       if (unlikely(pdcs_osid != OS_ID_LINUX))
+               return -EPERM;
+
+       size = pdcs_size - 224;
+
+       if (count > size)
+               return -EMSGSIZE;
+
+       /* We'll use a local copy of buf */
+
+       for (i=0; i<count; i+=4) {
+               memset(in, 0, 4);
+               memcpy(in, buf+i, (count-i < 4) ? count-i : 4);
+               if (unlikely(pdc_stable_write(PDCS_ADDR_OSD2 + i, &in,
+                                       sizeof(in)) != PDC_OK))
+                       return -EIO;
+       }
+
+       return count;
+}
+
 /* The remaining attributes. */
 static PDCS_ATTR(size, 0444, pdcs_size_read, NULL);
 static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
 static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
 static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL);
-static PDCS_ATTR(osid, 0400, pdcs_osid_read, NULL);
+static PDCS_ATTR(osid, 0444, pdcs_osid_read, NULL);
+static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write);
+static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
 static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
+static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
 
 static struct subsys_attribute *pdcs_subsys_attrs[] = {
        &pdcs_attr_size,
@@ -784,7 +954,10 @@ static struct subsys_attribute *pdcs_subsys_attrs[] = {
        &pdcs_attr_autosearch,
        &pdcs_attr_timer,
        &pdcs_attr_osid,
+       &pdcs_attr_osdep1,
+       &pdcs_attr_diagnostic,
        &pdcs_attr_fastsize,
+       &pdcs_attr_osdep2,
        NULL,
 };
 
@@ -865,6 +1038,7 @@ pdc_stable_init(void)
 {
        struct subsys_attribute *attr;
        int i, rc = 0, error = 0;
+       u32 result;
 
        /* find the size of the stable storage */
        if (pdc_stable_get_size(&pdcs_size) != PDC_OK) 
@@ -876,6 +1050,13 @@ pdc_stable_init(void)
 
        printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION);
 
+       /* get OSID */
+       if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+               return -EIO;
+
+       /* the actual result is 16 bits away */
+       pdcs_osid = (u16)(result >> 16);
+
        /* For now we'll register the stable subsys within this driver */
        if ((rc = firmware_register(&stable_subsys)))
                goto fail_firmreg;
@@ -887,7 +1068,7 @@ pdc_stable_init(void)
        
        /* register the paths subsys as a subsystem of stable subsys */
        kset_set_kset_s(&paths_subsys, stable_subsys);
-       if ((rc= subsystem_register(&paths_subsys)))
+       if ((rc = subsystem_register(&paths_subsys)))
                goto fail_subsysreg;
 
        /* now we create all "files" for the paths subsys */
index 278f325021ee25d748d04e780b110355b806102a..d09e39e39c60cbbef178b3e39c6b3e0c1a7ab7c8 100644 (file)
@@ -316,10 +316,10 @@ static int reserve_sba_gart = 1;
 **
 ** Superdome (in particular, REO) allows only 64-bit CSR accesses.
 */
-#define READ_REG32(addr)        le32_to_cpu(__raw_readl(addr))
-#define READ_REG64(addr)        le64_to_cpu(__raw_readq(addr))
-#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr)
-#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr)
+#define READ_REG32(addr)       readl(addr)
+#define READ_REG64(addr)       readq(addr)
+#define WRITE_REG32(val, addr) writel((val), (addr))
+#define WRITE_REG64(val, addr) writeq((val), (addr))
 
 #ifdef CONFIG_64BIT
 #define READ_REG(addr)         READ_REG64(addr)
@@ -1427,7 +1427,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
        iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT));
        ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
 
-       DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits)\n",
+       DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n",
                __FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20,
                iov_order + PAGE_SHIFT);
 
@@ -1764,7 +1764,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
 
        sba_dev->num_ioc = num_ioc;
        for (i = 0; i < num_ioc; i++) {
-               unsigned long ioc_hpa = sba_dev->ioc[i].ioc_hpa;
+               void __iomem *ioc_hpa = sba_dev->ioc[i].ioc_hpa;
                unsigned int j;
 
                for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) {
@@ -1776,7 +1776,8 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
                         * Improves netperf UDP_STREAM by ~10% for bcm5701.
                         */
                        if (IS_PLUTO(sba_dev->iodc)) {
-                               unsigned long rope_cfg, cfg_val;
+                               void __iomem *rope_cfg;
+                               unsigned long cfg_val;
 
                                rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j;
                                cfg_val = READ_REG(rope_cfg);
@@ -1902,7 +1903,7 @@ sba_common_init(struct sba_device *sba_dev)
         * (bit #61, big endian), we have to flush and sync every time
         * IO-PDIR is changed in Ike/Astro.
         */
-       if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) {
+       if (ioc_needs_fdc) {
                printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n");
        } else {
                printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n");
index 828eb45062de3fa51182d1c61660961307fc0b11..a988dc7a9abd33a4c7f579bcf15e7a3aab003dfe 100644 (file)
@@ -360,7 +360,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
 #endif
 
        for (i = 0; i < 16; i++) {
-               irq_desc[i].handler = &superio_interrupt_type;
+               irq_desc[i].chip = &superio_interrupt_type;
        }
 
        /*
index 7230926820234f3c676d50397abcdf41be4a7b52..5f7db9d2436e76141e15d50a44e9f1fc38e54378 100644 (file)
  */
 int
 pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
-       unsigned long size, unsigned long align, unsigned long min,
-       unsigned int type_mask,
-       void (*alignf)(void *, struct resource *,
-                       unsigned long, unsigned long),
-       void *alignf_data)
+               resource_size_t size, resource_size_t align,
+               resource_size_t min, unsigned int type_mask,
+               void (*alignf)(void *, struct resource *, resource_size_t,
+                               resource_size_t),
+               void *alignf_data)
 {
        int i, ret = -ENOMEM;
 
index f7cb00da38dfabbfd32e6c6ec366bf261f9ed7e4..1ec165df85223e4495ebb310b2702b70a1e14fd6 100644 (file)
@@ -95,8 +95,8 @@ static int zt5550_hc_config(struct pci_dev *pdev)
 
        hc_dev = pdev;
        dbg("hc_dev = %p", hc_dev);
-       dbg("pci resource start %lx", pci_resource_start(hc_dev, 1));
-       dbg("pci resource len %lx", pci_resource_len(hc_dev, 1));
+       dbg("pci resource start %llx", (unsigned long long)pci_resource_start(hc_dev, 1));
+       dbg("pci resource len %llx", (unsigned long long)pci_resource_len(hc_dev, 1));
 
        if(!request_mem_region(pci_resource_start(hc_dev, 1),
                                pci_resource_len(hc_dev, 1), MY_NAME)) {
@@ -108,8 +108,9 @@ static int zt5550_hc_config(struct pci_dev *pdev)
        hc_registers =
            ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1));
        if(!hc_registers) {
-               err("cannot remap MMIO region %lx @ %lx",
-                   pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1));
+               err("cannot remap MMIO region %llx @ %llx",
+                       (unsigned long long)pci_resource_len(hc_dev, 1),
+                       (unsigned long long)pci_resource_start(hc_dev, 1));
                ret = -ENODEV;
                goto exit_release_region;
        }
index 9bc1deb8df524225decdc7a5322d72ce2638f7bc..f8658d63f0773ca7022505bbe0aef995e4aaca12 100644 (file)
@@ -1089,8 +1089,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        
        dbg("pdev = %p\n", pdev);
-       dbg("pci resource start %lx\n", pci_resource_start(pdev, 0));
-       dbg("pci resource len %lx\n", pci_resource_len(pdev, 0));
+       dbg("pci resource start %llx\n", (unsigned long long)pci_resource_start(pdev, 0));
+       dbg("pci resource len %llx\n", (unsigned long long)pci_resource_len(pdev, 0));
 
        if (!request_mem_region(pci_resource_start(pdev, 0),
                                pci_resource_len(pdev, 0), MY_NAME)) {
@@ -1102,9 +1102,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0),
                                        pci_resource_len(pdev, 0));
        if (!ctrl->hpc_reg) {
-               err("cannot remap MMIO region %lx @ %lx\n",
-                               pci_resource_len(pdev, 0),
-                               pci_resource_start(pdev, 0));
+               err("cannot remap MMIO region %llx @ %llx\n",
+                   (unsigned long long)pci_resource_len(pdev, 0),
+                   (unsigned long long)pci_resource_start(pdev, 0));
                rc = -ENODEV;
                goto err_free_mem_region;
        }
index d77138ecb0981ec827a6d482d96f31eb6c5acc43..11f7858f0064f7a6ef992e7de171468e53806208 100644 (file)
@@ -1398,8 +1398,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 
        for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
                if (pci_resource_len(pdev, rc) > 0)
-                       dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
-                               pci_resource_start(pdev, rc), pci_resource_len(pdev, rc));
+                       dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
+                           (unsigned long long)pci_resource_start(pdev, rc),
+                           (unsigned long long)pci_resource_len(pdev, rc));
 
        info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 
                pdev->subsystem_vendor, pdev->subsystem_device);
index f5cfbf2c047c92796c7bdde79d4dbc33c977c6a8..620e1139e607c763dfaa69ff25413c971de82310 100644 (file)
@@ -51,8 +51,10 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
                res = bus->resource[index];
                if (res && (res->flags & IORESOURCE_MEM) &&
                                !(res->flags & IORESOURCE_PREFETCH)) {
-                       out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
-                                       res->start, (res->end - res->start));
+                       out += sprintf(out, "start = %8.8llx, "
+                                       "length = %8.8llx\n",
+                                       (unsigned long long)res->start,
+                                       (unsigned long long)(res->end - res->start));
                }
        }
        out += sprintf(out, "Free resources: prefetchable memory\n");
@@ -60,16 +62,20 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
                res = bus->resource[index];
                if (res && (res->flags & IORESOURCE_MEM) &&
                               (res->flags & IORESOURCE_PREFETCH)) {
-                       out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
-                                       res->start, (res->end - res->start));
+                       out += sprintf(out, "start = %8.8llx, "
+                                       "length = %8.8llx\n",
+                                       (unsigned long long)res->start,
+                                       (unsigned long long)(res->end - res->start));
                }
        }
        out += sprintf(out, "Free resources: IO\n");
        for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
                res = bus->resource[index];
                if (res && (res->flags & IORESOURCE_IO)) {
-                       out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
-                                       res->start, (res->end - res->start));
+                       out += sprintf(out, "start = %8.8llx, "
+                                       "length = %8.8llx\n",
+                                       (unsigned long long)res->start,
+                                       (unsigned long long)(res->end - res->start));
                }
        }
        out += sprintf(out, "Free resources: bus numbers\n");
index 7f8429284fabe0663e4c6dc30fc6deefeaa178e3..76d023d8a33b92c7f940c05815434061f47a6adb 100644 (file)
@@ -429,12 +429,12 @@ static void irq_handler_init(int cap_id, int pos, int mask)
 
        spin_lock_irqsave(&irq_desc[pos].lock, flags);
        if (cap_id == PCI_CAP_ID_MSIX)
-               irq_desc[pos].handler = &msix_irq_type;
+               irq_desc[pos].chip = &msix_irq_type;
        else {
                if (!mask)
-                       irq_desc[pos].handler = &msi_irq_wo_maskbit_type;
+                       irq_desc[pos].chip = &msi_irq_wo_maskbit_type;
                else
-                       irq_desc[pos].handler = &msi_irq_w_maskbit_type;
+                       irq_desc[pos].chip = &msi_irq_w_maskbit_type;
        }
        spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
 }
index bc405c035ce34b4ae00d54a61286782e31416125..606f9b6f70ebe220617aa437982c4f5287046d40 100644 (file)
@@ -87,7 +87,7 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
        char * str = buf;
        int i;
        int max = 7;
-       u64 start, end;
+       resource_size_t start, end;
 
        if (pci_dev->subordinate)
                max = DEVICE_COUNT_RESOURCE;
@@ -365,7 +365,7 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
                                                       struct device, kobj));
        struct resource *res = (struct resource *)attr->private;
        enum pci_mmap_state mmap_type;
-       u64 start, end;
+       resource_size_t start, end;
        int i;
 
        for (i = 0; i < PCI_ROM_RESOURCE; i++)
index 23d3b17c8cad2cacacb32bd042aefa2c532eb848..cf57d7de3765fcceb37216501c0ace480cc95fa2 100644 (file)
@@ -691,10 +691,12 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
        return 0;
 
 err_out:
-       printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+       printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%llx@%llx "
+               "for device %s\n",
                pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
                bar + 1, /* PCI BAR # */
-               pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
+               (unsigned long long)pci_resource_len(pdev, bar),
+               (unsigned long long)pci_resource_start(pdev, bar),
                pci_name(pdev));
        return -EBUSY;
 }
index 29bdeca031a8b49c60c7de124eabc68022c3c3b2..9cc842b666eb1d1d43fc24f9b06b2a3dd3a2f491 100644 (file)
@@ -6,10 +6,10 @@ extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_cleanup_rom(struct pci_dev *dev);
 extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
-                                 unsigned long size, unsigned long align,
-                                 unsigned long min, unsigned int type_mask,
+                                 resource_size_t size, resource_size_t align,
+                                 resource_size_t min, unsigned int type_mask,
                                  void (*alignf)(void *, struct resource *,
-                                                unsigned long, unsigned long),
+                                             resource_size_t, resource_size_t),
                                  void *alignf_data);
 /* Firmware callbacks */
 extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
index 54b2ebc9c91a4b4e18dead4f363b0c9c5150d2a5..99cf33379769310619557605b72c390bc913b39f 100644 (file)
@@ -302,12 +302,6 @@ static struct file_operations proc_bus_pci_operations = {
 #endif /* HAVE_PCI_MMAP */
 };
 
-#if BITS_PER_LONG == 32
-#define LONG_FORMAT "\t%08lx"
-#else
-#define LONG_FORMAT "\t%16lx"
-#endif
-
 /* iterator */
 static void *pci_seq_start(struct seq_file *m, loff_t *pos)
 {
@@ -356,18 +350,18 @@ static int show_device(struct seq_file *m, void *v)
                        dev->irq);
        /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
        for (i=0; i<7; i++) {
-               u64 start, end;
+               resource_size_t start, end;
                pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
-               seq_printf(m, LONG_FORMAT,
-                       ((unsigned long)start) |
-                       (dev->resource[i].flags & PCI_REGION_FLAG_MASK));
+               seq_printf(m, "\t%16llx",
+                       (unsigned long long)(start |
+                       (dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
        }
        for (i=0; i<7; i++) {
-               u64 start, end;
+               resource_size_t start, end;
                pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
-               seq_printf(m, LONG_FORMAT,
+               seq_printf(m, "\t%16llx",
                        dev->resource[i].start < dev->resource[i].end ?
-                       (unsigned long)(end - start) + 1 : 0);
+                       (unsigned long long)(end - start) + 1 : 0);
        }
        seq_putc(m, '\t');
        if (drv)
index 598a115cd00e762abb868b76e16447fa11faa0a3..cbb69cf41311a947f96fd3231f1d00b070d98082 100644 (file)
@@ -80,8 +80,8 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
        } else {
                if (res->flags & IORESOURCE_ROM_COPY) {
                        *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
-                       return (void __iomem *)pci_resource_start(pdev,
-                                                            PCI_ROM_RESOURCE);
+                       return (void __iomem *)(unsigned long)
+                               pci_resource_start(pdev, PCI_ROM_RESOURCE);
                } else {
                        /* assign the ROM an address if it doesn't have one */
                        if (res->parent == NULL &&
@@ -170,11 +170,11 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
                return rom;
 
        res->end = res->start + *size;
-       memcpy_fromio((void*)res->start, rom, *size);
+       memcpy_fromio((void*)(unsigned long)res->start, rom, *size);
        pci_unmap_rom(pdev, rom);
        res->flags |= IORESOURCE_ROM_COPY;
 
-       return (void __iomem *)res->start;
+       return (void __iomem *)(unsigned long)res->start;
 }
 
 /**
@@ -227,7 +227,7 @@ void pci_cleanup_rom(struct pci_dev *pdev)
 {
        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
        if (res->flags & IORESOURCE_ROM_COPY) {
-               kfree((void*)res->start);
+               kfree((void*)(unsigned long)res->start);
                res->flags &= ~IORESOURCE_ROM_COPY;
                res->start = 0;
                res->end = 0;
index 35086e80faa91a9db5ea225b5166d29f1b88e1b4..47c1071ad84ea06b057faac42e6ea60aeb87c5fe 100644 (file)
@@ -357,8 +357,10 @@ pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
                        order = __ffs(align) - 20;
                        if (order > 11) {
                                printk(KERN_WARNING "PCI: region %s/%d "
-                                      "too large: %lx-%lx\n",
-                                      pci_name(dev), i, r->start, r->end);
+                                      "too large: %llx-%llx\n",
+                                       pci_name(dev), i,
+                                       (unsigned long long)r->start,
+                                       (unsigned long long)r->end);
                                r->flags = 0;
                                continue;
                        }
index 577f4b55c46d6e37f52b5f67654ac94ecf73b0ab..ab78e4bbdd83044bc6bb6a3f32e4d7ea3834bf52 100644 (file)
@@ -40,8 +40,9 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
 
        pcibios_resource_to_bus(dev, &region, res);
 
-       pr_debug("  got res [%lx:%lx] bus [%lx:%lx] flags %lx for "
-                "BAR %d of %s\n", res->start, res->end,
+       pr_debug("  got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
+                "BAR %d of %s\n", (unsigned long long)res->start,
+                (unsigned long long)res->end,
                 region.start, region.end, res->flags, resno, pci_name(dev));
 
        new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
@@ -104,10 +105,12 @@ pci_claim_resource(struct pci_dev *dev, int resource)
                err = insert_resource(root, res);
 
        if (err) {
-               printk(KERN_ERR "PCI: %s region %d of %s %s [%lx:%lx]\n",
-                      root ? "Address space collision on" :
-                             "No parent found for",
-                      resource, dtype, pci_name(dev), res->start, res->end);
+               printk(KERN_ERR "PCI: %s region %d of %s %s [%llx:%llx]\n",
+                       root ? "Address space collision on" :
+                               "No parent found for",
+                       resource, dtype, pci_name(dev),
+                       (unsigned long long)res->start,
+                       (unsigned long long)res->end);
        }
 
        return err;
@@ -118,7 +121,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
 {
        struct pci_bus *bus = dev->bus;
        struct resource *res = dev->resource + resno;
-       unsigned long size, min, align;
+       resource_size_t size, min, align;
        int ret;
 
        size = res->end - res->start + 1;
@@ -145,9 +148,11 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
        }
 
        if (ret) {
-               printk(KERN_ERR "PCI: Failed to allocate %s resource #%d:%lx@%lx for %s\n",
-                      res->flags & IORESOURCE_IO ? "I/O" : "mem",
-                      resno, size, res->start, pci_name(dev));
+               printk(KERN_ERR "PCI: Failed to allocate %s resource "
+                       "#%d:%llx@%llx for %s\n",
+                       res->flags & IORESOURCE_IO ? "I/O" : "mem",
+                       resno, (unsigned long long)size,
+                       (unsigned long long)res->start, pci_name(dev));
        } else if (resno < PCI_BRIDGE_RESOURCES) {
                pci_update_resource(dev, res, resno);
        }
@@ -204,7 +209,7 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
                struct resource *r;
                struct resource_list *list, *tmp;
-               unsigned long r_align;
+               resource_size_t r_align;
 
                r = &dev->resource[i];
                r_align = r->end - r->start;
@@ -213,13 +218,14 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
                        continue;
                if (!r_align) {
                        printk(KERN_WARNING "PCI: Ignore bogus resource %d "
-                                           "[%lx:%lx] of %s\n",
-                                           i, r->start, r->end, pci_name(dev));
+                               "[%llx:%llx] of %s\n",
+                               i, (unsigned long long)r->start,
+                               (unsigned long long)r->end, pci_name(dev));
                        continue;
                }
                r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
                for (list = head; ; list = list->next) {
-                       unsigned long align = 0;
+                       resource_size_t align = 0;
                        struct resource_list *ln = list->next;
                        int idx;
 
index b39435bbfaeb2aa3c3f14bbc34499f6a16046313..c662e4f89d46174cf54b2d8af74c8d63b23fcc10 100644 (file)
@@ -244,8 +244,8 @@ static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
 
        hs_mapped_irq[irq].sock = sp;
        /* insert ourselves as the irq controller */
-       hs_mapped_irq[irq].old_handler = irq_desc[irq].handler;
-       irq_desc[irq].handler = &hd64465_ss_irq_type;
+       hs_mapped_irq[irq].old_handler = irq_desc[irq].chip;
+       irq_desc[irq].chip = &hd64465_ss_irq_type;
 }
 
 
@@ -260,7 +260,7 @@ static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq)
            return;
                
        /* restore the original irq controller */
-       irq_desc[irq].handler = hs_mapped_irq[irq].old_handler;
+       irq_desc[irq].chip = hs_mapped_irq[irq].old_handler;
 }
 
 /*============================================================*/
index a2f05f48515654e25d1284a260a6c52a522917f3..ff51a65d9433af984b04ce8cf2fe88812f023796 100644 (file)
@@ -1084,9 +1084,10 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
     u_short base, i;
     u_char map;
     
-    debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#lx-%#lx, "
+    debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
          "%#x)\n", sock, mem->map, mem->flags, mem->speed,
-         mem->res->start, mem->res->end, mem->card_start);
+         (unsigned long long)mem->res->start,
+         (unsigned long long)mem->res->end, mem->card_start);
 
     map = mem->map;
     if ((map > 4) || (mem->card_start > 0x3ffffff) ||
index 0e07d9535116db884fcbe1762d0971ae3192669b..d0f68ab8f04119c12661a27e1785d76b6a372be4 100644 (file)
@@ -157,7 +157,7 @@ MODULE_LICENSE("Dual MPL/GPL");
 
 static int pcmcia_schlvl = PCMCIA_SCHLVL;
 
-static spinlock_t events_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(events_lock);
 
 
 #define PCMCIA_SOCKET_KEY_5V 1
@@ -644,7 +644,7 @@ static struct platform_device m8xx_device = {
 };
 
 static u32 pending_events[PCMCIA_SOCKETS_NO];
-static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pending_event_lock);
 
 static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
index 247ab837f841739f0982c51ecd937692d841f5ef..9ee26c1b863566a0d846e4033a424aa3b8f9f68d 100644 (file)
@@ -642,7 +642,8 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
                goto err_out_free_mem;
 
        printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge "
-               "at 0x%lx on irq %d\n", pci_resource_start(dev, 0), dev->irq);
+               "at 0x%llx on irq %d\n",
+               (unsigned long long)pci_resource_start(dev, 0), dev->irq);
        /*
         * Since we have no memory BARs some firmware may not
         * have had PCI_COMMAND_MEMORY enabled, yet the device needs it.
index 0f8b157c97177d30c3dc2389a70dd85a211c5b75..c3176b16b7bea5223aba2031251196cd88440533 100644 (file)
@@ -72,7 +72,7 @@ static DEFINE_MUTEX(rsrc_mutex);
 ======================================================================*/
 
 static struct resource *
-make_resource(unsigned long b, unsigned long n, int flags, char *name)
+make_resource(resource_size_t b, resource_size_t n, int flags, char *name)
 {
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
@@ -86,8 +86,8 @@ make_resource(unsigned long b, unsigned long n, int flags, char *name)
 }
 
 static struct resource *
-claim_region(struct pcmcia_socket *s, unsigned long base, unsigned long size,
-            int type, char *name)
+claim_region(struct pcmcia_socket *s, resource_size_t base,
+               resource_size_t size, int type, char *name)
 {
        struct resource *res, *parent;
 
@@ -519,10 +519,10 @@ struct pcmcia_align_data {
 
 static void
 pcmcia_common_align(void *align_data, struct resource *res,
-                   unsigned long size, unsigned long align)
+                       resource_size_t size, resource_size_t align)
 {
        struct pcmcia_align_data *data = align_data;
-       unsigned long start;
+       resource_size_t start;
        /*
         * Ensure that we have the correct start address
         */
@@ -533,8 +533,8 @@ pcmcia_common_align(void *align_data, struct resource *res,
 }
 
 static void
-pcmcia_align(void *align_data, struct resource *res,
-            unsigned long size, unsigned long align)
+pcmcia_align(void *align_data, struct resource *res, resource_size_t size,
+               resource_size_t align)
 {
        struct pcmcia_align_data *data = align_data;
        struct resource_map *m;
@@ -808,8 +808,10 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
                if (res->flags & IORESOURCE_IO) {
                        if (res == &ioport_resource)
                                continue;
-                       printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n",
-                              res->start, res->end);
+                       printk(KERN_INFO "pcmcia: parent PCI bridge I/O "
+                               "window: 0x%llx - 0x%llx\n",
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                        if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
                                done |= IORESOURCE_IO;
 
@@ -818,8 +820,10 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
                if (res->flags & IORESOURCE_MEM) {
                        if (res == &iomem_resource)
                                continue;
-                       printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n",
-                              res->start, res->end);
+                       printk(KERN_INFO "pcmcia: parent PCI bridge Memory "
+                               "window: 0x%llx - 0x%llx\n",
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                        if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
                                done |= IORESOURCE_MEM;
                }
index 73bad1d5cb23d8660b803f9933a026dd36ad530a..65a60671659f1e1c77861a2235e5d31bbcc1035b 100644 (file)
@@ -756,8 +756,9 @@ static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
     u_long base, len, mmap;
 
     debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, "
-         "%#lx-%#lx, %#x)\n", psock, mem->map, mem->flags,
-         mem->speed, mem->res->start, mem->res->end, mem->card_start);
+         "%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags,
+         mem->speed, (unsigned long long)mem->res->start,
+         (unsigned long long)mem->res->end, mem->card_start);
     if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
        (mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) ||
        (mem->res->start > mem->res->end) || (mem->speed > 1000))
index a2d8ce7fef9c97bb0149b4e6166e044820119ea2..3163e3d73da13c1d6f58beecd6271a36f1bcb2e1 100644 (file)
@@ -264,7 +264,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
                        if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
                                pnp_printf(buffer," disabled\n");
                        else
-                               pnp_printf(buffer," 0x%lx-0x%lx\n",
+                               pnp_printf(buffer," 0x%llx-0x%llx\n",
                                                pnp_port_start(dev, i),
                                                pnp_port_end(dev, i));
                }
@@ -275,7 +275,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
                        if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
                                pnp_printf(buffer," disabled\n");
                        else
-                               pnp_printf(buffer," 0x%lx-0x%lx\n",
+                               pnp_printf(buffer," 0x%llx-0x%llx\n",
                                                pnp_mem_start(dev, i),
                                                pnp_mem_end(dev, i));
                }
@@ -286,7 +286,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
                        if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
                                pnp_printf(buffer," disabled\n");
                        else
-                               pnp_printf(buffer," %ld\n",
+                               pnp_printf(buffer," %lld\n",
                                                pnp_irq(dev, i));
                }
        }
@@ -296,7 +296,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
                        if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
                                pnp_printf(buffer," disabled\n");
                        else
-                               pnp_printf(buffer," %ld\n",
+                               pnp_printf(buffer," %lld\n",
                                                pnp_dma(dev, i));
                }
        }
index 6fff109bdab606e98eb188f70a4b4a1dcafe6415..1d7a5b87f4cbc3157e7abbf86d11da638f748eeb 100644 (file)
@@ -20,7 +20,8 @@ DECLARE_MUTEX(pnp_res_mutex);
 
 static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 {
-       unsigned long *start, *end, *flags;
+       resource_size_t *start, *end;
+       unsigned long *flags;
 
        if (!dev || !rule)
                return -EINVAL;
@@ -63,7 +64,8 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 
 static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
 {
-       unsigned long *start, *end, *flags;
+       resource_size_t *start, *end;
+       unsigned long *flags;
 
        if (!dev || !rule)
                return -EINVAL;
@@ -116,7 +118,8 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
 
 static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
 {
-       unsigned long *start, *end, *flags;
+       resource_size_t *start, *end;
+       unsigned long *flags;
        int i;
 
        /* IRQ priority: this table is good for i386 */
@@ -168,7 +171,8 @@ static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
 
 static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
 {
-       unsigned long *start, *end, *flags;
+       resource_size_t *start, *end;
+       unsigned long *flags;
        int i;
 
        /* DMA priority: this table is good for i386 */
@@ -582,7 +586,8 @@ int pnp_disable_dev(struct pnp_dev *dev)
  * @size: size of region
  *
  */
-void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)
+void pnp_resource_change(struct resource *resource, resource_size_t start,
+                               resource_size_t size)
 {
        if (resource == NULL)
                return;
index 6ded527169f4b805b43a77dba11a5c0b23d42af8..7bb892f58cc09815da0ee5963417cbc312bf0f9b 100644 (file)
@@ -241,7 +241,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
 {
        int tmp;
        struct pnp_dev *tdev;
-       unsigned long *port, *end, *tport, *tend;
+       resource_size_t *port, *end, *tport, *tend;
        port = &dev->res.port_resource[idx].start;
        end = &dev->res.port_resource[idx].end;
 
@@ -297,7 +297,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
 {
        int tmp;
        struct pnp_dev *tdev;
-       unsigned long *addr, *end, *taddr, *tend;
+       resource_size_t *addr, *end, *taddr, *tend;
        addr = &dev->res.mem_resource[idx].start;
        end = &dev->res.mem_resource[idx].end;
 
@@ -358,7 +358,7 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
 {
        int tmp;
        struct pnp_dev *tdev;
-       unsigned long * irq = &dev->res.irq_resource[idx].start;
+       resource_size_t * irq = &dev->res.irq_resource[idx].start;
 
        /* if the resource doesn't exist, don't complain about it */
        if (cannot_compare(dev->res.irq_resource[idx].flags))
@@ -423,7 +423,7 @@ int pnp_check_dma(struct pnp_dev * dev, int idx)
 #ifndef CONFIG_IA64
        int tmp;
        struct pnp_dev *tdev;
-       unsigned long * dma = &dev->res.dma_resource[idx].start;
+       resource_size_t * dma = &dev->res.dma_resource[idx].start;
 
        /* if the resource doesn't exist, don't complain about it */
        if (cannot_compare(dev->res.dma_resource[idx].flags))
index b9fab2ae3a36108ed2bbc48499682382c8e3b88f..8b56bbdd011ec0d5bf9870ca36abeda25caff49e 100644 (file)
@@ -17,8 +17,8 @@
  * These interrupt-safe spinlocks protect all accesses to RIO
  * configuration space and doorbell access.
  */
-static spinlock_t rio_config_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t rio_doorbell_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(rio_config_lock);
+static DEFINE_SPINLOCK(rio_doorbell_lock);
 
 /*
  *  Wrappers for all RIO configuration access functions.  They just check
index bccff400b198d6e0da250fd483a551ad60d992bd..f2fc81a9074d8af26c79940f87ddaa8c98712999 100644 (file)
@@ -162,6 +162,16 @@ config RTC_DRV_PCF8583
          This driver can also be built as a module. If so, the module
          will be called rtc-pcf8583.
 
+config RTC_DRV_RS5C348
+       tristate "Ricoh RS5C348A/B"
+       depends on RTC_CLASS && SPI
+       help
+         If you say yes here you get support for the
+         Ricoh RS5C348A and RS5C348B RTC chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-rs5c348.
+
 config RTC_DRV_RS5C372
        tristate "Ricoh RS5C372A/B"
        depends on RTC_CLASS && I2C
index 900d210dd1a24e017b46801251b5bdcea46e4407..da5e38774e130f444f1eb43f31740f5bae404abe 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_RTC_DRV_DS1742)  += rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_PCF8563)  += rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)  += rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_M48T86)   += rtc-m48t86.o
 obj-$(CONFIG_RTC_DRV_DS1553)   += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
index 5396beec30d0ca62b3d97a0c73c0ac66cb8ceccc..1cb61a761cb284cc6dd590e6ebd8062f6271d246 100644 (file)
@@ -94,7 +94,9 @@ exit_kfree:
        kfree(rtc);
 
 exit_idr:
+       mutex_lock(&idr_lock);
        idr_remove(&rtc_idr, id);
+       mutex_unlock(&idr_lock);
 
 exit:
        dev_err(dev, "rtc core: unable to register %s, err = %d\n",
index ecafbad41a242ce894d9247c88c6e1a5d0e67734..762521a1419cf296f080e7e4672e430f3029decc 100644 (file)
@@ -226,7 +226,7 @@ static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
        if (pdata->irq < 0)
-               return -ENOIOCTLCMD;
+               return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
        switch (cmd) {
        case RTC_AIE_OFF:
                pdata->irqen &= ~RTC_AF;
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
new file mode 100644 (file)
index 0000000..0964d1d
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * A SPI driver for the Ricoh RS5C348 RTC
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The board specific init code should provide characteristics of this
+ * device:
+ *     Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS
+ */
+
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+
+#define DRV_VERSION "0.1"
+
+#define RS5C348_REG_SECS       0
+#define RS5C348_REG_MINS       1
+#define RS5C348_REG_HOURS      2
+#define RS5C348_REG_WDAY       3
+#define RS5C348_REG_DAY        4
+#define RS5C348_REG_MONTH      5
+#define RS5C348_REG_YEAR       6
+#define RS5C348_REG_CTL1       14
+#define RS5C348_REG_CTL2       15
+
+#define RS5C348_SECS_MASK      0x7f
+#define RS5C348_MINS_MASK      0x7f
+#define RS5C348_HOURS_MASK     0x3f
+#define RS5C348_WDAY_MASK      0x03
+#define RS5C348_DAY_MASK       0x3f
+#define RS5C348_MONTH_MASK     0x1f
+
+#define RS5C348_BIT_PM 0x20    /* REG_HOURS */
+#define RS5C348_BIT_Y2K        0x80    /* REG_MONTH */
+#define RS5C348_BIT_24H        0x20    /* REG_CTL1 */
+#define RS5C348_BIT_XSTP       0x10    /* REG_CTL2 */
+#define RS5C348_BIT_VDET       0x40    /* REG_CTL2 */
+
+#define RS5C348_CMD_W(addr)    (((addr) << 4) | 0x08)  /* single write */
+#define RS5C348_CMD_R(addr)    (((addr) << 4) | 0x0c)  /* single read */
+#define RS5C348_CMD_MW(addr)   (((addr) << 4) | 0x00)  /* burst write */
+#define RS5C348_CMD_MR(addr)   (((addr) << 4) | 0x04)  /* burst read */
+
+struct rs5c348_plat_data {
+       struct rtc_device *rtc;
+       int rtc_24h;
+};
+
+static int
+rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+       u8 txbuf[5+7], *txp;
+       int ret;
+
+       /* Transfer 5 bytes before writing SEC.  This gives 31us for carry. */
+       txp = txbuf;
+       txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+       txbuf[1] = 0;   /* dummy */
+       txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+       txbuf[3] = 0;   /* dummy */
+       txbuf[4] = RS5C348_CMD_MW(RS5C348_REG_SECS); /* cmd, sec, ... */
+       txp = &txbuf[5];
+       txp[RS5C348_REG_SECS] = BIN2BCD(tm->tm_sec);
+       txp[RS5C348_REG_MINS] = BIN2BCD(tm->tm_min);
+       if (pdata->rtc_24h) {
+               txp[RS5C348_REG_HOURS] = BIN2BCD(tm->tm_hour);
+       } else {
+               /* hour 0 is AM12, noon is PM12 */
+               txp[RS5C348_REG_HOURS] = BIN2BCD((tm->tm_hour + 11) % 12 + 1) |
+                       (tm->tm_hour >= 12 ? RS5C348_BIT_PM : 0);
+       }
+       txp[RS5C348_REG_WDAY] = BIN2BCD(tm->tm_wday);
+       txp[RS5C348_REG_DAY] = BIN2BCD(tm->tm_mday);
+       txp[RS5C348_REG_MONTH] = BIN2BCD(tm->tm_mon + 1) |
+               (tm->tm_year >= 100 ? RS5C348_BIT_Y2K : 0);
+       txp[RS5C348_REG_YEAR] = BIN2BCD(tm->tm_year % 100);
+       /* write in one transfer to avoid data inconsistency */
+       ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), NULL, 0);
+       udelay(62);     /* Tcsr 62us */
+       return ret;
+}
+
+static int
+rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+       u8 txbuf[5], rxbuf[7];
+       int ret;
+
+       /* Transfer 5 byte befores reading SEC.  This gives 31us for carry. */
+       txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+       txbuf[1] = 0;   /* dummy */
+       txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+       txbuf[3] = 0;   /* dummy */
+       txbuf[4] = RS5C348_CMD_MR(RS5C348_REG_SECS); /* cmd, sec, ... */
+
+       /* read in one transfer to avoid data inconsistency */
+       ret = spi_write_then_read(spi, txbuf, sizeof(txbuf),
+                                 rxbuf, sizeof(rxbuf));
+       udelay(62);     /* Tcsr 62us */
+       if (ret < 0)
+               return ret;
+
+       tm->tm_sec = BCD2BIN(rxbuf[RS5C348_REG_SECS] & RS5C348_SECS_MASK);
+       tm->tm_min = BCD2BIN(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK);
+       tm->tm_hour = BCD2BIN(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK);
+       if (!pdata->rtc_24h) {
+               tm->tm_hour %= 12;
+               if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM)
+                       tm->tm_hour += 12;
+       }
+       tm->tm_wday = BCD2BIN(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK);
+       tm->tm_mday = BCD2BIN(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK);
+       tm->tm_mon =
+               BCD2BIN(rxbuf[RS5C348_REG_MONTH] & RS5C348_MONTH_MASK) - 1;
+       /* year is 1900 + tm->tm_year */
+       tm->tm_year = BCD2BIN(rxbuf[RS5C348_REG_YEAR]) +
+               ((rxbuf[RS5C348_REG_MONTH] & RS5C348_BIT_Y2K) ? 100 : 0);
+
+       if (rtc_valid_tm(tm) < 0) {
+               dev_err(&spi->dev, "retrieved date/time is not valid.\n");
+               rtc_time_to_tm(0, tm);
+       }
+
+       return 0;
+}
+
+static struct rtc_class_ops rs5c348_rtc_ops = {
+       .read_time      = rs5c348_rtc_read_time,
+       .set_time       = rs5c348_rtc_set_time,
+};
+
+static struct spi_driver rs5c348_driver;
+
+static int __devinit rs5c348_probe(struct spi_device *spi)
+{
+       int ret;
+       struct rtc_device *rtc;
+       struct rs5c348_plat_data *pdata;
+
+       pdata = kzalloc(sizeof(struct rs5c348_plat_data), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+       spi->dev.platform_data = pdata;
+
+       /* Check D7 of SECOND register */
+       ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_SECS));
+       if (ret < 0 || (ret & 0x80)) {
+               dev_err(&spi->dev, "not found.\n");
+               goto kfree_exit;
+       }
+
+       dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n");
+       dev_info(&spi->dev, "spiclk %u KHz.\n",
+                (spi->max_speed_hz + 500) / 1000);
+
+       /* turn RTC on if it was not on */
+       ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
+       if (ret < 0)
+               goto kfree_exit;
+       if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
+               u8 buf[2];
+               if (ret & RS5C348_BIT_VDET)
+                       dev_warn(&spi->dev, "voltage-low detected.\n");
+               buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
+               buf[1] = 0;
+               ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
+               if (ret < 0)
+                       goto kfree_exit;
+       }
+
+       ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1));
+       if (ret < 0)
+               goto kfree_exit;
+       if (ret & RS5C348_BIT_24H)
+               pdata->rtc_24h = 1;
+
+       rtc = rtc_device_register(rs5c348_driver.driver.name, &spi->dev,
+                                 &rs5c348_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto kfree_exit;
+       }
+
+       pdata->rtc = rtc;
+
+       return 0;
+ kfree_exit:
+       kfree(pdata);
+       return ret;
+}
+
+static int __devexit rs5c348_remove(struct spi_device *spi)
+{
+       struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+       struct rtc_device *rtc = pdata->rtc;
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+       kfree(pdata);
+       return 0;
+}
+
+static struct spi_driver rs5c348_driver = {
+       .driver = {
+               .name   = "rs5c348",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = rs5c348_probe,
+       .remove = __devexit_p(rs5c348_remove),
+};
+
+static __init int rs5c348_init(void)
+{
+       return spi_register_driver(&rs5c348_driver);
+}
+
+static __exit void rs5c348_exit(void)
+{
+       spi_unregister_driver(&rs5c348_driver);
+}
+
+module_init(rs5c348_init);
+module_exit(rs5c348_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index ab486fbc828dab567357ab1d1ca04e2c5fc7d625..9cd1cb304bb2a7b66a4a5aab5442e472419961df 100644 (file)
@@ -45,7 +45,7 @@
 
 static unsigned long rtc_freq = 1024;
 static struct rtc_time rtc_alarm;
-static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(sa1100_rtc_lock);
 
 static int rtc_update_alarm(struct rtc_time *alrm)
 {
index 33e029207e261cd2ce20f0bcb75375fa8380a768..4b9291dd444354ab1f2f374c26d2d0069266b800 100644 (file)
@@ -93,7 +93,7 @@ static void __iomem *rtc2_base;
 
 static unsigned long epoch = 1970;     /* Jan 1 1970 00:00:00 */
 
-static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(rtc_lock);
 static char rtc_name[] = "RTC";
 static unsigned long periodic_frequency;
 static unsigned long periodic_count;
index cfb1fff3787caafd63fe05a2c36587bfdb8f19a5..bafcd2f20ae241071e5fad970684bd4f088df9fa 100644 (file)
@@ -95,7 +95,7 @@ dasd_alloc_device(void)
        spin_lock_init(&device->mem_lock);
        spin_lock_init(&device->request_queue_lock);
        atomic_set (&device->tasklet_scheduled, 0);
-       tasklet_init(&device->tasklet, 
+       tasklet_init(&device->tasklet,
                     (void (*)(unsigned long)) dasd_tasklet,
                     (unsigned long) device);
        INIT_LIST_HEAD(&device->ccw_queue);
@@ -128,7 +128,7 @@ dasd_state_new_to_known(struct dasd_device *device)
        int rc;
 
        /*
-        * As long as the device is not in state DASD_STATE_NEW we want to 
+        * As long as the device is not in state DASD_STATE_NEW we want to
         * keep the reference count > 0.
         */
        dasd_get_device(device);
@@ -336,7 +336,7 @@ dasd_decrease_state(struct dasd_device *device)
        if (device->state == DASD_STATE_ONLINE &&
            device->target <= DASD_STATE_READY)
                dasd_state_online_to_ready(device);
-       
+
        if (device->state == DASD_STATE_READY &&
            device->target <= DASD_STATE_BASIC)
                dasd_state_ready_to_basic(device);
@@ -348,7 +348,7 @@ dasd_decrease_state(struct dasd_device *device)
        if (device->state == DASD_STATE_BASIC &&
            device->target <= DASD_STATE_KNOWN)
                dasd_state_basic_to_known(device);
-       
+
        if (device->state == DASD_STATE_KNOWN &&
            device->target <= DASD_STATE_NEW)
                dasd_state_known_to_new(device);
@@ -994,7 +994,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                      ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
 
        /* Find out the appropriate era_action. */
-       if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) 
+       if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
                era = dasd_era_fatal;
        else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
                 irb->scsw.cstat == 0 &&
@@ -1004,7 +1004,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                era = dasd_era_fatal; /* don't recover this request */
        else if (irb->esw.esw0.erw.cons)
                era = device->discipline->examine_error(cqr, irb);
-       else 
+       else
                era = dasd_era_recover;
 
        DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
@@ -1287,7 +1287,7 @@ __dasd_start_head(struct dasd_device * device)
 }
 
 /*
- * Remove requests from the ccw queue. 
+ * Remove requests from the ccw queue.
  */
 static void
 dasd_flush_ccw_queue(struct dasd_device * device, int all)
@@ -1450,23 +1450,23 @@ dasd_sleep_on(struct dasd_ccw_req * cqr)
        wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
-       
+
        device = cqr->device;
        spin_lock_irq(get_ccwdev_lock(device->cdev));
-       
+
        init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
        cqr->status = DASD_CQR_QUEUED;
        list_add_tail(&cqr->list, &device->ccw_queue);
-       
+
        /* let the bh start the request to keep them in order */
        dasd_schedule_bh(device);
-       
+
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
        wait_event(wait_q, _wait_for_wakeup(cqr));
-       
+
        /* Request status is either done or failed. */
        rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
        return rc;
@@ -1568,7 +1568,7 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
        wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
-       
+
        device = cqr->device;
        spin_lock_irq(get_ccwdev_lock(device->cdev));
        rc = _dasd_term_running_cqr(device);
@@ -1576,20 +1576,20 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
                spin_unlock_irq(get_ccwdev_lock(device->cdev));
                return rc;
        }
-       
+
        init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
        cqr->status = DASD_CQR_QUEUED;
        list_add(&cqr->list, &device->ccw_queue);
-       
+
        /* let the bh start the request to keep them in order */
        dasd_schedule_bh(device);
-       
+
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
        wait_event(wait_q, _wait_for_wakeup(cqr));
-       
+
        /* Request status is either done or failed. */
        rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
        return rc;
@@ -1725,7 +1725,7 @@ dasd_flush_request_queue(struct dasd_device * device)
 
        if (!device->request_queue)
                return;
-       
+
        spin_lock_irq(&device->request_queue_lock);
        while (!list_empty(&device->request_queue->queue_head)) {
                req = elv_next_request(device->request_queue);
@@ -1855,15 +1855,34 @@ dasd_generic_probe (struct ccw_device *cdev,
 {
        int ret;
 
+       ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
+       if (ret) {
+               printk(KERN_WARNING
+                      "dasd_generic_probe: could not set ccw-device options "
+                      "for %s\n", cdev->dev.bus_id);
+               return ret;
+       }
        ret = dasd_add_sysfs_files(cdev);
        if (ret) {
                printk(KERN_WARNING
                       "dasd_generic_probe: could not add sysfs entries "
                       "for %s\n", cdev->dev.bus_id);
-       } else {
-               cdev->handler = &dasd_int_handler;
+               return ret;
        }
+       cdev->handler = &dasd_int_handler;
 
+       /*
+        * Automatically online either all dasd devices (dasd_autodetect)
+        * or all devices specified with dasd= parameters during
+        * initial probe.
+        */
+       if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) ||
+           (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0))
+               ret = ccw_device_set_online(cdev);
+       if (ret)
+               printk(KERN_WARNING
+                      "dasd_generic_probe: could not initially online "
+                      "ccw-device %s\n", cdev->dev.bus_id);
        return ret;
 }
 
@@ -1911,6 +1930,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
        struct dasd_device *device;
        int rc;
 
+       /* first online clears initial online feature flag */
+       dasd_set_feature(cdev, DASD_FEATURE_INITIAL_ONLINE, 0);
        device = dasd_create_device(cdev);
        if (IS_ERR(device))
                return PTR_ERR(device);
@@ -2065,31 +2086,6 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
        return ret;
 }
 
-/*
- * Automatically online either all dasd devices (dasd_autodetect) or
- * all devices specified with dasd= parameters.
- */
-static int
-__dasd_auto_online(struct device *dev, void *data)
-{
-       struct ccw_device *cdev;
-
-       cdev = to_ccwdev(dev);
-       if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
-               ccw_device_set_online(cdev);
-       return 0;
-}
-
-void
-dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
-{
-       struct device_driver *drv;
-
-       drv = get_driver(&dasd_discipline_driver->driver);
-       driver_for_each_device(drv, NULL, NULL, __dasd_auto_online);
-       put_driver(drv);
-}
-
 
 static int __init
 dasd_init(void)
@@ -2170,23 +2166,4 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);
 EXPORT_SYMBOL_GPL(dasd_generic_notify);
 EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
-EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
 
-/*
- * 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-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index 1d11c2a9525d3d1ab7f158efd6f96df53e541949..1ddab8991d92fe1020c1c8309180d175700f954b 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_3370_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
 
 
 /*
- * DASD_3370_ERP_EXAMINE 
+ * DASD_3370_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -23,7 +23,7 @@
  *   'Chapter 7. 3370 Sense Data'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -82,22 +82,3 @@ dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
        return dasd_era_recover;
 
 }                              /* END dasd_3370_erp_examine */
-
-/*
- * 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-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index 2ed51562319eae9541b6f2dda331bb3818aac75b..669805d4402dcdf628424cb0ff49900db9ba50ad 100644 (file)
@@ -1,6 +1,6 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_3990_erp.c
- * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com> 
+ * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com>
  *                 Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
@@ -25,23 +25,23 @@ struct DCTL_data {
 } __attribute__ ((packed));
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * SECTION ERP EXAMINATION
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_EXAMINE_24 
+ * DASD_3990_ERP_EXAMINE_24
  *
  * DESCRIPTION
- *   Checks only for fatal (unrecoverable) error. 
+ *   Checks only for fatal (unrecoverable) error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
  *   Each bit configuration leading to an action code 2 (Exit with
  *   programming error or unusual condition indication)
  *   are handled as fatal error´s.
- * 
+ *
  *   All other configurations are handled as recoverable errors.
  *
  * RETURN VALUES
@@ -93,15 +93,15 @@ dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
 }                              /* END dasd_3990_erp_examine_24 */
 
 /*
- * DASD_3990_ERP_EXAMINE_32 
+ * DASD_3990_ERP_EXAMINE_32
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recoverable error. 
+ *   Checks only for fatal/no/recoverable error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for recoverable others.
  */
@@ -128,10 +128,10 @@ dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
 }                              /* end dasd_3990_erp_examine_32 */
 
 /*
- * DASD_3990_ERP_EXAMINE 
+ * DASD_3990_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -139,7 +139,7 @@ dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
  *   'Chapter 7. Error Recovery Procedures'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -178,18 +178,18 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
 }                              /* END dasd_3990_erp_examine */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * SECTION ERP HANDLING
- ***************************************************************************** 
+ *****************************************************************************
  */
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 24 and 32 byte sense ERP functions
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_CLEANUP 
+ * DASD_3990_ERP_CLEANUP
  *
  * DESCRIPTION
  *   Removes the already build but not necessary ERP request and sets
@@ -197,10 +197,10 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
  *
  *  PARAMETER
  *   erp               request to be blocked
- *   final_status      either DASD_CQR_DONE or DASD_CQR_FAILED 
+ *   final_status      either DASD_CQR_DONE or DASD_CQR_FAILED
  *
  * RETURN VALUES
- *   cqr               original cqr               
+ *   cqr               original cqr
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
@@ -214,7 +214,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
 }                              /* end dasd_3990_erp_cleanup */
 
 /*
- * DASD_3990_ERP_BLOCK_QUEUE 
+ * DASD_3990_ERP_BLOCK_QUEUE
  *
  * DESCRIPTION
  *   Block the given device request queue to prevent from further
@@ -237,7 +237,7 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
 }
 
 /*
- * DASD_3990_ERP_INT_REQ 
+ * DASD_3990_ERP_INT_REQ
  *
  * DESCRIPTION
  *   Handles 'Intervention Required' error.
@@ -277,7 +277,7 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_int_req */
 
 /*
- * DASD_3990_ERP_ALTERNATE_PATH 
+ * DASD_3990_ERP_ALTERNATE_PATH
  *
  * DESCRIPTION
  *   Repeat the operation on a different channel path.
@@ -330,15 +330,15 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
  * DASD_3990_ERP_DCTL
  *
  * DESCRIPTION
- *   Setup cqr to do the Diagnostic Control (DCTL) command with an 
+ *   Setup cqr to do the Diagnostic Control (DCTL) command with an
  *   Inhibit Write subcommand (0x20) and the given modifier.
  *
  *  PARAMETER
  *   erp               pointer to the current (failed) ERP
  *   modifier          subcommand modifier
- *   
+ *
  * RETURN VALUES
- *   dctl_cqr          pointer to NEW dctl_cqr 
+ *   dctl_cqr          pointer to NEW dctl_cqr
  *
  */
 static struct dasd_ccw_req *
@@ -386,7 +386,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
 }                              /* end dasd_3990_erp_DCTL */
 
 /*
- * DASD_3990_ERP_ACTION_1 
+ * DASD_3990_ERP_ACTION_1
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 1 (see Reference manual).
@@ -415,7 +415,7 @@ dasd_3990_erp_action_1(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_action_1 */
 
 /*
- * DASD_3990_ERP_ACTION_4 
+ * DASD_3990_ERP_ACTION_4
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 4 (see Reference manual).
@@ -453,11 +453,11 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 
                if (sense[25] == 0x1D) {        /* state change pending */
 
-                       DEV_MESSAGE(KERN_INFO, device, 
+                       DEV_MESSAGE(KERN_INFO, device,
                                    "waiting for state change pending "
                                    "interrupt, %d retries left",
                                    erp->retries);
-                       
+
                        dasd_3990_erp_block_queue(erp, 30*HZ);
 
                 } else if (sense[25] == 0x1E) {        /* busy */
@@ -469,9 +469,9 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
                } else {
 
                        /* no state change pending - retry */
-                       DEV_MESSAGE (KERN_INFO, device, 
+                       DEV_MESSAGE (KERN_INFO, device,
                                     "redriving request immediately, "
-                                    "%d retries left", 
+                                    "%d retries left",
                                     erp->retries);
                        erp->status = DASD_CQR_QUEUED;
                }
@@ -482,13 +482,13 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_action_4 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 24 byte sense ERP functions (only)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_ACTION_5 
+ * DASD_3990_ERP_ACTION_5
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 5 (see Reference manual).
@@ -523,7 +523,7 @@ dasd_3990_erp_action_5(struct dasd_ccw_req * erp)
  *
  * PARAMETER
  *   sense             current sense data
- *   
+ *
  * RETURN VALUES
  *   void
  */
@@ -1150,9 +1150,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
  * PARAMETER
  *   erp               current erp_head
  *   sense             current sense data
- * 
+ *
  * RETURN VALUES
- *   erp               'new' erp_head - pointer to new ERP 
+ *   erp               'new' erp_head - pointer to new ERP
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
@@ -1185,7 +1185,7 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_com_rej */
 
 /*
- * DASD_3990_ERP_BUS_OUT 
+ * DASD_3990_ERP_BUS_OUT
  *
  * DESCRIPTION
  *   Handles 24 byte 'Bus Out Parity Check' error.
@@ -1483,7 +1483,7 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
  *
  * PARAMETER
  *   erp               already added default ERP
- *             
+ *
  * RETURN VALUES
  *   erp               new erp_head - pointer to new ERP
  */
@@ -1527,11 +1527,11 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_file_prot */
 
 /*
- * DASD_3990_ERP_INSPECT_24 
+ * DASD_3990_ERP_INSPECT_24
  *
  * DESCRIPTION
  *   Does a detailed inspection of the 24 byte sense data
- *   and sets up a related error recovery action.  
+ *   and sets up a related error recovery action.
  *
  * PARAMETER
  *   sense             sense data of the actual error
@@ -1602,13 +1602,13 @@ dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
 }                              /* END dasd_3990_erp_inspect_24 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 32 byte sense ERP functions (only)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERPACTION_10_32 
+ * DASD_3990_ERPACTION_10_32
  *
  * DESCRIPTION
  *   Handles 32 byte 'Action 10' of Single Program Action Codes.
@@ -1616,7 +1616,7 @@ dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
  *
  * PARAMETER
  *   erp               current erp_head
- *   sense             current sense data 
+ *   sense             current sense data
  * RETURN VALUES
  *   erp               modified erp_head
  */
@@ -1640,18 +1640,18 @@ dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
  *
  * DESCRIPTION
  *   Handles 32 byte 'Action 1B' of Single Program Action Codes.
- *   A write operation could not be finished because of an unexpected 
+ *   A write operation could not be finished because of an unexpected
  *   condition.
- *   The already created 'default erp' is used to get the link to 
- *   the erp chain, but it can not be used for this recovery 
+ *   The already created 'default erp' is used to get the link to
+ *   the erp chain, but it can not be used for this recovery
  *   action because it contains no DE/LO data space.
  *
  * PARAMETER
  *   default_erp       already added default erp.
- *   sense             current sense data 
+ *   sense             current sense data
  *
  * RETURN VALUES
- *   erp               new erp or 
+ *   erp               new erp or
  *                     default_erp in case of imprecise ending or error
  */
 static struct dasd_ccw_req *
@@ -1789,16 +1789,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
  * DASD_3990_UPDATE_1B
  *
  * DESCRIPTION
- *   Handles the update to the 32 byte 'Action 1B' of Single Program 
+ *   Handles the update to the 32 byte 'Action 1B' of Single Program
  *   Action Codes in case the first action was not successful.
  *   The already created 'previous_erp' is the currently not successful
- *   ERP. 
+ *   ERP.
  *
  * PARAMETER
  *   previous_erp      already created previous erp.
- *   sense             current sense data 
+ *   sense             current sense data
  * RETURN VALUES
- *   erp               modified erp 
+ *   erp               modified erp
  */
 static struct dasd_ccw_req *
 dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
@@ -1897,7 +1897,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 }                              /* end dasd_3990_update_1B */
 
 /*
- * DASD_3990_ERP_COMPOUND_RETRY 
+ * DASD_3990_ERP_COMPOUND_RETRY
  *
  * DESCRIPTION
  *   Handles the compound ERP action retry code.
@@ -1943,7 +1943,7 @@ dasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_retry */
 
 /*
- * DASD_3990_ERP_COMPOUND_PATH 
+ * DASD_3990_ERP_COMPOUND_PATH
  *
  * DESCRIPTION
  *   Handles the compound ERP action for retry on alternate
@@ -1965,7 +1965,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
                dasd_3990_erp_alternate_path(erp);
 
                if (erp->status == DASD_CQR_FAILED) {
-                       /* reset the lpm and the status to be able to 
+                       /* reset the lpm and the status to be able to
                         * try further actions. */
 
                        erp->lpm = 0;
@@ -1980,7 +1980,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_path */
 
 /*
- * DASD_3990_ERP_COMPOUND_CODE 
+ * DASD_3990_ERP_COMPOUND_CODE
  *
  * DESCRIPTION
  *   Handles the compound ERP action for retry code.
@@ -2001,18 +2001,18 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
 
                switch (sense[28]) {
                case 0x17:
-                       /* issue a Diagnostic Control command with an 
+                       /* issue a Diagnostic Control command with an
                         * Inhibit Write subcommand and controler modifier */
                        erp = dasd_3990_erp_DCTL(erp, 0x20);
                        break;
-                       
+
                case 0x25:
                        /* wait for 5 seconds and retry again */
                        erp->retries = 1;
-                       
+
                        dasd_3990_erp_block_queue (erp, 5*HZ);
                        break;
-                       
+
                default:
                        /* should not happen - continue */
                        break;
@@ -2026,7 +2026,7 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_code */
 
 /*
- * DASD_3990_ERP_COMPOUND_CONFIG 
+ * DASD_3990_ERP_COMPOUND_CONFIG
  *
  * DESCRIPTION
  *   Handles the compound ERP action for configruation
@@ -2063,10 +2063,10 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_config */
 
 /*
- * DASD_3990_ERP_COMPOUND 
+ * DASD_3990_ERP_COMPOUND
  *
  * DESCRIPTION
- *   Does the further compound program action if 
+ *   Does the further compound program action if
  *   compound retry was not successful.
  *
  * PARAMETER
@@ -2110,11 +2110,11 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound */
 
 /*
- * DASD_3990_ERP_INSPECT_32 
+ * DASD_3990_ERP_INSPECT_32
  *
  * DESCRIPTION
  *   Does a detailed inspection of the 32 byte sense data
- *   and sets up a related error recovery action.  
+ *   and sets up a related error recovery action.
  *
  * PARAMETER
  *   sense             sense data of the actual error
@@ -2228,9 +2228,9 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_inspect_32 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * main ERP control fuctions (24 and 32 byte sense)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
@@ -2243,7 +2243,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
  * PARAMETER
  *   erp               pointer to the currently created default ERP
  * RETURN VALUES
- *   erp_new           contens was possibly modified 
+ *   erp_new           contens was possibly modified
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
@@ -2272,14 +2272,14 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
 
 /*
  * DASD_3990_ERP_ADD_ERP
- * 
+ *
  * DESCRIPTION
  *   This funtion adds an additional request block (ERP) to the head of
  *   the given cqr (or erp).
  *   This erp is initialized as an default erp (retry TIC)
  *
  * PARAMETER
- *   cqr               head of the current ERP-chain (or single cqr if 
+ *   cqr               head of the current ERP-chain (or single cqr if
  *                     first error)
  * RETURN VALUES
  *   erp               pointer to new ERP-chain head
@@ -2332,15 +2332,15 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
 }
 
 /*
- * DASD_3990_ERP_ADDITIONAL_ERP 
- * 
+ * DASD_3990_ERP_ADDITIONAL_ERP
+ *
  * DESCRIPTION
  *   An additional ERP is needed to handle the current error.
  *   Add ERP to the head of the ERP-chain containing the ERP processing
  *   determined based on the sense data.
  *
  * PARAMETER
- *   cqr               head of the current ERP-chain (or single cqr if 
+ *   cqr               head of the current ERP-chain (or single cqr if
  *                     first error)
  *
  * RETURN VALUES
@@ -2376,7 +2376,7 @@ dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr)
  *   24 byte sense byte 25 and 27 is set as well.
  *
  * PARAMETER
- *   cqr1              first cqr, which will be compared with the 
+ *   cqr1              first cqr, which will be compared with the
  *   cqr2              second cqr.
  *
  * RETURN VALUES
@@ -2415,7 +2415,7 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2)
  *   cqr               failed cqr (either original cqr or already an erp)
  *
  * RETURN VALUES
- *   erp               erp-pointer to the already defined error 
+ *   erp               erp-pointer to the already defined error
  *                     recovery procedure OR
  *                     NULL if a 'new' error occurred.
  */
@@ -2451,10 +2451,10 @@ dasd_3990_erp_in_erp(struct dasd_ccw_req *cqr)
  * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense)
  *
  * DESCRIPTION
- *   No retry is left for the current ERP. Check what has to be done 
+ *   No retry is left for the current ERP. Check what has to be done
  *   with the ERP.
  *     - do further defined ERP action or
- *     - wait for interrupt or 
+ *     - wait for interrupt or
  *     - exit with permanent error
  *
  * PARAMETER
@@ -2485,7 +2485,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 
                if (!(sense[2] & DASD_SENSE_BIT_0)) {
 
-                       /* issue a Diagnostic Control command with an 
+                       /* issue a Diagnostic Control command with an
                         * Inhibit Write subcommand */
 
                        switch (sense[25]) {
@@ -2535,14 +2535,14 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 }                              /* end dasd_3990_erp_further_erp */
 
 /*
- * DASD_3990_ERP_HANDLE_MATCH_ERP 
+ * DASD_3990_ERP_HANDLE_MATCH_ERP
  *
  * DESCRIPTION
  *   An error occurred again and an ERP has been detected which is already
- *   used to handle this error (e.g. retries). 
+ *   used to handle this error (e.g. retries).
  *   All prior ERP's are asumed to be successful and therefore removed
  *   from queue.
- *   If retry counter of matching erp is already 0, it is checked if further 
+ *   If retry counter of matching erp is already 0, it is checked if further
  *   action is needed (besides retry) or if the ERP has failed.
  *
  * PARAMETER
@@ -2631,7 +2631,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
  *   erp               erp-pointer to the head of the ERP action chain.
  *                     This means:
  *                      - either a ptr to an additional ERP cqr or
- *                      - the original given cqr (which's status might 
+ *                      - the original given cqr (which's status might
  *                        be modified)
  */
 struct dasd_ccw_req *
@@ -2723,22 +2723,3 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
        return erp;
 
 }                              /* end dasd_3990_erp_action */
-
-/*
- * 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-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index dc861446d0562b991427433df7605111429a818e..6e082688475a8f31352cefeebc46aff0ed3ba63e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_9336_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
 
 
 /*
- * DASD_9336_ERP_EXAMINE 
+ * DASD_9336_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -23,7 +23,7 @@
  *   'Chapter 7. 9336 Sense Data'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -39,22 +39,3 @@ dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
        return dasd_era_recover;
 
 }                              /* END dasd_9336_erp_examine */
-
-/*
- * 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-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index 4a5b79569aaaa463461f55a25dffc09f0d9b3b32..ddecb9808ed4b1c08e22399b8bb7151fc0cd636e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_9345_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
index 216bc4fba19998c2c5a92a8455d92f32d0dce4ab..9e9ae71796028162b94d45316776ec2b2f7f0d6b 100644 (file)
@@ -27,7 +27,7 @@
 #include "dasd_int.h"
 
 kmem_cache_t *dasd_page_cache;
-EXPORT_SYMBOL(dasd_page_cache);
+EXPORT_SYMBOL_GPL(dasd_page_cache);
 
 /*
  * dasd_devmap_t is used to store the features and the relation
@@ -48,6 +48,20 @@ struct dasd_devmap {
        struct dasd_uid uid;
 };
 
+/*
+ * dasd_servermap is used to store the server_id of all storage servers
+ * accessed by DASD device driver.
+ */
+struct dasd_servermap {
+       struct list_head list;
+       struct server_id {
+               char vendor[4];
+               char serial[15];
+       } sid;
+};
+
+static struct list_head dasd_serverlist;
+
 /*
  * Parameter parsing functions for dasd= parameter. The syntax is:
  *   <devno>           : (0x)?[0-9a-fA-F]+
@@ -64,6 +78,8 @@ struct dasd_devmap {
 
 int dasd_probeonly =  0;       /* is true, when probeonly mode is active */
 int dasd_autodetect = 0;       /* is true, when autodetection is active */
+int dasd_nopav = 0;            /* is true, when PAV is disabled */
+EXPORT_SYMBOL_GPL(dasd_nopav);
 
 /*
  * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
@@ -123,7 +139,7 @@ static inline int
 dasd_busid(char **str, int *id0, int *id1, int *devno)
 {
        int val, old_style;
+
        /* check for leading '0x' */
        old_style = 0;
        if ((*str)[0] == '0' && (*str)[1] == 'x') {
@@ -179,7 +195,7 @@ dasd_feature_list(char *str, char **endp)
        features = 0;
 
        while (1) {
-               for (len = 0; 
+               for (len = 0;
                     str[len] && str[len] != ':' && str[len] != ')'; len++);
                if (len == 2 && !strncmp(str, "ro", 2))
                        features |= DASD_FEATURE_READONLY;
@@ -228,19 +244,24 @@ dasd_parse_keyword( char *parsestring ) {
                length = strlen(parsestring);
                residual_str = parsestring + length;
         }
-       if (strncmp ("autodetect", parsestring, length) == 0) {
+       if (strncmp("autodetect", parsestring, length) == 0) {
                dasd_autodetect = 1;
                MESSAGE (KERN_INFO, "%s",
                         "turning to autodetection mode");
                 return residual_str;
         }
-        if (strncmp ("probeonly", parsestring, length) == 0) {
+       if (strncmp("probeonly", parsestring, length) == 0) {
                dasd_probeonly = 1;
                MESSAGE(KERN_INFO, "%s",
                        "turning to probeonly mode");
                 return residual_str;
         }
-        if (strncmp ("fixedbuffers", parsestring, length) == 0) {
+       if (strncmp("nopav", parsestring, length) == 0) {
+               dasd_nopav = 1;
+               MESSAGE(KERN_INFO, "%s", "disable PAV mode");
+               return residual_str;
+       }
+       if (strncmp("fixedbuffers", parsestring, length) == 0) {
                if (dasd_page_cache)
                        return residual_str;
                dasd_page_cache =
@@ -294,6 +315,8 @@ dasd_parse_range( char *parsestring ) {
        features = dasd_feature_list(str, &str);
        if (features < 0)
                return ERR_PTR(-EINVAL);
+       /* each device in dasd= parameter should be set initially online */
+       features |= DASD_FEATURE_INITIAL_ONLINE;
        while (from <= to) {
                sprintf(bus_id, "%01x.%01x.%04x",
                        from_id0, from_id1, from++);
@@ -359,7 +382,7 @@ dasd_parse(void)
  * Add a devmap for the device specified by busid. It is possible that
  * the devmap already exists (dasd= parameter). The order of the devices
  * added through this function will define the kdevs for the individual
- * devices. 
+ * devices.
  */
 static struct dasd_devmap *
 dasd_add_busid(char *bus_id, int features)
@@ -368,7 +391,7 @@ dasd_add_busid(char *bus_id, int features)
        int hash;
 
        new = (struct dasd_devmap *)
-               kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
+               kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
        if (!new)
                return ERR_PTR(-ENOMEM);
        spin_lock(&dasd_devmap_lock);
@@ -630,7 +653,8 @@ dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 
 static ssize_t
-dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+dasd_ro_store(struct device *dev, struct device_attribute *attr,
+             const char *buf, size_t count)
 {
        struct dasd_devmap *devmap;
        int ro_flag;
@@ -658,7 +682,7 @@ static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
  * use_diag controls whether the driver should use diag rather than ssch
  * to talk to the device
  */
-static ssize_t 
+static ssize_t
 dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct dasd_devmap *devmap;
@@ -673,7 +697,8 @@ dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 
 static ssize_t
-dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
+                   const char *buf, size_t count)
 {
        struct dasd_devmap *devmap;
        ssize_t rc;
@@ -697,11 +722,11 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const cha
        return rc;
 }
 
-static
-DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
+static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
 
 static ssize_t
-dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf)
+dasd_discipline_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
 {
        struct dasd_devmap *devmap;
        char *dname;
@@ -834,6 +859,38 @@ static struct attribute_group dasd_attr_group = {
        .attrs = dasd_attrs,
 };
 
+/*
+ * Check if the related storage server is already contained in the
+ * dasd_serverlist. If server is not contained, create new entry.
+ * Return 0 if server was already in serverlist,
+ *       1 if the server was added successfully
+ *      <0 in case of error.
+ */
+static int
+dasd_add_server(struct dasd_uid *uid)
+{
+       struct dasd_servermap *new, *tmp;
+
+       /* check if server is already contained */
+       list_for_each_entry(tmp, &dasd_serverlist, list)
+         // normale cmp?
+               if (strncmp(tmp->sid.vendor, uid->vendor,
+                           sizeof(tmp->sid.vendor)) == 0
+                   && strncmp(tmp->sid.serial, uid->serial,
+                              sizeof(tmp->sid.serial)) == 0)
+                       return 0;
+
+       new = (struct dasd_servermap *)
+               kzalloc(sizeof(struct dasd_servermap), GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+
+       strncpy(new->sid.vendor, uid->vendor, sizeof(new->sid.vendor));
+       strncpy(new->sid.serial, uid->serial, sizeof(new->sid.serial));
+       list_add(&new->list, &dasd_serverlist);
+       return 1;
+}
+
 
 /*
  * Return copy of the device unique identifier.
@@ -854,21 +911,26 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 
 /*
  * Register the given device unique identifier into devmap struct.
+ * Return 0 if server was already in serverlist,
+ *       1 if the server was added successful
+ *      <0 in case of error.
  */
 int
 dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 {
        struct dasd_devmap *devmap;
+       int rc;
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
                return PTR_ERR(devmap);
        spin_lock(&dasd_devmap_lock);
        devmap->uid = *uid;
+       rc = dasd_add_server(uid);
        spin_unlock(&dasd_devmap_lock);
-       return 0;
+       return rc;
 }
-EXPORT_SYMBOL(dasd_set_uid);
+EXPORT_SYMBOL_GPL(dasd_set_uid);
 
 /*
  * Return value of the specified feature.
@@ -880,7 +942,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature)
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
-               return (int) PTR_ERR(devmap);
+               return PTR_ERR(devmap);
 
        return ((devmap->features & feature) != 0);
 }
@@ -896,7 +958,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
-               return (int) PTR_ERR(devmap);
+               return PTR_ERR(devmap);
 
        spin_lock(&dasd_devmap_lock);
        if (flag)
@@ -932,8 +994,10 @@ dasd_devmap_init(void)
        dasd_max_devindex = 0;
        for (i = 0; i < 256; i++)
                INIT_LIST_HEAD(&dasd_hashlists[i]);
-       return 0;
 
+       /* Initialize servermap structure. */
+       INIT_LIST_HEAD(&dasd_serverlist);
+       return 0;
 }
 
 void
index 3f9d704d2657483f739dcced896a212413665882..4002f6c1c1b3222a01b1fa2ced3b8df3da0fe043 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_diag.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Based on.......: linux/drivers/s390/block/mdisk.c
@@ -336,7 +336,7 @@ dasd_diag_check_device(struct dasd_device *device)
 
        private = (struct dasd_diag_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
+               private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
                                "memory allocation failed for private data");
@@ -527,7 +527,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
                                   datasize, device);
        if (IS_ERR(cqr))
                return cqr;
-       
+
        dreq = (struct dasd_diag_req *) cqr->data;
        dreq->block_count = count;
        dbio = dreq->bio;
index 38a4e55f89539b90f514ea9f80b77d4f4d139475..b8c78267ff3ef01ef0e60a1e211784629f2f094e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_diag.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Based on.......: linux/drivers/s390/block/mdisk.h
index 7d5a6cee4bd8ff075c4c48ed6edccdb30cefb283..0dfab30e8089814ca75b1320ce4114a0942dcb8a 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_eckd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                 Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  *                 Carsten Otte <Cotte@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
@@ -24,6 +24,7 @@
 #include <asm/io.h>
 #include <asm/todclk.h>
 #include <asm/uaccess.h>
+#include <asm/cio.h>
 #include <asm/ccwdev.h>
 
 #include "dasd_int.h"
@@ -89,17 +90,22 @@ dasd_eckd_probe (struct ccw_device *cdev)
 {
        int ret;
 
-       ret = dasd_generic_probe (cdev, &dasd_eckd_discipline);
-       if (ret)
+       /* set ECKD specific ccw-device options */
+       ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
+       if (ret) {
+               printk(KERN_WARNING
+                      "dasd_eckd_probe: could not set ccw-device options "
+                      "for %s\n", cdev->dev.bus_id);
                return ret;
-       ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP | CCWDEV_ALLOW_FORCE);
-       return 0;
+       }
+       ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
+       return ret;
 }
 
 static int
 dasd_eckd_set_online(struct ccw_device *cdev)
 {
-       return dasd_generic_set_online (cdev, &dasd_eckd_discipline);
+       return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
 }
 
 static struct ccw_driver dasd_eckd_driver = {
@@ -210,14 +216,14 @@ check_XRC (struct ccw1         *de_ccw,
 
         /* switch on System Time Stamp - needed for XRC Support */
         if (private->rdc_data.facilities.XRC_supported) {
-                
+
                 data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
                 data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-                
+
                 data->ep_sys_time = get_clock ();
-                
+
                 de_ccw->count = sizeof (struct DE_eckd_data);
-                de_ccw->flags |= CCW_FLAG_SLI;  
+               de_ccw->flags |= CCW_FLAG_SLI;
         }
 
         return;
@@ -296,8 +302,8 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
        /* check for sequential prestage - enhance cylinder range */
        if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
            data->attributes.operation == DASD_SEQ_ACCESS) {
-               
-               if (end.cyl + private->attrib.nr_cyl < geo.cyl) 
+
+               if (end.cyl + private->attrib.nr_cyl < geo.cyl)
                        end.cyl += private->attrib.nr_cyl;
                else
                        end.cyl = (geo.cyl - 1);
@@ -317,7 +323,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
        struct dasd_eckd_private *private;
        int sector;
        int dn, d;
-                               
+
        private = (struct dasd_eckd_private *) device->private;
 
        DBF_DEV_EVENT(DBF_INFO, device,
@@ -540,6 +546,86 @@ dasd_eckd_read_conf(struct dasd_device *device)
        return 0;
 }
 
+/*
+ * Build CP for Perform Subsystem Function - SSC.
+ */
+struct dasd_ccw_req *
+dasd_eckd_build_psf_ssc(struct dasd_device *device)
+{
+       struct dasd_ccw_req *cqr;
+       struct dasd_psf_ssc_data *psf_ssc_data;
+       struct ccw1 *ccw;
+
+       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+                                 sizeof(struct dasd_psf_ssc_data),
+                                 device);
+
+       if (IS_ERR(cqr)) {
+              DEV_MESSAGE(KERN_WARNING, device, "%s",
+                          "Could not allocate PSF-SSC request");
+              return cqr;
+       }
+       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
+       psf_ssc_data->order = PSF_ORDER_SSC;
+       psf_ssc_data->suborder = 0x08;
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->cda = (__u32)(addr_t)psf_ssc_data;
+       ccw->count = 66;
+
+       cqr->device = device;
+       cqr->expires = 10*HZ;
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+       return cqr;
+}
+
+/*
+ * Perform Subsystem Function.
+ * It is necessary to trigger CIO for channel revalidation since this
+ * call might change behaviour of DASD devices.
+ */
+static int
+dasd_eckd_psf_ssc(struct dasd_device *device)
+{
+       struct dasd_ccw_req *cqr;
+       int rc;
+
+       cqr = dasd_eckd_build_psf_ssc(device);
+       if (IS_ERR(cqr))
+              return PTR_ERR(cqr);
+
+       rc = dasd_sleep_on(cqr);
+       if (!rc)
+              /* trigger CIO to reprobe devices */
+              css_schedule_reprobe();
+       dasd_sfree_request(cqr, cqr->device);
+       return rc;
+}
+
+/*
+ * Valide storage server of current device.
+ */
+static int
+dasd_eckd_validate_server(struct dasd_device *device)
+{
+       int rc;
+
+       /* Currently PAV is the only reason to 'validate' server on LPAR */
+       if (dasd_nopav || MACHINE_IS_VM)
+               return 0;
+
+       rc = dasd_eckd_psf_ssc(device);
+       if (rc)
+               /* may be requested feature is not available on server,
+                * therefore just report error and go ahead */
+               DEV_MESSAGE(KERN_INFO, device,
+                           "Perform Subsystem Function returned rc=%d", rc);
+       /* RE-Read Configuration Data */
+       return dasd_eckd_read_conf(device);
+}
+
 /*
  * Check device characteristics.
  * If the device is accessible using ECKD discipline, the device is enabled.
@@ -554,7 +640,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 
        private = (struct dasd_eckd_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_eckd_private),
+               private = kzalloc(sizeof(struct dasd_eckd_private),
                                  GFP_KERNEL | GFP_DMA);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
@@ -562,7 +648,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                                    "data");
                        return -ENOMEM;
                }
-               memset(private, 0, sizeof(struct dasd_eckd_private));
                device->private = (void *) private;
        }
        /* Invalidate status of initial analysis. */
@@ -571,16 +656,29 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        private->attrib.operation = DASD_NORMAL_CACHE;
        private->attrib.nr_cyl = 0;
 
+       /* Read Configuration Data */
+       rc = dasd_eckd_read_conf(device);
+       if (rc)
+               return rc;
+
+       /* Generate device unique id and register in devmap */
+       rc = dasd_eckd_generate_uid(device, &uid);
+       if (rc)
+               return rc;
+       rc = dasd_set_uid(device->cdev, &uid);
+       if (rc == 1)    /* new server found */
+               rc = dasd_eckd_validate_server(device);
+       if (rc)
+               return rc;
+
        /* Read Device Characteristics */
        rdc_data = (void *) &(private->rdc_data);
        memset(rdc_data, 0, sizeof(rdc_data));
        rc = read_dev_chars(device->cdev, &rdc_data, 64);
-       if (rc) {
+       if (rc)
                DEV_MESSAGE(KERN_WARNING, device,
-                           "Read device characteristics returned error %d",
-                           rc);
-               return rc;
-       }
+                           "Read device characteristics returned "
+                           "rc=%d", rc);
 
        DEV_MESSAGE(KERN_INFO, device,
                    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
@@ -591,19 +689,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                    private->rdc_data.no_cyl,
                    private->rdc_data.trk_per_cyl,
                    private->rdc_data.sec_per_trk);
-
-       /* Read Configuration Data */
-       rc = dasd_eckd_read_conf (device);
-       if (rc)
-               return rc;
-
-       /* Generate device unique id and register in devmap */
-       rc = dasd_eckd_generate_uid(device, &uid);
-       if (rc)
-               return rc;
-
-       rc = dasd_set_uid(device->cdev, &uid);
-
        return rc;
 }
 
@@ -773,7 +858,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
                    ((private->rdc_data.no_cyl *
                      private->rdc_data.trk_per_cyl *
                      blk_per_trk * (device->bp_block >> 9)) >> 1),
-                   ((blk_per_trk * device->bp_block) >> 10), 
+                   ((blk_per_trk * device->bp_block) >> 10),
                    private->uses_cdl ?
                    "compatible disk layout" : "linux disk layout");
 
@@ -970,7 +1055,7 @@ dasd_eckd_format_device(struct dasd_device * device,
                                if (i < 3) {
                                        ect->kl = 4;
                                        ect->dl = sizes_trk0[i] - 4;
-                               } 
+                               }
                        }
                        if ((fdata->intensity & 0x08) &&
                            fdata->start_unit == 1) {
@@ -1270,7 +1355,7 @@ dasd_eckd_fill_info(struct dasd_device * device,
 
 /*
  * Release device ioctl.
- * Buils a channel programm to releases a prior reserved 
+ * Buils a channel programm to releases a prior reserved
  * (see dasd_eckd_reserve) device.
  */
 static int
@@ -1310,8 +1395,8 @@ dasd_eckd_release(struct dasd_device *device)
 /*
  * Reserve device ioctl.
  * Options are set to 'synchronous wait for interrupt' and
- * 'timeout the request'. This leads to a terminate IO if 
- * the interrupt is outstanding for a certain time. 
+ * 'timeout the request'. This leads to a terminate IO if
+ * the interrupt is outstanding for a certain time.
  */
 static int
 dasd_eckd_reserve(struct dasd_device *device)
@@ -1349,7 +1434,7 @@ dasd_eckd_reserve(struct dasd_device *device)
 
 /*
  * Steal lock ioctl - unconditional reserve device.
- * Buils a channel programm to break a device's reservation. 
+ * Buils a channel programm to break a device's reservation.
  * (unconditional reserve)
  */
 static int
@@ -1521,6 +1606,40 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
        }
 }
 
+/*
+ * Dump the range of CCWs into 'page' buffer
+ * and return number of printed chars.
+ */
+static inline int
+dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
+{
+       int len, count;
+       char *datap;
+
+       len = 0;
+       while (from <= to) {
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                              " CCW %p: %08X %08X DAT:",
+                              from, ((int *) from)[0], ((int *) from)[1]);
+
+               /* get pointer to data (consider IDALs) */
+               if (from->flags & CCW_FLAG_IDA)
+                       datap = (char *) *((addr_t *) (addr_t) from->cda);
+               else
+                       datap = (char *) ((addr_t) from->cda);
+
+               /* dump data (max 32 bytes) */
+               for (count = 0; count < from->count && count < 32; count++) {
+                       if (count % 8 == 0) len += sprintf(page + len, " ");
+                       if (count % 4 == 0) len += sprintf(page + len, " ");
+                       len += sprintf(page + len, "%02x", datap[count]);
+               }
+               len += sprintf(page + len, "\n");
+               from++;
+       }
+       return len;
+}
+
 /*
  * Print sense data and related channel program.
  * Parts are printed because printk buffer is only 1024 bytes.
@@ -1530,8 +1649,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                     struct irb *irb)
 {
        char *page;
-       struct ccw1 *act, *end, *last;
-       int len, sl, sct, count;
+       struct ccw1 *first, *last, *fail, *from, *to;
+       int len, sl, sct;
 
        page = (char *) get_zeroed_page(GFP_ATOMIC);
        if (page == NULL) {
@@ -1539,7 +1658,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                            "No memory to dump sense data");
                return;
        }
-       len = sprintf(page, KERN_ERR PRINTK_HEADER
+       /* dump the sense data */
+       len = sprintf(page,  KERN_ERR PRINTK_HEADER
                      " I/O status report for device %s:\n",
                      device->cdev->dev.bus_id);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
@@ -1564,87 +1684,55 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 
                if (irb->ecw[27] & DASD_SENSE_BIT_0) {
                        /* 24 Byte Sense Data */
-                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                                      " 24 Byte: %x MSG %x, "
-                                      "%s MSGb to SYSOP\n",
-                                      irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
-                                      irb->ecw[1] & 0x10 ? "" : "no");
+                       sprintf(page + len, KERN_ERR PRINTK_HEADER
+                               " 24 Byte: %x MSG %x, "
+                               "%s MSGb to SYSOP\n",
+                               irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
+                               irb->ecw[1] & 0x10 ? "" : "no");
                } else {
                        /* 32 Byte Sense Data */
-                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                                      " 32 Byte: Format: %x "
-                                      "Exception class %x\n",
-                                      irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
+                       sprintf(page + len, KERN_ERR PRINTK_HEADER
+                               " 32 Byte: Format: %x "
+                               "Exception class %x\n",
+                               irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
                }
        } else {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " SORRY - NO VALID SENSE AVAILABLE\n");
+               sprintf(page + len, KERN_ERR PRINTK_HEADER
+                       " SORRY - NO VALID SENSE AVAILABLE\n");
        }
-       MESSAGE_LOG(KERN_ERR, "%s",
-                   page + sizeof(KERN_ERR PRINTK_HEADER));
-
-       /* dump the Channel Program */
-       /* print first CCWs (maximum 8) */
-       act = req->cpaddr;
-        for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
-       end = min(act + 8, last);
-       len = sprintf(page, KERN_ERR PRINTK_HEADER
+       printk("%s", page);
+
+       /* dump the Channel Program (max 140 Bytes per line) */
+       /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+       first = req->cpaddr;
+       for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+       to = min(first + 6, last);
+       len = sprintf(page,  KERN_ERR PRINTK_HEADER
                      " Related CP in req: %p\n", req);
-       while (act <= end) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
-       }
-       MESSAGE_LOG(KERN_ERR, "%s",
-                   page + sizeof(KERN_ERR PRINTK_HEADER));
+       dasd_eckd_dump_ccw_range(first, to, page + len);
+       printk("%s", page);
 
-       /* print failing CCW area */
+       /* print failing CCW area (maximum 4) */
+       /* scsw->cda is either valid or zero  */
        len = 0;
-       if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) {
-               act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2;
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
-       }
-       end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last);
-       while (act <= end) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
+       from = ++to;
+       fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+       if (from <  fail - 2) {
+               from = fail - 2;     /* there is a gap - print header */
+               len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
        }
+       to = min(fail + 1, last);
+       len += dasd_eckd_dump_ccw_range(from, to, page + len);
 
-       /* print last CCWs */
-       if (act <  last - 2) {
-               act = last - 2;
+       /* print last CCWs (maximum 2) */
+       from = max(from, ++to);
+       if (from < last - 1) {
+               from = last - 1;     /* there is a gap - print header */
                len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
        }
-       while (act <= last) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
-       }
+       len += dasd_eckd_dump_ccw_range(from, last, page + len);
        if (len > 0)
-               MESSAGE_LOG(KERN_ERR, "%s",
-                           page + sizeof(KERN_ERR PRINTK_HEADER));
+               printk("%s", page);
        free_page((unsigned long) page);
 }
 
@@ -1685,14 +1773,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
 static int __init
 dasd_eckd_init(void)
 {
-       int ret;
-
        ASCEBC(dasd_eckd_discipline.ebcname, 4);
-
-       ret = ccw_driver_register(&dasd_eckd_driver);
-       if (!ret)
-               dasd_generic_auto_online(&dasd_eckd_driver);
-       return ret;
+       return ccw_driver_register(&dasd_eckd_driver);
 }
 
 static void __exit
@@ -1703,22 +1785,3 @@ dasd_eckd_cleanup(void)
 
 module_init(dasd_eckd_init);
 module_exit(dasd_eckd_cleanup);
-
-/*
- * 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-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index d5734e976e1c7da5fd599c52f83ba75a0f6e6e18..712ff1650134c5e1b60953758c922440231bd66d 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_eckd.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
 #define DASD_ECKD_CCW_RESERVE           0xB4
 
 /*
- *Perform Subsystem Function / Sub-Orders
+ * Perform Subsystem Function / Sub-Orders
  */
-#define PSF_ORDER_PRSSD                         0x18
+#define PSF_ORDER_PRSSD 0x18
+#define PSF_ORDER_SSC  0x1D
 
 /*****************************************************************************
  * SECTION: Type Definitions
@@ -155,7 +156,7 @@ struct dasd_eckd_characteristics {
                unsigned char reserved2:4;
                unsigned char reserved3:8;
                unsigned char defect_wr:1;
-               unsigned char XRC_supported:1; 
+               unsigned char XRC_supported:1;
                unsigned char reserved4:1;
                unsigned char striping:1;
                unsigned char reserved5:4;
@@ -343,7 +344,7 @@ struct dasd_eckd_path {
 };
 
 /*
- * Perform Subsystem Function - Prepare for Read Subsystem Data         
+ * Perform Subsystem Function - Prepare for Read Subsystem Data
  */
 struct dasd_psf_prssd_data {
        unsigned char order;
@@ -353,4 +354,15 @@ struct dasd_psf_prssd_data {
        unsigned char varies[9];
 } __attribute__ ((packed));
 
+/*
+ * Perform Subsystem Function - Set Subsystem Characteristics
+ */
+struct dasd_psf_ssc_data {
+       unsigned char order;
+       unsigned char flags;
+       unsigned char cu_type[4];
+       unsigned char suborder;
+       unsigned char reserved[59];
+} __attribute__((packed));
+
 #endif                         /* DASD_ECKD_H */
index 2d946b6ca074cd0eea567e680ac00fabfd614d59..da65f1b032f5ad59748e356342afd1793eb0878e 100644 (file)
@@ -89,7 +89,7 @@ struct eerbuffer {
 };
 
 static LIST_HEAD(bufferlist);
-static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(bufferlock);
 static DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);
 
 /*
@@ -276,7 +276,7 @@ struct dasd_eer_header {
        __u64 tv_sec;
        __u64 tv_usec;
        char busid[DASD_EER_BUSID_SIZE];
-};
+} __attribute__ ((packed));
 
 /*
  * The following function can be used for those triggers that have
@@ -521,6 +521,8 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
        unsigned long flags;
 
        eerb = kzalloc(sizeof(struct eerbuffer), GFP_KERNEL);
+       if (!eerb)
+               return -ENOMEM;
        eerb->buffer_page_count = eer_pages;
        if (eerb->buffer_page_count < 1 ||
            eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {
index b842377cb0c6c51fa562ba364d4bcab4b2a0d07e..4108d96f6a5a8b9ae5622c79efc09f16adf38b04 100644 (file)
@@ -90,7 +90,7 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
 
         /* just retry - there is nothing to save ... I got no sense data.... */
         if (cqr->retries > 0) {
-                DEV_MESSAGE (KERN_DEBUG, device, 
+               DEV_MESSAGE (KERN_DEBUG, device,
                              "default ERP called (%i retries left)",
                              cqr->retries);
                cqr->lpm    = LPM_ANYPATH;
@@ -155,7 +155,7 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
 
 /*
  * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the 
+ * all error recovery ccws that have been chained in from of the
  * real request.
  */
 static inline void
@@ -227,12 +227,12 @@ dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
                /*
                 * Log bytes arround failed CCW but only if we did
                 * not log the whole CP of the CCW is outside the
-                * logged CP. 
+                * logged CP.
                 */
                if (cplength > 40 ||
                    ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
                     (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-                       
+
                        DEV_MESSAGE(KERN_ERR, device,
                                    "Failed CCW (%p) (area):",
                                    (void *) (long) cpa);
index 91145698f8e926c7265e3d1581abf61479d62b9b..bb7755b9b19d7dfa408a9d79c959ff40f858468e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_fba.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
@@ -56,19 +56,13 @@ static struct ccw_driver dasd_fba_driver; /* see below */
 static int
 dasd_fba_probe(struct ccw_device *cdev)
 {
-       int ret;
-
-       ret = dasd_generic_probe (cdev, &dasd_fba_discipline);
-       if (ret)
-               return ret;
-       ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
-       return 0;
+       return dasd_generic_probe(cdev, &dasd_fba_discipline);
 }
 
 static int
 dasd_fba_set_online(struct ccw_device *cdev)
 {
-       return dasd_generic_set_online (cdev, &dasd_fba_discipline);
+       return dasd_generic_set_online(cdev, &dasd_fba_discipline);
 }
 
 static struct ccw_driver dasd_fba_driver = {
@@ -125,13 +119,13 @@ static int
 dasd_fba_check_characteristics(struct dasd_device *device)
 {
        struct dasd_fba_private *private;
-       struct ccw_device *cdev = device->cdev; 
+       struct ccw_device *cdev = device->cdev;
        void *rdc_data;
        int rc;
 
        private = (struct dasd_fba_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
+               private = kzalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
                                    "memory allocation failed for private "
@@ -204,7 +198,7 @@ dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
        if (irb->scsw.cstat == 0x00 &&
            irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
                return dasd_era_none;
-       
+
        cdev = device->cdev;
        switch (cdev->id.dev_type) {
        case 0x3370:
@@ -539,7 +533,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
  * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
  * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
  * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
- * addition we have one define extent ccw + 16 bytes of data and a 
+ * addition we have one define extent ccw + 16 bytes of data and a
  * locate record ccw for each block (stupid devices!) + 16 bytes of data.
  * That makes:
  * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
@@ -569,16 +563,8 @@ static struct dasd_discipline dasd_fba_discipline = {
 static int __init
 dasd_fba_init(void)
 {
-       int ret;
-
        ASCEBC(dasd_fba_discipline.ebcname, 4);
-
-       ret = ccw_driver_register(&dasd_fba_driver);
-       if (ret)
-               return ret;
-
-       dasd_generic_auto_online(&dasd_fba_driver);
-       return 0;
+       return ccw_driver_register(&dasd_fba_driver);
 }
 
 static void __exit
@@ -589,22 +575,3 @@ dasd_fba_cleanup(void)
 
 module_init(dasd_fba_init);
 module_exit(dasd_fba_cleanup);
-
-/*
- * 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-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index da1fa91fc01dd42a94cffe047459c9ffc6a00136..14c910baa5fe6160192b7c548d8921b829707eda 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_fba.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
index d4b13e300a76db523ad2f263ce2f55023c108e6e..03a83efc34c4f71db19f4403c2170554fa4f9f91 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_int.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
@@ -186,7 +186,7 @@ struct dasd_ccw_req {
         void *callback_data;
 };
 
-/* 
+/*
  * dasd_ccw_req -> status can be:
  */
 #define DASD_CQR_FILLED   0x00 /* request is ready to be processed */
@@ -248,7 +248,7 @@ struct dasd_discipline {
         /*
          * Error recovery functions. examine_error() returns a value that
          * indicates what to do for an error condition. If examine_error()
-         * returns 'dasd_era_recover' erp_action() is called to create a 
+        * returns 'dasd_era_recover' erp_action() is called to create a
          * special error recovery ccw. erp_postaction() is called after
          * an error recovery ccw has finished its execution. dump_sense
          * is called for every error condition to print the sense data
@@ -302,11 +302,11 @@ struct dasd_device {
        spinlock_t request_queue_lock;
        struct block_device *bdev;
         unsigned int devindex;
-       unsigned long blocks;           /* size of volume in blocks */
-       unsigned int bp_block;          /* bytes per block */
-       unsigned int s2b_shift;         /* log2 (bp_block/512) */
-       unsigned long flags;            /* per device flags */
-       unsigned short features;        /* copy of devmap-features (read-only!) */
+       unsigned long blocks;      /* size of volume in blocks */
+       unsigned int bp_block;     /* bytes per block */
+       unsigned int s2b_shift;    /* log2 (bp_block/512) */
+       unsigned long flags;       /* per device flags */
+       unsigned short features;   /* copy of devmap-features (read-only!) */
 
        /* extended error reporting stuff (eer) */
        struct dasd_ccw_req *eer_cqr;
@@ -513,12 +513,12 @@ void dasd_generic_remove (struct ccw_device *cdev);
 int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
-void dasd_generic_auto_online (struct ccw_driver *);
 
 /* externals in dasd_devmap.c */
 extern int dasd_max_devindex;
 extern int dasd_probeonly;
 extern int dasd_autodetect;
+extern int dasd_nopav;
 
 int dasd_devmap_init(void);
 void dasd_devmap_exit(void);
@@ -606,22 +606,3 @@ static inline int dasd_eer_enabled(struct dasd_device *device)
 #endif                         /* __KERNEL__ */
 
 #endif                         /* DASD_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index b8c80d28df41dba762d8827608fd22e5c5c93e2f..302bcd0f28be4c4532862915417ba2a5add9ea2d 100644 (file)
@@ -90,10 +90,10 @@ static int
 dasd_ioctl_quiesce(struct dasd_device *device)
 {
        unsigned long flags;
-       
+
        if (!capable (CAP_SYS_ADMIN))
                return -EACCES;
-       
+
        DEV_MESSAGE (KERN_DEBUG, device, "%s",
                     "Quiesce IO on device");
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
@@ -110,13 +110,13 @@ static int
 dasd_ioctl_resume(struct dasd_device *device)
 {
        unsigned long flags;
-       
-       if (!capable (CAP_SYS_ADMIN)) 
+
+       if (!capable (CAP_SYS_ADMIN))
                return -EACCES;
 
        DEV_MESSAGE (KERN_DEBUG, device, "%s",
                     "resume IO on device");
-       
+
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
        device->stopped &= ~DASD_STOPPED_QUIESCE;
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
@@ -287,7 +287,7 @@ dasd_ioctl_information(struct dasd_device *device,
        dasd_info->open_count = atomic_read(&device->open_count);
        if (!device->bdev)
                dasd_info->open_count++;
-       
+
        /*
         * check if device is really formatted
         * LDL / CDL was returned by 'fill_info'
index eecb2afad5c25ce460acdeba66041b7d5f291838..3c1314b7391b0fe5141982210c366dfb902875e0 100644 (file)
@@ -50,6 +50,9 @@ struct raw3270 {
        unsigned char *ascebc;          /* ascii -> ebcdic table */
        struct class_device *clttydev;  /* 3270-class tty device ptr */
        struct class_device *cltubdev;  /* 3270-class tub device ptr */
+
+       struct raw3270_request init_request;
+       unsigned char init_data[256];
 };
 
 /* raw3270->flags */
@@ -484,8 +487,6 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
        } __attribute__ ((packed)) aua;
 } __attribute__ ((packed));
 
-static unsigned char raw3270_init_data[256];
-static struct raw3270_request raw3270_init_request;
 static struct diag210 raw3270_init_diag210;
 static DECLARE_MUTEX(raw3270_init_sem);
 
@@ -644,17 +645,17 @@ __raw3270_size_device(struct raw3270 *rp)
         * required (3270 device switched to 'stand-by') and command
         * rejects (old devices that can't do 'read partition').
         */
-       memset(&raw3270_init_request, 0, sizeof(raw3270_init_request));
-       memset(raw3270_init_data, 0, sizeof(raw3270_init_data));
-       /* Store 'read partition' data stream to raw3270_init_data */
-       memcpy(raw3270_init_data, wbuf, sizeof(wbuf));
-       INIT_LIST_HEAD(&raw3270_init_request.list);
-       raw3270_init_request.ccw.cmd_code = TC_WRITESF;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = sizeof(wbuf);
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
-
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       memset(&rp->init_request, 0, sizeof(rp->init_request));
+       memset(&rp->init_data, 0, 256);
+       /* Store 'read partition' data stream to init_data */
+       memcpy(&rp->init_data, wbuf, sizeof(wbuf));
+       INIT_LIST_HEAD(&rp->init_request.list);
+       rp->init_request.ccw.cmd_code = TC_WRITESF;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = sizeof(wbuf);
+       rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
+
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        if (rc)
                /* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
                return rc;
@@ -679,18 +680,18 @@ __raw3270_size_device(struct raw3270 *rp)
         * The device accepted the 'read partition' command. Now
         * set up a read ccw and issue it.
         */
-       raw3270_init_request.ccw.cmd_code = TC_READMOD;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = sizeof(raw3270_init_data);
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       rp->init_request.ccw.cmd_code = TC_READMOD;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = sizeof(rp->init_data);
+       rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        if (rc)
                return rc;
        /* Got a Query Reply */
-       count = sizeof(raw3270_init_data) - raw3270_init_request.rescnt;
-       uap = (struct raw3270_ua *) (raw3270_init_data + 1);
+       count = sizeof(rp->init_data) - rp->init_request.rescnt;
+       uap = (struct raw3270_ua *) (rp->init_data + 1);
        /* Paranoia check. */
-       if (raw3270_init_data[0] != 0x88 || uap->uab.qcode != 0x81)
+       if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
                return -EOPNOTSUPP;
        /* Copy rows/columns of default Usable Area */
        rp->rows = uap->uab.h;
@@ -749,18 +750,18 @@ raw3270_reset_device(struct raw3270 *rp)
        int rc;
 
        down(&raw3270_init_sem);
-       memset(&raw3270_init_request, 0, sizeof(raw3270_init_request));
-       memset(raw3270_init_data, 0, sizeof(raw3270_init_data));
-       /* Store reset data stream to raw3270_init_data/raw3270_init_request */
-       raw3270_init_data[0] = TW_KR;
-       INIT_LIST_HEAD(&raw3270_init_request.list);
-       raw3270_init_request.ccw.cmd_code = TC_EWRITEA;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = 1;
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
+       memset(&rp->init_request, 0, sizeof(rp->init_request));
+       memset(&rp->init_data, 0, sizeof(rp->init_data));
+       /* Store reset data stream to init_data/init_request */
+       rp->init_data[0] = TW_KR;
+       INIT_LIST_HEAD(&rp->init_request.list);
+       rp->init_request.ccw.cmd_code = TC_EWRITEA;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = 1;
+       rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
        rp->view = &raw3270_init_view;
        raw3270_init_view.dev = rp;
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        raw3270_init_view.dev = 0;
        rp->view = 0;
        up(&raw3270_init_sem);
@@ -854,7 +855,7 @@ raw3270_setup_console(struct ccw_device *cdev)
        char *ascebc;
        int rc;
 
-       rp = (struct raw3270 *) alloc_bootmem(sizeof(struct raw3270));
+       rp = (struct raw3270 *) alloc_bootmem_low(sizeof(struct raw3270));
        ascebc = (char *) alloc_bootmem(256);
        rc = raw3270_setup_device(cdev, rp, ascebc);
        if (rc)
@@ -895,7 +896,7 @@ raw3270_create_device(struct ccw_device *cdev)
        char *ascebc;
        int rc;
 
-       rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL);
+       rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
        if (!rp)
                return ERR_PTR(-ENOMEM);
        ascebc = kmalloc(256, GFP_KERNEL);
index 0960bef7b199ca6c45868f6e746dee1a862550ac..15b895496a45025038559b18eb874d1b6b6cfc50 100644 (file)
@@ -224,39 +224,6 @@ is_blacklisted (int ssid, int devno)
 }
 
 #ifdef CONFIG_PROC_FS
-static int
-__s390_redo_validation(struct subchannel_id schid, void *data)
-{
-       int ret;
-       struct subchannel *sch;
-
-       sch = get_subchannel_by_schid(schid);
-       if (sch) {
-               /* Already known. */
-               put_device(&sch->dev);
-               return 0;
-       }
-       ret = css_probe_device(schid);
-       if (ret == -ENXIO)
-               return ret; /* We're through. */
-       if (ret == -ENOMEM)
-               /* Stop validation for now. Bad, but no need for a panic. */
-               return ret;
-       return 0;
-}
-
-/*
- * Function: s390_redo_validation
- * Look for no longer blacklisted devices
- * FIXME: there must be a better way to do this */
-static inline void
-s390_redo_validation (void)
-{
-       CIO_TRACE_EVENT (0, "redoval");
-
-       for_each_subchannel(__s390_redo_validation, NULL);
-}
-
 /*
  * Function: blacklist_parse_proc_parameters
  * parse the stuff which is piped to /proc/cio_ignore
@@ -281,7 +248,7 @@ blacklist_parse_proc_parameters (char *buf)
                return;
        }
 
-       s390_redo_validation ();
+       css_schedule_reprobe();
 }
 
 /* Iterator struct for all devices. */
index bdfee7fbaa2ea1f4f9af9e6c964ef04c52f6cd09..c7319a07ba35161fde79dac21de10332d0387736 100644 (file)
@@ -404,21 +404,24 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
 }
 
 static int
-__ccwgroup_driver_unregister_device(struct device *dev, void *data)
+__ccwgroup_match_all(struct device *dev, void *data)
 {
-       __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
-       device_unregister(dev);
-       put_device(dev);
-       return 0;
+       return 1;
 }
 
 void
 ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
 {
+       struct device *dev;
+
        /* We don't want ccwgroup devices to live longer than their driver. */
        get_driver(&cdriver->driver);
-       driver_for_each_device(&cdriver->driver, NULL, NULL,
-                              __ccwgroup_driver_unregister_device);
+       while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
+                                        __ccwgroup_match_all))) {
+               __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+               device_unregister(dev);
+               put_device(dev);
+       }
        put_driver(&cdriver->driver);
        driver_unregister(&cdriver->driver);
 }
index 72187e54dcac79353107616bac3fb1aec3f1b4d0..b00f3ed051a094bf259d90b62026959ad139143c 100644 (file)
@@ -244,8 +244,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
 
        if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) &&
            (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) &&
-           (sch->schib.pmcw.lpum == mask) &&
-           (sch->vpm == 0)) {
+           (sch->schib.pmcw.lpum == mask)) {
                int cc;
 
                cc = cio_clear(sch);
@@ -918,12 +917,13 @@ chp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
        chp = to_channelpath(container_of(kobj, struct device, kobj));
        css = to_css(chp->dev.parent);
 
-       size = sizeof(struct cmg_chars);
+       size = sizeof(struct cmg_entry);
 
        /* Only allow single reads. */
        if (off || count < size)
                return 0;
        chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->id);
+       count = size;
        return count;
 }
 
index 07ef3f640f4aa73ec17460a93ab020f21a9bfb2e..1c3e8e9012b08c3553c1b5b7de806a87598f2fc0 100644 (file)
@@ -3,9 +3,10 @@
  *
  * Linux on zSeries Channel Measurement Facility support
  *
- * Copyright 2000,2003 IBM Corporation
+ * Copyright 2000,2006 IBM Corporation
  *
- * Author: Arnd Bergmann <arndb@de.ibm.com>
+ * Authors: Arnd Bergmann <arndb@de.ibm.com>
+ *         Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com>
  *
@@ -96,9 +97,9 @@ module_param(format, bool, 0444);
 /**
  * struct cmb_operations - functions to use depending on cmb_format
  *
- * all these functions operate on a struct cmf_device. There is only
- * one instance of struct cmb_operations because all cmf_device
- * objects are guaranteed to be of the same type.
+ * Most of these functions operate on a struct ccw_device. There is only
+ * one instance of struct cmb_operations because the format of the measurement
+ * data is guaranteed to be the same for every ccw_device.
  *
  * @alloc:     allocate memory for a channel measurement block,
  *             either with the help of a special pool or with kmalloc
@@ -107,6 +108,7 @@ module_param(format, bool, 0444);
  * @readall:   read a measurement block in a common format
  * @reset:     clear the data in the associated measurement block and
  *             reset its time stamp
+ * @align:     align an allocated block so that the hardware can use it
  */
 struct cmb_operations {
        int (*alloc)  (struct ccw_device*);
@@ -115,11 +117,19 @@ struct cmb_operations {
        u64 (*read)   (struct ccw_device*, int);
        int (*readall)(struct ccw_device*, struct cmbdata *);
        void (*reset) (struct ccw_device*);
+       void * (*align) (void *);
 
        struct attribute_group *attr_group;
 };
 static struct cmb_operations *cmbops;
 
+struct cmb_data {
+       void *hw_block;   /* Pointer to block updated by hardware */
+       void *last_block; /* Last changed block copied from hardware block */
+       int size;         /* Size of hw_block and last_block */
+       unsigned long long last_update;  /* when last_block was updated */
+};
+
 /* our user interface is designed in terms of nanoseconds,
  * while the hardware measures total times in its own
  * unit.*/
@@ -226,63 +236,229 @@ struct set_schib_struct {
        unsigned long address;
        wait_queue_head_t wait;
        int ret;
+       struct kref kref;
 };
 
+static void cmf_set_schib_release(struct kref *kref)
+{
+       struct set_schib_struct *set_data;
+
+       set_data = container_of(kref, struct set_schib_struct, kref);
+       kfree(set_data);
+}
+
+#define CMF_PENDING 1
+
 static int set_schib_wait(struct ccw_device *cdev, u32 mme,
                                int mbfc, unsigned long address)
 {
-       struct set_schib_struct s = {
-               .mme = mme,
-               .mbfc = mbfc,
-               .address = address,
-               .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s.wait),
-       };
+       struct set_schib_struct *set_data;
+       int ret;
 
        spin_lock_irq(cdev->ccwlock);
-       s.ret = set_schib(cdev, mme, mbfc, address);
-       if (s.ret != -EBUSY) {
-               goto out_nowait;
+       if (!cdev->private->cmb) {
+               ret = -ENODEV;
+               goto out;
        }
+       set_data = kzalloc(sizeof(struct set_schib_struct), GFP_ATOMIC);
+       if (!set_data) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       init_waitqueue_head(&set_data->wait);
+       kref_init(&set_data->kref);
+       set_data->mme = mme;
+       set_data->mbfc = mbfc;
+       set_data->address = address;
+
+       ret = set_schib(cdev, mme, mbfc, address);
+       if (ret != -EBUSY)
+               goto out_put;
 
        if (cdev->private->state != DEV_STATE_ONLINE) {
-               s.ret = -EBUSY;
                /* if the device is not online, don't even try again */
-               goto out_nowait;
+               ret = -EBUSY;
+               goto out_put;
        }
+
        cdev->private->state = DEV_STATE_CMFCHANGE;
-       cdev->private->cmb_wait = &s;
-       s.ret = 1;
+       set_data->ret = CMF_PENDING;
+       cdev->private->cmb_wait = set_data;
 
        spin_unlock_irq(cdev->ccwlock);
-       if (wait_event_interruptible(s.wait, s.ret != 1)) {
+       if (wait_event_interruptible(set_data->wait,
+                                    set_data->ret != CMF_PENDING)) {
                spin_lock_irq(cdev->ccwlock);
-               if (s.ret == 1) {
-                       s.ret = -ERESTARTSYS;
-                       cdev->private->cmb_wait = 0;
+               if (set_data->ret == CMF_PENDING) {
+                       set_data->ret = -ERESTARTSYS;
                        if (cdev->private->state == DEV_STATE_CMFCHANGE)
                                cdev->private->state = DEV_STATE_ONLINE;
                }
                spin_unlock_irq(cdev->ccwlock);
        }
-       return s.ret;
-
-out_nowait:
+       spin_lock_irq(cdev->ccwlock);
+       cdev->private->cmb_wait = NULL;
+       ret = set_data->ret;
+out_put:
+       kref_put(&set_data->kref, cmf_set_schib_release);
+out:
        spin_unlock_irq(cdev->ccwlock);
-       return s.ret;
+       return ret;
 }
 
 void retry_set_schib(struct ccw_device *cdev)
 {
-       struct set_schib_struct *s;
+       struct set_schib_struct *set_data;
+
+       set_data = cdev->private->cmb_wait;
+       if (!set_data) {
+               WARN_ON(1);
+               return;
+       }
+       kref_get(&set_data->kref);
+       set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc,
+                                 set_data->address);
+       wake_up(&set_data->wait);
+       kref_put(&set_data->kref, cmf_set_schib_release);
+}
+
+static int cmf_copy_block(struct ccw_device *cdev)
+{
+       struct subchannel *sch;
+       void *reference_buf;
+       void *hw_block;
+       struct cmb_data *cmb_data;
+
+       sch = to_subchannel(cdev->dev.parent);
+
+       if (stsch(sch->schid, &sch->schib))
+               return -ENODEV;
+
+       if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) {
+               /* Don't copy if a start function is in progress. */
+               if ((!sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED) &&
+                   (sch->schib.scsw.actl &
+                    (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
+                   (!sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))
+                       return -EBUSY;
+       }
+       cmb_data = cdev->private->cmb;
+       hw_block = cmbops->align(cmb_data->hw_block);
+       if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size))
+               /* No need to copy. */
+               return 0;
+       reference_buf = kzalloc(cmb_data->size, GFP_ATOMIC);
+       if (!reference_buf)
+               return -ENOMEM;
+       /* Ensure consistency of block copied from hardware. */
+       do {
+               memcpy(cmb_data->last_block, hw_block, cmb_data->size);
+               memcpy(reference_buf, hw_block, cmb_data->size);
+       } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size));
+       cmb_data->last_update = get_clock();
+       kfree(reference_buf);
+       return 0;
+}
+
+struct copy_block_struct {
+       wait_queue_head_t wait;
+       int ret;
+       struct kref kref;
+};
+
+static void cmf_copy_block_release(struct kref *kref)
+{
+       struct copy_block_struct *copy_block;
+
+       copy_block = container_of(kref, struct copy_block_struct, kref);
+       kfree(copy_block);
+}
+
+static int cmf_cmb_copy_wait(struct ccw_device *cdev)
+{
+       struct copy_block_struct *copy_block;
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               ret = -ENODEV;
+               goto out;
+       }
+       copy_block = kzalloc(sizeof(struct copy_block_struct), GFP_ATOMIC);
+       if (!copy_block) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       init_waitqueue_head(&copy_block->wait);
+       kref_init(&copy_block->kref);
+
+       ret = cmf_copy_block(cdev);
+       if (ret != -EBUSY)
+               goto out_put;
+
+       if (cdev->private->state != DEV_STATE_ONLINE) {
+               ret = -EBUSY;
+               goto out_put;
+       }
+
+       cdev->private->state = DEV_STATE_CMFUPDATE;
+       copy_block->ret = CMF_PENDING;
+       cdev->private->cmb_wait = copy_block;
+
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (wait_event_interruptible(copy_block->wait,
+                                    copy_block->ret != CMF_PENDING)) {
+               spin_lock_irqsave(cdev->ccwlock, flags);
+               if (copy_block->ret == CMF_PENDING) {
+                       copy_block->ret = -ERESTARTSYS;
+                       if (cdev->private->state == DEV_STATE_CMFUPDATE)
+                               cdev->private->state = DEV_STATE_ONLINE;
+               }
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
+       }
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       cdev->private->cmb_wait = NULL;
+       ret = copy_block->ret;
+out_put:
+       kref_put(&copy_block->kref, cmf_copy_block_release);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
+}
+
+void cmf_retry_copy_block(struct ccw_device *cdev)
+{
+       struct copy_block_struct *copy_block;
 
-       s = cdev->private->cmb_wait;
-       cdev->private->cmb_wait = 0;
-       if (!s) {
+       copy_block = cdev->private->cmb_wait;
+       if (!copy_block) {
                WARN_ON(1);
                return;
        }
-       s->ret = set_schib(cdev, s->mme, s->mbfc, s->address);
-       wake_up(&s->wait);
+       kref_get(&copy_block->kref);
+       copy_block->ret = cmf_copy_block(cdev);
+       wake_up(&copy_block->wait);
+       kref_put(&copy_block->kref, cmf_copy_block_release);
+}
+
+static void cmf_generic_reset(struct ccw_device *cdev)
+{
+       struct cmb_data *cmb_data;
+
+       spin_lock_irq(cdev->ccwlock);
+       cmb_data = cdev->private->cmb;
+       if (cmb_data) {
+               memset(cmb_data->last_block, 0, cmb_data->size);
+               /*
+                * Need to reset hw block as well to make the hardware start
+                * from 0 again.
+                */
+               memset(cmbops->align(cmb_data->hw_block), 0, cmb_data->size);
+               cmb_data->last_update = 0;
+       }
+       cdev->private->cmb_start_time = get_clock();
+       spin_unlock_irq(cdev->ccwlock);
 }
 
 /**
@@ -343,8 +519,8 @@ struct cmb {
 /* insert a single device into the cmb_area list
  * called with cmb_area.lock held from alloc_cmb
  */
-static inline int
-alloc_cmb_single (struct ccw_device *cdev)
+static inline int alloc_cmb_single (struct ccw_device *cdev,
+                                   struct cmb_data *cmb_data)
 {
        struct cmb *cmb;
        struct ccw_device_private *node;
@@ -358,10 +534,12 @@ alloc_cmb_single (struct ccw_device *cdev)
 
        /* find first unused cmb in cmb_area.mem.
         * this is a little tricky: cmb_area.list
-        * remains sorted by ->cmb pointers */
+        * remains sorted by ->cmb->hw_data pointers */
        cmb = cmb_area.mem;
        list_for_each_entry(node, &cmb_area.list, cmb_list) {
-               if ((struct cmb*)node->cmb > cmb)
+               struct cmb_data *data;
+               data = node->cmb;
+               if ((struct cmb*)data->hw_block > cmb)
                        break;
                cmb++;
        }
@@ -372,7 +550,8 @@ alloc_cmb_single (struct ccw_device *cdev)
 
        /* insert new cmb */
        list_add_tail(&cdev->private->cmb_list, &node->cmb_list);
-       cdev->private->cmb = cmb;
+       cmb_data->hw_block = cmb;
+       cdev->private->cmb = cmb_data;
        ret = 0;
 out:
        spin_unlock_irq(cdev->ccwlock);
@@ -385,7 +564,19 @@ alloc_cmb (struct ccw_device *cdev)
        int ret;
        struct cmb *mem;
        ssize_t size;
+       struct cmb_data *cmb_data;
+
+       /* Allocate private cmb_data. */
+       cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+       if (!cmb_data)
+               return -ENOMEM;
 
+       cmb_data->last_block = kzalloc(sizeof(struct cmb), GFP_KERNEL);
+       if (!cmb_data->last_block) {
+               kfree(cmb_data);
+               return -ENOMEM;
+       }
+       cmb_data->size = sizeof(struct cmb);
        spin_lock(&cmb_area.lock);
 
        if (!cmb_area.mem) {
@@ -414,29 +605,36 @@ alloc_cmb (struct ccw_device *cdev)
        }
 
        /* do the actual allocation */
-       ret = alloc_cmb_single(cdev);
+       ret = alloc_cmb_single(cdev, cmb_data);
 out:
        spin_unlock(&cmb_area.lock);
-
+       if (ret) {
+               kfree(cmb_data->last_block);
+               kfree(cmb_data);
+       }
        return ret;
 }
 
-static void
-free_cmb(struct ccw_device *cdev)
+static void free_cmb(struct ccw_device *cdev)
 {
        struct ccw_device_private *priv;
-
-       priv = cdev->private;
+       struct cmb_data *cmb_data;
 
        spin_lock(&cmb_area.lock);
        spin_lock_irq(cdev->ccwlock);
 
+       priv = cdev->private;
+
        if (list_empty(&priv->cmb_list)) {
                /* already freed */
                goto out;
        }
 
+       cmb_data = priv->cmb;
        priv->cmb = NULL;
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
        list_del_init(&priv->cmb_list);
 
        if (list_empty(&cmb_area.list)) {
@@ -451,83 +649,97 @@ out:
        spin_unlock(&cmb_area.lock);
 }
 
-static int
-set_cmb(struct ccw_device *cdev, u32 mme)
+static int set_cmb(struct ccw_device *cdev, u32 mme)
 {
        u16 offset;
+       struct cmb_data *cmb_data;
+       unsigned long flags;
 
-       if (!cdev->private->cmb)
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
                return -EINVAL;
-
-       offset = mme ? (struct cmb *)cdev->private->cmb - cmb_area.mem : 0;
+       }
+       cmb_data = cdev->private->cmb;
+       offset = mme ? (struct cmb *)cmb_data->hw_block - cmb_area.mem : 0;
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
 
        return set_schib_wait(cdev, mme, 0, offset);
 }
 
-static u64
-read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb (struct ccw_device *cdev, int index)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmb cmb;
-       unsigned long flags;
+       struct cmb *cmb;
        u32 val;
+       int ret;
+       unsigned long flags;
+
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return 0;
 
        spin_lock_irqsave(cdev->ccwlock, flags);
        if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return 0;
+               ret = 0;
+               goto out;
        }
-
-       cmb = *(struct cmb*)cdev->private->cmb;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       cmb = ((struct cmb_data *)cdev->private->cmb)->last_block;
 
        switch (index) {
        case cmb_ssch_rsch_count:
-               return cmb.ssch_rsch_count;
+               ret = cmb->ssch_rsch_count;
+               goto out;
        case cmb_sample_count:
-               return cmb.sample_count;
+               ret = cmb->sample_count;
+               goto out;
        case cmb_device_connect_time:
-               val = cmb.device_connect_time;
+               val = cmb->device_connect_time;
                break;
        case cmb_function_pending_time:
-               val = cmb.function_pending_time;
+               val = cmb->function_pending_time;
                break;
        case cmb_device_disconnect_time:
-               val = cmb.device_disconnect_time;
+               val = cmb->device_disconnect_time;
                break;
        case cmb_control_unit_queuing_time:
-               val = cmb.control_unit_queuing_time;
+               val = cmb->control_unit_queuing_time;
                break;
        case cmb_device_active_only_time:
-               val = cmb.device_active_only_time;
+               val = cmb->device_active_only_time;
                break;
        default:
-               return 0;
+               ret = 0;
+               goto out;
        }
-       return time_to_avg_nsec(val, cmb.sample_count);
+       ret = time_to_avg_nsec(val, cmb->sample_count);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static int
-readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmb cmb;
-       unsigned long flags;
+       struct cmb *cmb;
+       struct cmb_data *cmb_data;
        u64 time;
+       unsigned long flags;
+       int ret;
 
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return ret;
        spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return -ENODEV;
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = -ENODEV;
+               goto out;
        }
-
-       cmb = *(struct cmb*)cdev->private->cmb;
-       time = get_clock() - cdev->private->cmb_start_time;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (cmb_data->last_update == 0) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       cmb = cmb_data->last_block;
+       time = cmb_data->last_update - cdev->private->cmb_start_time;
 
        memset(data, 0, sizeof(struct cmbdata));
 
@@ -538,31 +750,32 @@ readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
        data->elapsed_time = (time * 1000) >> 12;
 
        /* copy data to new structure */
-       data->ssch_rsch_count = cmb.ssch_rsch_count;
-       data->sample_count = cmb.sample_count;
+       data->ssch_rsch_count = cmb->ssch_rsch_count;
+       data->sample_count = cmb->sample_count;
 
        /* time fields are converted to nanoseconds while copying */
-       data->device_connect_time = time_to_nsec(cmb.device_connect_time);
-       data->function_pending_time = time_to_nsec(cmb.function_pending_time);
-       data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time);
+       data->device_connect_time = time_to_nsec(cmb->device_connect_time);
+       data->function_pending_time = time_to_nsec(cmb->function_pending_time);
+       data->device_disconnect_time =
+               time_to_nsec(cmb->device_disconnect_time);
        data->control_unit_queuing_time
-               = time_to_nsec(cmb.control_unit_queuing_time);
+               = time_to_nsec(cmb->control_unit_queuing_time);
        data->device_active_only_time
-               = time_to_nsec(cmb.device_active_only_time);
+               = time_to_nsec(cmb->device_active_only_time);
+       ret = 0;
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
+}
 
-       return 0;
+static void reset_cmb(struct ccw_device *cdev)
+{
+       cmf_generic_reset(cdev);
 }
 
-static void
-reset_cmb(struct ccw_device *cdev)
+static void * align_cmb(void *area)
 {
-       struct cmb *cmb;
-       spin_lock_irq(cdev->ccwlock);
-       cmb = cdev->private->cmb;
-       if (cmb)
-               memset (cmb, 0, sizeof (*cmb));
-       cdev->private->cmb_start_time = get_clock();
-       spin_unlock_irq(cdev->ccwlock);
+       return area;
 }
 
 static struct attribute_group cmf_attr_group;
@@ -574,6 +787,7 @@ static struct cmb_operations cmbops_basic = {
        .read   = read_cmb,
        .readall    = readall_cmb,
        .reset      = reset_cmb,
+       .align      = align_cmb,
        .attr_group = &cmf_attr_group,
 };
 \f
@@ -610,22 +824,34 @@ static inline struct cmbe* cmbe_align(struct cmbe *c)
        return (struct cmbe*)addr;
 }
 
-static int
-alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe (struct ccw_device *cdev)
 {
        struct cmbe *cmbe;
-       cmbe = kmalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
+       struct cmb_data *cmb_data;
+       int ret;
+
+       cmbe = kzalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
        if (!cmbe)
                return -ENOMEM;
-
+       cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+       if (!cmb_data) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       cmb_data->last_block = kzalloc(sizeof(struct cmbe), GFP_KERNEL);
+       if (!cmb_data->last_block) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       cmb_data->size = sizeof(struct cmbe);
        spin_lock_irq(cdev->ccwlock);
        if (cdev->private->cmb) {
-               kfree(cmbe);
                spin_unlock_irq(cdev->ccwlock);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_free;
        }
-
-       cdev->private->cmb = cmbe;
+       cmb_data->hw_block = cmbe;
+       cdev->private->cmb = cmb_data;
        spin_unlock_irq(cdev->ccwlock);
 
        /* activate global measurement if this is the first channel */
@@ -636,14 +862,24 @@ alloc_cmbe (struct ccw_device *cdev)
        spin_unlock(&cmb_area.lock);
 
        return 0;
+out_free:
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
+       kfree(cmbe);
+       return ret;
 }
 
-static void
-free_cmbe (struct ccw_device *cdev)
+static void free_cmbe (struct ccw_device *cdev)
 {
+       struct cmb_data *cmb_data;
+
        spin_lock_irq(cdev->ccwlock);
-       kfree(cdev->private->cmb);
+       cmb_data = cdev->private->cmb;
        cdev->private->cmb = NULL;
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
        spin_unlock_irq(cdev->ccwlock);
 
        /* deactivate global measurement if this is the last channel */
@@ -654,89 +890,105 @@ free_cmbe (struct ccw_device *cdev)
        spin_unlock(&cmb_area.lock);
 }
 
-static int
-set_cmbe(struct ccw_device *cdev, u32 mme)
+static int set_cmbe(struct ccw_device *cdev, u32 mme)
 {
        unsigned long mba;
+       struct cmb_data *cmb_data;
+       unsigned long flags;
 
-       if (!cdev->private->cmb)
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
                return -EINVAL;
-       mba = mme ? (unsigned long) cmbe_align(cdev->private->cmb) : 0;
+       }
+       cmb_data = cdev->private->cmb;
+       mba = mme ? (unsigned long) cmbe_align(cmb_data->hw_block) : 0;
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
 
        return set_schib_wait(cdev, mme, 1, mba);
 }
 
 
-u64
-read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe (struct ccw_device *cdev, int index)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmbe cmb;
-       unsigned long flags;
+       struct cmbe *cmb;
+       struct cmb_data *cmb_data;
        u32 val;
+       int ret;
+       unsigned long flags;
 
-       spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
                return 0;
-       }
 
-       cmb = *cmbe_align(cdev->private->cmb);
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = 0;
+               goto out;
+       }
+       cmb = cmb_data->last_block;
 
        switch (index) {
        case cmb_ssch_rsch_count:
-               return cmb.ssch_rsch_count;
+               ret = cmb->ssch_rsch_count;
+               goto out;
        case cmb_sample_count:
-               return cmb.sample_count;
+               ret = cmb->sample_count;
+               goto out;
        case cmb_device_connect_time:
-               val = cmb.device_connect_time;
+               val = cmb->device_connect_time;
                break;
        case cmb_function_pending_time:
-               val = cmb.function_pending_time;
+               val = cmb->function_pending_time;
                break;
        case cmb_device_disconnect_time:
-               val = cmb.device_disconnect_time;
+               val = cmb->device_disconnect_time;
                break;
        case cmb_control_unit_queuing_time:
-               val = cmb.control_unit_queuing_time;
+               val = cmb->control_unit_queuing_time;
                break;
        case cmb_device_active_only_time:
-               val = cmb.device_active_only_time;
+               val = cmb->device_active_only_time;
                break;
        case cmb_device_busy_time:
-               val = cmb.device_busy_time;
+               val = cmb->device_busy_time;
                break;
        case cmb_initial_command_response_time:
-               val = cmb.initial_command_response_time;
+               val = cmb->initial_command_response_time;
                break;
        default:
-               return 0;
+               ret = 0;
+               goto out;
        }
-       return time_to_avg_nsec(val, cmb.sample_count);
+       ret = time_to_avg_nsec(val, cmb->sample_count);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static int
-readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmbe cmb;
-       unsigned long flags;
+       struct cmbe *cmb;
+       struct cmb_data *cmb_data;
        u64 time;
+       unsigned long flags;
+       int ret;
 
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return ret;
        spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return -ENODEV;
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = -ENODEV;
+               goto out;
        }
-
-       cmb = *cmbe_align(cdev->private->cmb);
-       time = get_clock() - cdev->private->cmb_start_time;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (cmb_data->last_update == 0) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       time = cmb_data->last_update - cdev->private->cmb_start_time;
 
        memset (data, 0, sizeof(struct cmbdata));
 
@@ -746,35 +998,38 @@ readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
        /* conver to nanoseconds */
        data->elapsed_time = (time * 1000) >> 12;
 
+       cmb = cmb_data->last_block;
        /* copy data to new structure */
-       data->ssch_rsch_count = cmb.ssch_rsch_count;
-       data->sample_count = cmb.sample_count;
+       data->ssch_rsch_count = cmb->ssch_rsch_count;
+       data->sample_count = cmb->sample_count;
 
        /* time fields are converted to nanoseconds while copying */
-       data->device_connect_time = time_to_nsec(cmb.device_connect_time);
-       data->function_pending_time = time_to_nsec(cmb.function_pending_time);
-       data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time);
+       data->device_connect_time = time_to_nsec(cmb->device_connect_time);
+       data->function_pending_time = time_to_nsec(cmb->function_pending_time);
+       data->device_disconnect_time =
+               time_to_nsec(cmb->device_disconnect_time);
        data->control_unit_queuing_time
-               = time_to_nsec(cmb.control_unit_queuing_time);
+               = time_to_nsec(cmb->control_unit_queuing_time);
        data->device_active_only_time
-               = time_to_nsec(cmb.device_active_only_time);
-       data->device_busy_time = time_to_nsec(cmb.device_busy_time);
+               = time_to_nsec(cmb->device_active_only_time);
+       data->device_busy_time = time_to_nsec(cmb->device_busy_time);
        data->initial_command_response_time
-               = time_to_nsec(cmb.initial_command_response_time);
+               = time_to_nsec(cmb->initial_command_response_time);
 
-       return 0;
+       ret = 0;
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static void
-reset_cmbe(struct ccw_device *cdev)
+static void reset_cmbe(struct ccw_device *cdev)
 {
-       struct cmbe *cmb;
-       spin_lock_irq(cdev->ccwlock);
-       cmb = cmbe_align(cdev->private->cmb);
-       if (cmb)
-               memset (cmb, 0, sizeof (*cmb));
-       cdev->private->cmb_start_time = get_clock();
-       spin_unlock_irq(cdev->ccwlock);
+       cmf_generic_reset(cdev);
+}
+
+static void * align_cmbe(void *area)
+{
+       return cmbe_align(area);
 }
 
 static struct attribute_group cmf_attr_group_ext;
@@ -786,6 +1041,7 @@ static struct cmb_operations cmbops_extended = {
        .read       = read_cmbe,
        .readall    = readall_cmbe,
        .reset      = reset_cmbe,
+       .align      = align_cmbe,
        .attr_group = &cmf_attr_group_ext,
 };
 \f
@@ -803,14 +1059,19 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
        struct ccw_device *cdev;
        long interval;
        unsigned long count;
+       struct cmb_data *cmb_data;
 
        cdev = to_ccwdev(dev);
-       interval  = get_clock() - cdev->private->cmb_start_time;
        count = cmf_read(cdev, cmb_sample_count);
-       if (count)
+       spin_lock_irq(cdev->ccwlock);
+       cmb_data = cdev->private->cmb;
+       if (count) {
+               interval = cmb_data->last_update -
+                       cdev->private->cmb_start_time;
                interval /= count;
-       else
+       else
                interval = -1;
+       spin_unlock_irq(cdev->ccwlock);
        return sprintf(buf, "%ld\n", interval);
 }
 
@@ -823,7 +1084,10 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char
        int ret;
 
        ret = cmf_readall(to_ccwdev(dev), &data);
-       if (ret)
+       if (ret == -EAGAIN || ret == -ENODEV)
+               /* No data (yet/currently) available to use for calculation. */
+               return sprintf(buf, "n/a\n");
+       else if (ret)
                return ret;
 
        utilization = data.device_connect_time +
@@ -982,6 +1246,13 @@ cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
        return cmbops->readall(cdev, data);
 }
 
+/* Reenable cmf when a disconnected device becomes available again. */
+int cmf_reenable(struct ccw_device *cdev)
+{
+       cmbops->reset(cdev);
+       return cmbops->set(cdev, 2);
+}
+
 static int __init
 init_cmf(void)
 {
index 74ea8aac4b7d9683c37ce79e79a41edf673b9d07..1d3be80797f81e1ed119a08394f872cc20700236 100644 (file)
 #include "cio_debug.h"
 #include "ioasm.h"
 #include "chsc.h"
+#include "device.h"
 
 int need_rescan = 0;
 int css_init_done = 0;
+static int need_reprobe = 0;
 static int max_ssid = 0;
 
 struct channel_subsystem *css[__MAX_CSSID + 1];
@@ -339,6 +341,67 @@ typedef void (*workfunc)(void *);
 DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL);
 struct workqueue_struct *slow_path_wq;
 
+/* Reprobe subchannel if unregistered. */
+static int reprobe_subchannel(struct subchannel_id schid, void *data)
+{
+       struct subchannel *sch;
+       int ret;
+
+       CIO_DEBUG(KERN_INFO, 6, "cio: reprobe 0.%x.%04x\n",
+                 schid.ssid, schid.sch_no);
+       if (need_reprobe)
+               return -EAGAIN;
+
+       sch = get_subchannel_by_schid(schid);
+       if (sch) {
+               /* Already known. */
+               put_device(&sch->dev);
+               return 0;
+       }
+
+       ret = css_probe_device(schid);
+       switch (ret) {
+       case 0:
+               break;
+       case -ENXIO:
+       case -ENOMEM:
+               /* These should abort looping */
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
+/* Work function used to reprobe all unregistered subchannels. */
+static void reprobe_all(void *data)
+{
+       int ret;
+
+       CIO_MSG_EVENT(2, "reprobe start\n");
+
+       need_reprobe = 0;
+       /* Make sure initial subchannel scan is done. */
+       wait_event(ccw_device_init_wq,
+                  atomic_read(&ccw_device_init_count) == 0);
+       ret = for_each_subchannel(reprobe_subchannel, NULL);
+
+       CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
+                     need_reprobe);
+}
+
+DECLARE_WORK(css_reprobe_work, reprobe_all, NULL);
+
+/* Schedule reprobing of all unregistered subchannels. */
+void css_schedule_reprobe(void)
+{
+       need_reprobe = 1;
+       queue_work(ccw_device_work, &css_reprobe_work);
+}
+
+EXPORT_SYMBOL_GPL(css_schedule_reprobe);
+
 /*
  * Rescan for new devices. FIXME: This is slow.
  * This function is called when we have lost CRWs due to overflows and we have
index 8e3053c2a451b4f5dc84d5b7fb77df52119d124c..eafde43e8410cd3e1f041343f86dad2bd543d8c6 100644 (file)
@@ -133,8 +133,8 @@ struct css_driver io_subchannel_driver = {
 
 struct workqueue_struct *ccw_device_work;
 struct workqueue_struct *ccw_device_notify_work;
-static wait_queue_head_t ccw_device_init_wq;
-static atomic_t ccw_device_init_count;
+wait_queue_head_t ccw_device_init_wq;
+atomic_t ccw_device_init_count;
 
 static int __init
 init_ccw_bus_type (void)
index 11587ebb72897dcd68d04dc8d26df767e01af52f..00be9a5b4acde18141a76d7aef38ad4b90b2347c 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef S390_DEVICE_H
 #define S390_DEVICE_H
 
+#include <asm/ccwdev.h>
+#include <asm/atomic.h>
+#include <linux/wait.h>
+
 /*
  * states of the device statemachine
  */
@@ -23,6 +27,7 @@ enum dev_state {
        DEV_STATE_DISCONNECTED,
        DEV_STATE_DISCONNECTED_SENSE_ID,
        DEV_STATE_CMFCHANGE,
+       DEV_STATE_CMFUPDATE,
        /* last element! */
        NR_DEV_STATES
 };
@@ -67,6 +72,8 @@ dev_fsm_final_state(struct ccw_device *cdev)
 
 extern struct workqueue_struct *ccw_device_work;
 extern struct workqueue_struct *ccw_device_notify_work;
+extern wait_queue_head_t ccw_device_init_wq;
+extern atomic_t ccw_device_init_count;
 
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
@@ -112,5 +119,8 @@ int ccw_device_stlck(struct ccw_device *);
 void ccw_device_set_timeout(struct ccw_device *, int);
 extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
 
+/* Channel measurement facility related */
 void retry_set_schib(struct ccw_device *cdev);
+void cmf_retry_copy_block(struct ccw_device *);
+int cmf_reenable(struct ccw_device *);
 #endif
index 49ec562d7f60b7d9d5d3c7658851394c11020d8d..7d0dd72635ebde671ce882d13cab17ad6094019f 100644 (file)
@@ -336,8 +336,11 @@ ccw_device_oper_notify(void *data)
        if (!ret)
                /* Driver doesn't want device back. */
                ccw_device_do_unreg_rereg((void *)cdev);
-       else
+       else {
+               /* Reenable channel measurements, if needed. */
+               cmf_reenable(cdev);
                wake_up(&cdev->private->wait_q);
+       }
 }
 
 /*
@@ -861,6 +864,8 @@ ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event)
        irb = (struct irb *) __LC_IRB;
        /* Accumulate status. We don't do basic sense. */
        ccw_device_accumulate_irb(cdev, irb);
+       /* Remember to clear irb to avoid residuals. */
+       memset(&cdev->private->irb, 0, sizeof(struct irb));
        /* Try to start delayed device verification. */
        ccw_device_online_verify(cdev, 0);
        /* Note: Don't call handler for cio initiated clear! */
@@ -1093,6 +1098,13 @@ ccw_device_change_cmfstate(struct ccw_device *cdev, enum dev_event dev_event)
        dev_fsm_event(cdev, dev_event);
 }
 
+static void ccw_device_update_cmfblock(struct ccw_device *cdev,
+                                      enum dev_event dev_event)
+{
+       cmf_retry_copy_block(cdev);
+       cdev->private->state = DEV_STATE_ONLINE;
+       dev_fsm_event(cdev, dev_event);
+}
 
 static void
 ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
@@ -1247,6 +1259,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_TIMEOUT]     = ccw_device_change_cmfstate,
                [DEV_EVENT_VERIFY]      = ccw_device_change_cmfstate,
        },
+       [DEV_STATE_CMFUPDATE] = {
+               [DEV_EVENT_NOTOPER]     = ccw_device_update_cmfblock,
+               [DEV_EVENT_INTERRUPT]   = ccw_device_update_cmfblock,
+               [DEV_EVENT_TIMEOUT]     = ccw_device_update_cmfblock,
+               [DEV_EVENT_VERIFY]      = ccw_device_update_cmfblock,
+       },
 };
 
 /*
index 795abb5a65ba122620517ff44b7164deceec0a50..b266ad8e14ff2623fc6e5cea70e04d9a4160435b 100644 (file)
@@ -78,7 +78,8 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
                return -ENODEV;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
-       if (cdev->private->state == DEV_STATE_VERIFY) {
+       if (cdev->private->state == DEV_STATE_VERIFY ||
+           cdev->private->state == DEV_STATE_CLEAR_VERIFY) {
                /* Remember to fake irb when finished. */
                if (!cdev->private->flags.fake_irb) {
                        cdev->private->flags.fake_irb = 1;
@@ -270,7 +271,8 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
                 * We didn't get channel end / device end. Check if path
                 * verification has been started; we can retry after it has
                 * finished. We also retry unit checks except for command reject
-                * or intervention required.
+                * or intervention required. Also check for long busy
+                * conditions.
                 */
                 if (cdev->private->flags.doverify ||
                         cdev->private->state == DEV_STATE_VERIFY)
@@ -279,6 +281,10 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
                     !(irb->ecw[0] &
                       (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
                         cdev->private->intparm = -EAGAIN;
+               else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
+                        (irb->scsw.dstat & DEV_STAT_DEV_END) &&
+                        (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
+                       cdev->private->intparm = -EAGAIN;
                 else
                         cdev->private->intparm = -EIO;
                         
index f99e55308b32df8625658de3f63c1fddf5010236..8dc75002acbea71b1788ed35d314b42dc0e70207 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/workqueue.h>
 #include <linux/time.h>
+#include <linux/kthread.h>
 
 #include <asm/lowcore.h>
 
@@ -56,8 +57,6 @@ s390_collect_crw_info(void *param)
        unsigned int chain;
 
        sem = (struct semaphore *)param;
-       /* Set a nice name. */
-       daemonize("kmcheck");
 repeat:
        down_interruptible(sem);
        slow = 0;
@@ -516,7 +515,7 @@ arch_initcall(machine_check_init);
 static int __init
 machine_check_crw_init (void)
 {
-       kernel_thread(s390_collect_crw_info, &m_sem, CLONE_FS|CLONE_FILES);
+       kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
        ctl_set_bit(14, 28);    /* enable channel report MCH */
        return 0;
 }
index c84b02aec1f35fd819428ba91956900959264884..96a81cd17617aaa95fe7bad50875488182f65081 100644 (file)
@@ -501,7 +501,7 @@ config SCSI_ATA_PIIX
        tristate "Intel PIIX/ICH SATA support"
        depends on SCSI_SATA && PCI
        help
-         This option enables support for ICH5 Serial ATA.
+         This option enables support for ICH5/6/7/8 Serial ATA.
          If PATA support was enabled previously, this enables
          support for select Intel PIIX/ICH PATA host controllers.
 
index 4bb77f62b3b9bef9c6660b990c4ee838213fb3ae..f059467777183f0463d604eefb3860c3884a3d36 100644 (file)
@@ -48,7 +48,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "ahci"
-#define DRV_VERSION    "1.3"
+#define DRV_VERSION    "2.0"
 
 
 enum {
index 521b718763f6c9ab0f324f5f07294048836d495f..94b1261a259d934d5a5506e22f215fa3af0854e0 100644 (file)
@@ -93,7 +93,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "ata_piix"
-#define DRV_VERSION    "1.10"
+#define DRV_VERSION    "2.00"
 
 enum {
        PIIX_IOCFG              = 0x54, /* IDE I/O configuration register */
index 6c66877be2bffe069b7663fc756fb176ed092003..d1c1c30d123f36946d74cbd873ddad63d1902ae4 100644 (file)
@@ -88,6 +88,10 @@ int libata_fua = 0;
 module_param_named(fua, libata_fua, int, 0444);
 MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
 
+static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
+module_param(ata_probe_timeout, int, 0444);
+MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
@@ -777,11 +781,9 @@ void ata_std_dev_select (struct ata_port *ap, unsigned int device)
 void ata_dev_select(struct ata_port *ap, unsigned int device,
                           unsigned int wait, unsigned int can_sleep)
 {
-       if (ata_msg_probe(ap)) {
+       if (ata_msg_probe(ap))
                ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
-                               "device %u, wait %u\n",
-                               ap->id, device, wait);
-       }
+                               "device %u, wait %u\n", ap->id, device, wait);
 
        if (wait)
                ata_wait_idle(ap);
@@ -950,7 +952,8 @@ void ata_port_flush_task(struct ata_port *ap)
         */
        if (!cancel_delayed_work(&ap->port_task)) {
                if (ata_msg_ctl(ap))
-                       ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", __FUNCTION__);
+                       ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
+                                       __FUNCTION__);
                flush_workqueue(ata_wq);
        }
 
@@ -1059,7 +1062,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
 
        spin_unlock_irqrestore(ap->lock, flags);
 
-       rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL);
+       rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
 
        ata_port_flush_task(ap);
 
@@ -1081,7 +1084,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
 
                        if (ata_msg_warn(ap))
                                ata_dev_printk(dev, KERN_WARNING,
-                                      "qc timeout (cmd 0x%x)\n", command);
+                                       "qc timeout (cmd 0x%x)\n", command);
                }
 
                spin_unlock_irqrestore(ap->lock, flags);
@@ -1093,9 +1096,9 @@ unsigned ata_exec_internal(struct ata_device *dev,
 
        if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
                if (ata_msg_warn(ap))
-                       ata_dev_printk(dev, KERN_WARNING, 
+                       ata_dev_printk(dev, KERN_WARNING,
                                "zero err_mask for failed "
-                              "internal command, assuming AC_ERR_OTHER\n");
+                               "internal command, assuming AC_ERR_OTHER\n");
                qc->err_mask |= AC_ERR_OTHER;
        }
 
@@ -1131,6 +1134,33 @@ unsigned ata_exec_internal(struct ata_device *dev,
        return err_mask;
 }
 
+/**
+ *     ata_do_simple_cmd - execute simple internal command
+ *     @dev: Device to which the command is sent
+ *     @cmd: Opcode to execute
+ *
+ *     Execute a 'simple' command, that only consists of the opcode
+ *     'cmd' itself, without filling any other registers
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     Zero on success, AC_ERR_* mask on failure
+ */
+unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+{
+       struct ata_taskfile tf;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = cmd;
+       tf.flags |= ATA_TFLAG_DEVICE;
+       tf.protocol = ATA_PROT_NODATA;
+
+       return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+}
+
 /**
  *     ata_pio_need_iordy      -       check if iordy needed
  *     @adev: ATA device
@@ -1193,8 +1223,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
        int rc;
 
        if (ata_msg_ctl(ap))
-               ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", 
-                               __FUNCTION__, ap->id, dev->devno);
+               ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+                              __FUNCTION__, ap->id, dev->devno);
 
        ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
 
@@ -1263,9 +1293,9 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
        return 0;
 
  err_out:
-       if (ata_msg_warn(ap)) 
+       if (ata_msg_warn(ap))
                ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
-                      "(%s, err_mask=0x%x)\n", reason, err_mask);
+                              "(%s, err_mask=0x%x)\n", reason, err_mask);
        return rc;
 }
 
@@ -1318,19 +1348,21 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
        int i, rc;
 
        if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
-               ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
-                       __FUNCTION__, ap->id, dev->devno);
+               ata_dev_printk(dev, KERN_INFO,
+                              "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
+                              __FUNCTION__, ap->id, dev->devno);
                return 0;
        }
 
        if (ata_msg_probe(ap))
-               ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", 
-                       __FUNCTION__, ap->id, dev->devno);
+               ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+                              __FUNCTION__, ap->id, dev->devno);
 
        /* print device capabilities */
        if (ata_msg_probe(ap))
-               ata_dev_printk(dev, KERN_DEBUG, "%s: cfg 49:%04x 82:%04x 83:%04x "
-                              "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+               ata_dev_printk(dev, KERN_DEBUG,
+                              "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x "
+                              "85:%04x 86:%04x 87:%04x 88:%04x\n",
                               __FUNCTION__,
                               id[49], id[82], id[83], id[84],
                               id[85], id[86], id[87], id[88]);
@@ -1402,14 +1434,16 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                                        ata_id_major_version(id),
                                        ata_mode_string(xfer_mask),
                                        (unsigned long long)dev->n_sectors,
-                                       dev->cylinders, dev->heads, dev->sectors);
+                                       dev->cylinders, dev->heads,
+                                       dev->sectors);
                }
 
                if (dev->id[59] & 0x100) {
                        dev->multi_count = dev->id[59] & 0xff;
                        if (ata_msg_info(ap))
-                               ata_dev_printk(dev, KERN_INFO, "ata%u: dev %u multi count %u\n",
-                               ap->id, dev->devno, dev->multi_count);
+                               ata_dev_printk(dev, KERN_INFO,
+                                       "ata%u: dev %u multi count %u\n",
+                                       ap->id, dev->devno, dev->multi_count);
                }
 
                dev->cdb_len = 16;
@@ -1422,8 +1456,8 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                rc = atapi_cdb_len(id);
                if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
                        if (ata_msg_warn(ap))
-                               ata_dev_printk(dev, KERN_WARNING, 
-                                       "unsupported CDB len\n");
+                               ata_dev_printk(dev, KERN_WARNING,
+                                              "unsupported CDB len\n");
                        rc = -EINVAL;
                        goto err_out_nosup;
                }
@@ -1466,8 +1500,8 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
 
 err_out_nosup:
        if (ata_msg_probe(ap))
-               ata_dev_printk(dev, KERN_DEBUG, 
-                               "%s: EXIT, err\n", __FUNCTION__);
+               ata_dev_printk(dev, KERN_DEBUG,
+                              "%s: EXIT, err\n", __FUNCTION__);
        return rc;
 }
 
@@ -3527,7 +3561,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
  *     Inherited from caller.
  */
 
-void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, 
+void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
                        unsigned int buflen, int write_data)
 {
        struct ata_port *ap = adev->ap;
@@ -3573,7 +3607,7 @@ void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
  *     Inherited from caller.
  */
 
-void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, 
+void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
                       unsigned int buflen, int write_data)
 {
        struct ata_port *ap = adev->ap;
@@ -3607,7 +3641,7 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
  *     @buflen: buffer length
  *     @write_data: read/write
  *
- *     Transfer data from/to the device data register by PIO. Do the 
+ *     Transfer data from/to the device data register by PIO. Do the
  *     transfer with interrupts disabled.
  *
  *     LOCKING:
@@ -4946,31 +4980,9 @@ int ata_port_offline(struct ata_port *ap)
        return 0;
 }
 
-/*
- * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
- * without filling any other registers
- */
-static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
-{
-       struct ata_taskfile tf;
-       int err;
-
-       ata_tf_init(dev, &tf);
-
-       tf.command = cmd;
-       tf.flags |= ATA_TFLAG_DEVICE;
-       tf.protocol = ATA_PROT_NODATA;
-
-       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-       if (err)
-               ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
-                              __FUNCTION__, err);
-
-       return err;
-}
-
-static int ata_flush_cache(struct ata_device *dev)
+int ata_flush_cache(struct ata_device *dev)
 {
+       unsigned int err_mask;
        u8 cmd;
 
        if (!ata_try_flush_cache(dev))
@@ -4981,17 +4993,41 @@ static int ata_flush_cache(struct ata_device *dev)
        else
                cmd = ATA_CMD_FLUSH;
 
-       return ata_do_simple_cmd(dev, cmd);
+       err_mask = ata_do_simple_cmd(dev, cmd);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
+               return -EIO;
+       }
+
+       return 0;
 }
 
 static int ata_standby_drive(struct ata_device *dev)
 {
-       return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+       unsigned int err_mask;
+
+       err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
+                              "(err_mask=0x%x)\n", err_mask);
+               return -EIO;
+       }
+
+       return 0;
 }
 
 static int ata_start_drive(struct ata_device *dev)
 {
-       return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
+       unsigned int err_mask;
+
+       err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_ERR, "failed to start drive "
+                              "(err_mask=0x%x)\n", err_mask);
+               return -EIO;
+       }
+
+       return 0;
 }
 
 /**
@@ -5212,7 +5248,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
        ap->msg_enable = 0x00FF;
 #elif defined(ATA_DEBUG)
        ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
-#else 
+#else
        ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
 #endif
 
@@ -5709,6 +5745,7 @@ int ata_pci_device_resume(struct pci_dev *pdev)
 
 static int __init ata_init(void)
 {
+       ata_probe_timeout *= HZ;
        ata_wq = create_workqueue("ata");
        if (!ata_wq)
                return -ENOMEM;
@@ -5733,7 +5770,7 @@ module_init(ata_init);
 module_exit(ata_exit);
 
 static unsigned long ratelimit_time;
-static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ata_ratelimit_lock);
 
 int ata_ratelimit(void)
 {
index 823385981a7a59f85ef69fb4c2799029182e791d..bf5a72aca8a4979957ae9a7ce8ff519d70490655 100644 (file)
@@ -93,6 +93,38 @@ static int ata_ering_map(struct ata_ering *ering,
        return rc;
 }
 
+static unsigned int ata_eh_dev_action(struct ata_device *dev)
+{
+       struct ata_eh_context *ehc = &dev->ap->eh_context;
+
+       return ehc->i.action | ehc->i.dev_action[dev->devno];
+}
+
+static void ata_eh_clear_action(struct ata_device *dev,
+                               struct ata_eh_info *ehi, unsigned int action)
+{
+       int i;
+
+       if (!dev) {
+               ehi->action &= ~action;
+               for (i = 0; i < ATA_MAX_DEVICES; i++)
+                       ehi->dev_action[i] &= ~action;
+       } else {
+               /* doesn't make sense for port-wide EH actions */
+               WARN_ON(!(action & ATA_EH_PERDEV_MASK));
+
+               /* break ehi->action into ehi->dev_action */
+               if (ehi->action & action) {
+                       for (i = 0; i < ATA_MAX_DEVICES; i++)
+                               ehi->dev_action[i] |= ehi->action & action;
+                       ehi->action &= ~action;
+               }
+
+               /* turn off the specified per-dev action */
+               ehi->dev_action[dev->devno] &= ~action;
+       }
+}
+
 /**
  *     ata_scsi_timed_out - SCSI layer time out callback
  *     @cmd: timed out SCSI command
@@ -702,32 +734,11 @@ static void ata_eh_detach_dev(struct ata_device *dev)
                ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
        }
 
-       spin_unlock_irqrestore(ap->lock, flags);
-}
-
-static void ata_eh_clear_action(struct ata_device *dev,
-                               struct ata_eh_info *ehi, unsigned int action)
-{
-       int i;
+       /* clear per-dev EH actions */
+       ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
+       ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
 
-       if (!dev) {
-               ehi->action &= ~action;
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       ehi->dev_action[i] &= ~action;
-       } else {
-               /* doesn't make sense for port-wide EH actions */
-               WARN_ON(!(action & ATA_EH_PERDEV_MASK));
-
-               /* break ehi->action into ehi->dev_action */
-               if (ehi->action & action) {
-                       for (i = 0; i < ATA_MAX_DEVICES; i++)
-                               ehi->dev_action[i] |= ehi->action & action;
-                       ehi->action &= ~action;
-               }
-
-               /* turn off the specified per-dev action */
-               ehi->dev_action[dev->devno] &= ~action;
-       }
+       spin_unlock_irqrestore(ap->lock, flags);
 }
 
 /**
@@ -1592,7 +1603,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                unsigned int action;
 
                dev = &ap->device[i];
-               action = ehc->i.action | ehc->i.dev_action[dev->devno];
+               action = ata_eh_dev_action(dev);
 
                if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
                        if (ata_port_offline(ap)) {
index 93d18a74c401c37fe194422377736718c8bb02b1..2915bca691e8e941bd3813ab63b7de41532ef564 100644 (file)
@@ -222,9 +222,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
         && copy_to_user(arg + sizeof(args), argbuf, argsize))
                rc = -EFAULT;
 error:
-       if (argbuf)
-               kfree(argbuf);
-
+       kfree(argbuf);
        return rc;
 }
 
index bdd48889709678da69f8c4f7503c8c464ef3039b..c325679d9b545dc666496b941f91128d39a38546 100644 (file)
@@ -29,7 +29,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME       "libata"
-#define DRV_VERSION    "1.30"  /* must be exactly four chars */
+#define DRV_VERSION    "2.00"  /* must be exactly four chars */
 
 struct ata_scsi_args {
        struct ata_device       *dev;
@@ -50,6 +50,7 @@ extern void ata_port_flush_task(struct ata_port *ap);
 extern unsigned ata_exec_internal(struct ata_device *dev,
                                  struct ata_taskfile *tf, const u8 *cdb,
                                  int dma_dir, void *buf, unsigned int buflen);
+extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
 extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                           int post_reset, u16 *id);
 extern int ata_dev_configure(struct ata_device *dev, int print_info);
@@ -64,6 +65,7 @@ extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
 extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+extern int ata_flush_cache(struct ata_device *dev);
 extern void ata_dev_init(struct ata_device *dev);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
index d18e7e0932effc420c3fd0a21483dd1044bc4fdc..5cc42c6054eb66ebd8dbc67052b3e86ca4f2032a 100644 (file)
@@ -44,7 +44,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME                       "sata_nv"
-#define DRV_VERSION                    "0.9"
+#define DRV_VERSION                    "2.0"
 
 enum {
        NV_PORTS                        = 2,
index bc9f918a7f286e2e07690cc5e64ec3376fd58aa3..51d86d750e84f6892b05c98beaa9ac7f82e09fcb 100644 (file)
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_sil"
-#define DRV_VERSION    "1.0"
+#define DRV_VERSION    "2.0"
 
 enum {
        /*
         * host flags
         */
+       SIL_FLAG_NO_SATA_IRQ    = (1 << 28),
        SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
        SIL_FLAG_MOD15WRITE     = (1 << 30),
 
@@ -62,8 +63,9 @@ enum {
         * Controller IDs
         */
        sil_3112                = 0,
-       sil_3512                = 1,
-       sil_3114                = 2,
+       sil_3112_no_sata_irq    = 1,
+       sil_3512                = 2,
+       sil_3114                = 3,
 
        /*
         * Register offsets
@@ -123,8 +125,8 @@ static const struct pci_device_id sil_pci_tbl[] = {
        { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
        { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
        { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
        { }     /* terminate list */
 };
 
@@ -217,6 +219,16 @@ static const struct ata_port_info sil_port_info[] = {
                .udma_mask      = 0x3f,                 /* udma0-5 */
                .port_ops       = &sil_ops,
        },
+       /* sil_3112_no_sata_irq */
+       {
+               .sht            = &sil_sht,
+               .host_flags     = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE |
+                                 SIL_FLAG_NO_SATA_IRQ,
+               .pio_mask       = 0x1f,                 /* pio0-4 */
+               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .udma_mask      = 0x3f,                 /* udma0-5 */
+               .port_ops       = &sil_ops,
+       },
        /* sil_3512 */
        {
                .sht            = &sil_sht,
@@ -437,6 +449,10 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance,
                if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
                        continue;
 
+               /* turn off SATA_IRQ if not supported */
+               if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
+                       bmdma2 &= ~SIL_DMA_SATA_IRQ;
+
                if (bmdma2 == 0xffffffff ||
                    !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
                        continue;
@@ -474,8 +490,9 @@ static void sil_thaw(struct ata_port *ap)
        ata_chk_status(ap);
        ata_bmdma_irq_clear(ap);
 
-       /* turn on SATA IRQ */
-       writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
+       /* turn on SATA IRQ if supported */
+       if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
+               writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
 
        /* turn on IRQ */
        tmp = readl(mmio_base + SIL_SYSCFG);
index c8b477c672475debae2c8994fefd290a3a660053..b5f8fa955679063e6420bfe915d36aa75760a75c 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "sata_sil24"
-#define DRV_VERSION    "0.24"
+#define DRV_VERSION    "0.3"
 
 /*
  * Port request block (PRB) 32 bytes
index c94b870cf378af39df82966e20b59b04876fe395..7566c2cabaf725bcde3d2c7ac4fa09add5259e0e 100644 (file)
@@ -54,7 +54,7 @@
 #endif /* CONFIG_PPC_OF */
 
 #define DRV_NAME       "sata_svw"
-#define DRV_VERSION    "1.8"
+#define DRV_VERSION    "2.0"
 
 enum {
        /* Taskfile registers offsets */
index f668c997e9af0bccf3637fe60375c6ebbd7ee661..64f3c1aeed217d5f07250a69c8f8e8afacff8d77 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_uli"
-#define DRV_VERSION    "0.6"
+#define DRV_VERSION    "1.0"
 
 enum {
        uli_5289                = 0,
index 322890b400a6000a9d627fa44d69fcabdfe9f131..501ce1791782a7284f5af4614d1552468d29bb5b 100644 (file)
@@ -47,7 +47,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "sata_via"
-#define DRV_VERSION    "1.2"
+#define DRV_VERSION    "2.0"
 
 enum board_ids_enum {
        vt6420,
@@ -335,10 +335,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                if ((pci_resource_start(pdev, i) == 0) ||
                    (pci_resource_len(pdev, i) < bar_sizes[i])) {
                        dev_printk(KERN_ERR, &pdev->dev,
-                                  "invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
-                                  i,
-                                  pci_resource_start(pdev, i),
-                                  pci_resource_len(pdev, i));
+                               "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
+                               i,
+                               (unsigned long long)pci_resource_start(pdev, i),
+                               (unsigned long long)pci_resource_len(pdev, i));
                        rc = -ENODEV;
                        goto err_out_regions;
                }
index 6d0c4f18e652ed42acec91830c8bde7fb875598c..616fd9634b4b0deb83a09e62dbde168c0da849ca 100644 (file)
@@ -47,7 +47,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_vsc"
-#define DRV_VERSION    "1.2"
+#define DRV_VERSION    "2.0"
 
 enum {
        /* Interrupt register offsets (from chip base address) */
@@ -443,16 +443,12 @@ err_out:
 }
 
 
-/*
- * Intel 31244 is supposed to be identical.
- * Compatibility is untested as of yet.
- */
 static const struct pci_device_id vsc_sata_pci_tbl[] = {
-       { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174,
+       { PCI_VENDOR_ID_VITESSE, 0x7174,
          PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
-       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244,
+       { PCI_VENDOR_ID_INTEL, 0x3200,
          PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
-       { }
+       { }     /* terminate list */
 };
 
 
index b88a7c1158af15b4cb34be96e142dbfd4bdce666..bff94541991c099047ce91fa47f6563da27ff825 100644 (file)
@@ -131,17 +131,6 @@ static int m68328_console_baud    = CONSOLE_BAUD_RATE;
 static int m68328_console_cbaud   = DEFAULT_CBAUD;
 
 
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char tmp_buf[SERIAL_XMIT_SIZE]; /* This is cheating */
-
 static inline int serial_paranoia_check(struct m68k_serial *info,
                                        char *name, const char *routine)
 {
@@ -211,16 +200,16 @@ static void rs_stop(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_stop"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        uart->ustcnt &= ~USTCNT_TXEN;
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 static void rs_put_char(char ch)
 {
         int flags, loops = 0;
 
-        save_flags(flags); cli();
+        local_irq_save(flags);
 
        while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
                loops++;
@@ -229,7 +218,7 @@ static void rs_put_char(char ch)
 
        UTX_TXDATA = ch;
         udelay(5);
-        restore_flags(flags);
+        local_irq_restore(flags);
 }
 
 static void rs_start(struct tty_struct *tty)
@@ -241,7 +230,7 @@ static void rs_start(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_start"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
 #ifdef USE_INTS
                uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
@@ -249,7 +238,7 @@ static void rs_start(struct tty_struct *tty)
                uart->ustcnt |= USTCNT_TXEN;
 #endif
        }
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 /* Drop into either the boot monitor or kadb upon receiving a break
@@ -327,14 +316,6 @@ static void receive_chars(struct m68k_serial *info, struct pt_regs *regs,
                if(!tty)
                        goto clear_and_exit;
                
-               /*
-                * Make sure that we do not overflow the buffer
-                */
-               if (tty_request_buffer_room(tty, 1) == 0) {
-                       tty_schedule_flip(tty);
-                       return;
-               }
-
                flag = TTY_NORMAL;
 
                if(rx & URX_PARITY_ERROR) {
@@ -473,7 +454,7 @@ static int startup(struct m68k_serial * info)
                        return -ENOMEM;
        }
 
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        /*
         * Clear the FIFO buffers and disable them
@@ -506,7 +487,7 @@ static int startup(struct m68k_serial * info)
        change_speed(info);
 
        info->flags |= S_INITIALIZED;
-       restore_flags(flags);
+       local_irq_restore(flags);
        return 0;
 }
 
@@ -523,7 +504,7 @@ static void shutdown(struct m68k_serial * info)
        if (!(info->flags & S_INITIALIZED))
                return;
 
-       save_flags(flags); cli(); /* Disable interrupts */
+       local_irq_save(flags);
        
        if (info->xmit_buf) {
                free_page((unsigned long) info->xmit_buf);
@@ -534,7 +515,7 @@ static void shutdown(struct m68k_serial * info)
                set_bit(TTY_IO_ERROR, &info->tty->flags);
        
        info->flags &= ~S_INITIALIZED;
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 struct {
@@ -655,24 +636,24 @@ static void rs_fair_output(void)
        if (info == 0) return;
        if (info->xmit_buf == 0) return;
 
-       save_flags(flags);  cli();
+       local_irq_save(flags);
        left = info->xmit_cnt;
        while (left != 0) {
                c = info->xmit_buf[info->xmit_tail];
                info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt--;
-               restore_flags(flags);
+               local_irq_restore(flags);
 
                rs_put_char(c);
 
-               save_flags(flags);  cli();
+               local_irq_save(flags);
                left = min(info->xmit_cnt, left-1);
        }
 
        /* Last character is being transmitted now (hopefully). */
        udelay(5);
 
-       restore_flags(flags);
+       local_irq_restore(flags);
        return;
 }
 
@@ -720,11 +701,11 @@ static void rs_flush_chars(struct tty_struct *tty)
 #endif
 
        /* Enable transmitter */
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
                        !info->xmit_buf) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
 
@@ -749,7 +730,7 @@ static void rs_flush_chars(struct tty_struct *tty)
        while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
        }
 #endif
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 extern void console_printn(const char * b, int count);
@@ -768,18 +749,22 @@ static int rs_write(struct tty_struct * tty,
        if (!tty || !info->xmit_buf)
                return 0;
 
-       save_flags(flags);
+       local_save_flags(flags);
        while (1) {
-               cli();          
+               local_irq_disable();            
                c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                   SERIAL_XMIT_SIZE - info->xmit_head));
+               local_irq_restore(flags);
+
                if (c <= 0)
                        break;
 
                memcpy(info->xmit_buf + info->xmit_head, buf, c);
+
+               local_irq_disable();
                info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt += c;
-               restore_flags(flags);
+               local_irq_restore(flags);
                buf += c;
                count -= c;
                total += c;
@@ -787,7 +772,7 @@ static int rs_write(struct tty_struct * tty,
 
        if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
                /* Enable transmitter */
-               cli();          
+               local_irq_disable();            
 #ifndef USE_INTS
                while(info->xmit_cnt) {
 #endif
@@ -807,9 +792,9 @@ static int rs_write(struct tty_struct * tty,
 #ifndef USE_INTS
                }
 #endif
-               restore_flags(flags);
+               local_irq_restore(flags);
        }
-       restore_flags(flags);
+
        return total;
 }
 
@@ -838,12 +823,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 static void rs_flush_buffer(struct tty_struct *tty)
 {
        struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       unsigned long flags;
                                
        if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
                return;
-       cli();
+       local_irq_save(flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       sti();
+       local_irq_restore(flags);
        tty_wakeup(tty);
 }
 
@@ -973,14 +959,15 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
        m68328_uart *uart = &uart_addr[info->line];
 #endif
        unsigned char status;
+       unsigned long flags;
 
-       cli();
+       local_irq_save(flags);
 #ifdef CONFIG_SERIAL_68328_RTS_CTS
        status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
 #else
        status = 0;
 #endif
-       sti();
+       local_irq_restore(flags);
        put_user(status,value);
        return 0;
 }
@@ -994,14 +981,13 @@ static void send_break(struct m68k_serial * info, unsigned int duration)
         unsigned long flags;
         if (!info->port)
                 return;
-        save_flags(flags);
-        cli();
+        local_irq_save(flags);
 #ifdef USE_INTS        
        uart->utx.w |= UTX_SEND_BREAK;
        msleep_interruptible(duration);
        uart->utx.w &= ~UTX_SEND_BREAK;
 #endif         
-        restore_flags(flags);
+        local_irq_restore(flags);
 }
 
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
@@ -1060,7 +1046,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                                               (struct serial_struct *) arg);
                case TIOCSERGETLSR: /* Get line status register */
                        if (access_ok(VERIFY_WRITE, (void *) arg,
-                                               sizeof(unsigned int));
+                                               sizeof(unsigned int)))
                                return get_lsr_info(info, (unsigned int *) arg);
                        return -EFAULT;
                case TIOCSERGSTRUCT:
@@ -1113,10 +1099,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        
        if (tty_hung_up_p(filp)) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
        
@@ -1138,7 +1124,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                info->count = 0;
        }
        if (info->count) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
        info->flags |= S_CLOSING;
@@ -1186,7 +1172,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        }
        info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
        wake_up_interruptible(&info->close_wait);
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 /*
@@ -1262,9 +1248,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        info->count--;
        info->blocked_open++;
        while (1) {
-               cli();
+               local_irq_disable();
                m68k_rtsdtr(info, 1);
-               sti();
+               local_irq_enable();
                current->state = TASK_INTERRUPTIBLE;
                if (tty_hung_up_p(filp) ||
                    !(info->flags & S_INITIALIZED)) {
@@ -1444,7 +1430,7 @@ rs68328_init(void)
                return -ENOMEM;
        }
 
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        for(i=0;i<NR_PORTS;i++) {
 
@@ -1489,7 +1475,7 @@ rs68328_init(void)
                    serial_pm[i]->data = info;
 #endif
        }
-       restore_flags(flags);
+       local_irq_restore(flags);
        return 0;
 }
 
index 94886c000d2a2e8ff9581d83423bee68cfeaa409..864ef859be5676e3c6638517e31d87d1a4045229 100644 (file)
@@ -594,8 +594,8 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
        else
                offset += idx * board->uart_offset;
 
-       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) /
-               (8 << board->reg_shift);
+       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+               (board->reg_shift + 3);
 
        if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
                return 1;
index 89700141f87e0d41b462ce6881a9f0a775d98549..5cacc5e74a9246e1982150027b95e96b4dbbd9c6 100644 (file)
@@ -2573,12 +2573,6 @@ static void flush_to_flip_buffer(struct e100_serial *info)
 
        DFLIP(
          if (1) {
-
-                 if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-                         DEBUG_LOG(info->line, "*** TTY_DONT_FLIP set flip.count %i ***\n", tty->flip.count);
-                         DEBUG_LOG(info->line, "*** recv_cnt %i\n", info->recv_cnt);
-                 } else {
-                 }
                  DEBUG_LOG(info->line, "*** rxtot %i\n", info->icount.rx);
                  DEBUG_LOG(info->line, "ldisc %lu\n", tty->ldisc.chars_in_buffer(tty));
                  DEBUG_LOG(info->line, "room  %lu\n", tty->ldisc.receive_room(tty));
index 7d823705193cfd55cebe2323b95d8edbf5d44c62..f8262e6ad8d3c3fc9728e621248c2d54f70bf2e5 100644 (file)
@@ -588,13 +588,6 @@ void jsm_input(struct jsm_channel *ch)
        len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
        ld = tty_ldisc_ref(tp);
 
-       /*
-        * If the DONT_FLIP flag is on, don't flush our buffer, and act
-        * like the ld doesn't have any space to put the data right now.
-        */
-       if (test_bit(TTY_DONT_FLIP, &tp->flags))
-               len = 0;
-
        /*
         * If we were unable to get a reference to the ld,
         * don't flush our buffer, and act like the ld doesn't
index 501316b198e51123bcaf30618f002c7de589afc0..ed946311d3a47e3120185e909eeb9524185cf4bc 100644 (file)
@@ -26,7 +26,7 @@ static DECLARE_RWSEM(ioc3_devices_rwsem);
 
 static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];
 static struct ioc3_submodule *ioc3_ethernet;
-static rwlock_t ioc3_submodules_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(ioc3_submodules_lock);
 
 /* NIC probing code */
 
index 8256a97eb508c1b4db3ff98574894091cb51dece..8562821e6498be2324f8763f17d1292c70f105a7 100644 (file)
@@ -438,7 +438,7 @@ static struct pci_device_id ioc4_id_table[] = {
        {0}
 };
 
-static struct pci_driver __devinitdata ioc4_driver = {
+static struct pci_driver ioc4_driver = {
        .name = "IOC4",
        .id_table = ioc4_id_table,
        .probe = ioc4_probe,
index 1cea4a6799fe66c3e6fd94eaf56b3ed52b13e2cb..ed1cdf6ac8f34dbe5d61a6b172b49ccea1bfdddd 100644 (file)
@@ -210,6 +210,7 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip)
        proxy->master = master;
        proxy->chip_select = chip->chip_select;
        proxy->max_speed_hz = chip->max_speed_hz;
+       proxy->mode = chip->mode;
        proxy->irq = chip->irq;
        proxy->modalias = chip->modalias;
 
index 6b4bc3f2bd864fd28b3b135118db929735ecf016..89bcda5a329897aee7d5694b879595355190d84e 100644 (file)
@@ -1684,9 +1684,13 @@ sl811h_probe(struct platform_device *dev)
                if (!addr || !data)
                        return -ENODEV;
                ioaddr = 1;
-
-               addr_reg = (void __iomem *) addr->start;
-               data_reg = (void __iomem *) data->start;
+               /*
+                * NOTE: 64-bit resource->start is getting truncated
+                * to avoid compiler warning, assuming that ->start
+                * is always 32-bit for this case
+                */
+               addr_reg = (void __iomem *) (unsigned long) addr->start;
+               data_reg = (void __iomem *) (unsigned long) data->start;
        } else {
                addr_reg = ioremap(addr->start, 1);
                if (addr_reg == NULL) {
index 9432c73022758435fd9dbfaf1c374aee31079bbf..d7f3f736a6928fc760d2159e1562132935584e40 100644 (file)
@@ -453,8 +453,7 @@ static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
                        tty = port->tty;
 
                        /*
-                        *      FIXME: must not do this in IRQ context,
-                        *      must honour TTY_DONT_FLIP
+                        *      FIXME: must not do this in IRQ context
                         */
                        tty->ldisc.receive_buf(
                                tty,
index 7de66b855d4e4e292d13182c40fafe0a44ceddac..1755dddf189908550b0dae24bdf8d2d498b1cc46 100644 (file)
@@ -40,14 +40,14 @@ static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
 
        mutex_unlock(&info->bl_mutex);
 
-       if (pdata->negative)
-               rlevel = MAX_RADEON_LEVEL - rlevel;
-
        if (rlevel < 0)
                rlevel = 0;
        else if (rlevel > MAX_RADEON_LEVEL)
                rlevel = MAX_RADEON_LEVEL;
 
+       if (pdata->negative)
+               rlevel = MAX_RADEON_LEVEL - rlevel;
+
        return rlevel;
 }
 
index d63c3f485853e52eb9b351bd7991295c05df1ebe..9ef68cd83bb4d0cc527524c073779fae21579d20 100644 (file)
@@ -743,8 +743,7 @@ void __exit au1100fb_cleanup(void)
 {
        driver_unregister(&au1100fb_driver);
 
-       if (drv_info.opt_mode)
-               kfree(drv_info.opt_mode);
+       kfree(drv_info.opt_mode);
 }
 
 module_init(au1100fb_init);
index a71e984c93d47aa8c8678ce1abb98a29b0a39336..ffc72ae3ada80a01f98c959099b004e57bc5aed4 100644 (file)
@@ -27,7 +27,7 @@
 
 static int hp680bl_suspended;
 static int current_intensity = 0;
-static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(bl_lock);
 static struct backlight_device *hp680_backlight_device;
 
 static void hp680bl_send_intensity(struct backlight_device *bd)
index f32b590730f237943c1589f401bceb9fc5211c5c..01401cd63ac061279a382f9884cb86424f2d0cd7 100644 (file)
@@ -390,7 +390,7 @@ static const char *vgacon_startup(void)
                vga_video_port_val = VGA_CRT_DM;
                if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
                        static struct resource ega_console_resource =
-                           { "ega", 0x3B0, 0x3BF };
+                           { .name = "ega", .start = 0x3B0, .end = 0x3BF };
                        vga_video_type = VIDEO_TYPE_EGAM;
                        vga_vram_size = 0x8000;
                        display_desc = "EGA+";
@@ -398,9 +398,9 @@ static const char *vgacon_startup(void)
                                         &ega_console_resource);
                } else {
                        static struct resource mda1_console_resource =
-                           { "mda", 0x3B0, 0x3BB };
+                           { .name = "mda", .start = 0x3B0, .end = 0x3BB };
                        static struct resource mda2_console_resource =
-                           { "mda", 0x3BF, 0x3BF };
+                           { .name = "mda", .start = 0x3BF, .end = 0x3BF };
                        vga_video_type = VIDEO_TYPE_MDA;
                        vga_vram_size = 0x2000;
                        display_desc = "*MDA";
@@ -423,14 +423,14 @@ static const char *vgacon_startup(void)
 
                        if (!ORIG_VIDEO_ISVGA) {
                                static struct resource ega_console_resource
-                                   = { "ega", 0x3C0, 0x3DF };
+                                   = { .name = "ega", .start = 0x3C0, .end = 0x3DF };
                                vga_video_type = VIDEO_TYPE_EGAC;
                                display_desc = "EGA";
                                request_resource(&ioport_resource,
                                                 &ega_console_resource);
                        } else {
                                static struct resource vga_console_resource
-                                   = { "vga+", 0x3C0, 0x3DF };
+                                   = { .name = "vga+", .start = 0x3C0, .end = 0x3DF };
                                vga_video_type = VIDEO_TYPE_VGAC;
                                display_desc = "VGA+";
                                request_resource(&ioport_resource,
@@ -474,7 +474,7 @@ static const char *vgacon_startup(void)
                        }
                } else {
                        static struct resource cga_console_resource =
-                           { "cga", 0x3D4, 0x3D5 };
+                           { .name = "cga", .start = 0x3D4, .end = 0x3D5 };
                        vga_video_type = VIDEO_TYPE_CGA;
                        vga_vram_size = 0x2000;
                        display_desc = "*CGA";
index 2e6df1fcb2b926e875508bc8ff3181bb4d89a7bc..c0cc5e3ba7b5fe28d689071a52836897d8450627 100644 (file)
@@ -23,6 +23,8 @@
 #include <asm/io.h>
 #include <asm/mtrr.h>
 
+#include <setup_arch.h>
+
 #define INCLUDE_TIMING_TABLE_DATA
 #define DBE_REG_BASE par->regs
 #include <video/sgivw.h>
@@ -42,10 +44,6 @@ struct sgivw_par {
  *  The default can be overridden if the driver is compiled as a module
  */
 
-/* set by arch/i386/kernel/setup.c */
-extern unsigned long sgivwfb_mem_phys;
-extern unsigned long sgivwfb_mem_size;
-
 static int ypan = 0;
 static int ywrap = 0;
 
index 12e1baa4508d6569753284260d04878849cf8aa3..8d45ed6688376461f357ca69d6ec6c9abe3c671a 100644 (file)
@@ -932,6 +932,8 @@ v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
                                        r.rcall || r.err);
                        } while (!r.rcall && !r.err && err==-ERESTARTSYS &&
                                m->trans->status==Connected && !m->err);
+
+                       err = -ERESTARTSYS;
                }
                sigpending = 1;
        }
index f867b8d3e973a069d1d0bf21495114963e36a0a0..450b0c1b385e62f31db2d74ce6990fd67f8aeedc 100644 (file)
@@ -38,7 +38,7 @@
  */
 
 extern struct file_system_type v9fs_fs_type;
-extern struct address_space_operations v9fs_addr_operations;
+extern const struct address_space_operations v9fs_addr_operations;
 extern const struct file_operations v9fs_file_operations;
 extern const struct file_operations v9fs_dir_operations;
 extern struct dentry_operations v9fs_dentry_operations;
index efda46fb64d9e5a0bacaa14ead4f0414e04b07f6..d4f0aa3c87f2fc2717413169d5ec651cda144aa8 100644 (file)
@@ -103,6 +103,6 @@ UnmapAndUnlock:
        return retval;
 }
 
-struct address_space_operations v9fs_addr_operations = {
+const struct address_space_operations v9fs_addr_operations = {
       .readpage = v9fs_vfs_readpage,
 };
index 5c6bdf82146c3618caeae2f9ff5a1f2832e89fae..2f580a197b8dadf573ce7093742e4e647c950c82 100644 (file)
@@ -300,7 +300,7 @@ clunk_fid:
        fid = V9FS_NOFID;
 
 put_fid:
-       if (fid >= 0)
+       if (fid != V9FS_NOFID)
                v9fs_put_idpool(fid, &v9ses->fidpool);
 
        kfree(fcall);
index 6c5051802bd285bebefc266a282cf3539846850f..6dc8cfd6d80cf7e57a73e1be4828b945667894d4 100644 (file)
@@ -1116,7 +1116,7 @@ config JFFS2_SUMMARY
 
 config JFFS2_FS_XATTR
        bool "JFFS2 XATTR support (EXPERIMENTAL)"
-       depends on JFFS2_FS && EXPERIMENTAL && !JFFS2_FS_WRITEBUFFER
+       depends on JFFS2_FS && EXPERIMENTAL
        default n
        help
          Extended attributes are name:value pairs associated with inodes by
@@ -1722,7 +1722,7 @@ config CIFS_STATS
          mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
 
 config CIFS_STATS2
-       bool "CIFS extended statistics"
+       bool "Extended statistics"
        depends on CIFS_STATS
        help
          Enabling this option will allow more detailed statistics on SMB
@@ -1735,6 +1735,32 @@ config CIFS_STATS2
          Unless you are a developer or are doing network performance analysis
          or tuning, say N.
 
+config CIFS_WEAK_PW_HASH
+       bool "Support legacy servers which use weaker LANMAN security"
+       depends on CIFS
+       help
+         Modern CIFS servers including Samba and most Windows versions
+         (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
+         security mechanisms. These hash the password more securely
+         than the mechanisms used in the older LANMAN version of the
+          SMB protocol needed to establish sessions with old SMB servers.
+
+         Enabling this option allows the cifs module to mount to older
+         LANMAN based servers such as OS/2 and Windows 95, but such
+         mounts may be less secure than mounts using NTLM or more recent
+         security mechanisms if you are on a public network.  Unless you
+         have a need to access old SMB servers (and are on a private 
+         network) you probably want to say N.  Even if this support
+         is enabled in the kernel build, they will not be used
+         automatically. At runtime LANMAN mounts are disabled but
+         can be set to required (or optional) either in
+         /proc/fs/cifs (see fs/cifs/README for more detail) or via an
+         option on the mount command. This support is disabled by 
+         default in order to reduce the possibility of a downgrade
+         attack.
+         If unsure, say N.
+
 config CIFS_XATTR
         bool "CIFS extended attributes"
         depends on CIFS
@@ -1763,6 +1789,16 @@ config CIFS_POSIX
          (such as Samba 3.10 and later) which can negotiate
          CIFS POSIX ACL support.  If unsure, say N.
 
+config CIFS_DEBUG2
+       bool "Enable additional CIFS debugging routines"
+       help
+          Enabling this option adds a few more debugging routines
+          to the cifs code which slightly increases the size of
+          the cifs module and can cause additional logging of debug
+          messages in some error paths, slowing performance. This
+          option can be turned off unless you are debugging
+          cifs problems.  If unsure, say N.
+          
 config CIFS_EXPERIMENTAL
          bool "CIFS Experimental Features (EXPERIMENTAL)"
          depends on CIFS && EXPERIMENTAL
@@ -1778,7 +1814,7 @@ config CIFS_EXPERIMENTAL
            If unsure, say N.
 
 config CIFS_UPCALL
-         bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
+         bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
          depends on CIFS_EXPERIMENTAL
          select CONNECTOR
          help
index a02802a30798a0eefe36f52e8302f0d1b8c70a38..534f3eecc985c7b5bfe9231bd4807db4091e388d 100644 (file)
@@ -72,7 +72,7 @@ static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping, block, adfs_get_block);
 }
 
-static struct address_space_operations adfs_aops = {
+static const struct address_space_operations adfs_aops = {
        .readpage       = adfs_readpage,
        .writepage      = adfs_writepage,
        .sync_page      = block_sync_page,
index a43a876742b8e3b9759c7429e475bb62f5fb7e61..0ddd4cc0d1a0b598ca934b67ba6598b23bc725b7 100644 (file)
@@ -195,9 +195,9 @@ extern struct inode_operations   affs_symlink_inode_operations;
 extern const struct file_operations     affs_file_operations;
 extern const struct file_operations     affs_file_operations_ofs;
 extern const struct file_operations     affs_dir_operations;
-extern struct address_space_operations  affs_symlink_aops;
-extern struct address_space_operations  affs_aops;
-extern struct address_space_operations  affs_aops_ofs;
+extern const struct address_space_operations    affs_symlink_aops;
+extern const struct address_space_operations    affs_aops;
+extern const struct address_space_operations    affs_aops_ofs;
 
 extern struct dentry_operations         affs_dentry_operations;
 extern struct dentry_operations         affs_dentry_operations_intl;
index 7076262af39b39404c4ae2669392597934554602..3de8590e4f6a56a35d13e09be2e8a3012df2fb54 100644 (file)
@@ -406,7 +406,7 @@ static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,affs_get_block);
 }
-struct address_space_operations affs_aops = {
+const struct address_space_operations affs_aops = {
        .readpage = affs_readpage,
        .writepage = affs_writepage,
        .sync_page = block_sync_page,
@@ -759,7 +759,7 @@ out:
        goto done;
 }
 
-struct address_space_operations affs_aops_ofs = {
+const struct address_space_operations affs_aops_ofs = {
        .readpage = affs_readpage_ofs,
        //.writepage = affs_writepage_ofs,
        //.sync_page = affs_sync_page_ofs,
index 426f0f094f23b145372e3153731eb8112a172463..f802256a59330d96d537ac513f636b01a81eb79c 100644 (file)
@@ -66,7 +66,7 @@ fail:
        return err;
 }
 
-struct address_space_operations affs_symlink_aops = {
+const struct address_space_operations affs_symlink_aops = {
        .readpage       = affs_symlink_readpage,
 };
 
index 7bb716887e29b6029ea058d2c206502d1ad5605c..67d6634101fdcc81e75787c87d8084f5c13256c9 100644 (file)
@@ -35,7 +35,7 @@ struct inode_operations afs_file_inode_operations = {
        .getattr        = afs_inode_getattr,
 };
 
-struct address_space_operations afs_fs_aops = {
+const struct address_space_operations afs_fs_aops = {
        .readpage       = afs_file_readpage,
        .sync_page      = block_sync_page,
        .set_page_dirty = __set_page_dirty_nobuffers,
index 72febdf9a35af9379996eb51a9167e1c085aeb8b..e88b3b65ae494a2861c8447b0592e9a7abcc353c 100644 (file)
@@ -69,7 +69,7 @@ extern const struct file_operations afs_dir_file_operations;
 /*
  * file.c
  */
-extern struct address_space_operations afs_fs_aops;
+extern const struct address_space_operations afs_fs_aops;
 extern struct inode_operations afs_file_inode_operations;
 
 #ifdef AFS_CACHING_SUPPORT
index 08201fab26cde9e33778add4589356f931d2e1b4..a83e889a97cd7d8d79dd04fe29b5f0f43edbe890 100644 (file)
@@ -73,7 +73,7 @@ static struct inode_operations befs_dir_inode_operations = {
        .lookup         = befs_lookup,
 };
 
-static struct address_space_operations befs_aops = {
+static const struct address_space_operations befs_aops = {
        .readpage       = befs_readpage,
        .sync_page      = block_sync_page,
        .bmap           = befs_bmap,
index 9d791004b21ccbf02ccc7a6d01d01a64cddf0b70..31973bbbf0574d285c71e309cbdbc36de83d0784 100644 (file)
@@ -50,7 +50,7 @@ static inline struct bfs_inode_info *BFS_I(struct inode *inode)
 /* file.c */
 extern struct inode_operations bfs_file_inops;
 extern const struct file_operations bfs_file_operations;
-extern struct address_space_operations bfs_aops;
+extern const struct address_space_operations bfs_aops;
 
 /* dir.c */
 extern struct inode_operations bfs_dir_inops;
index d83cd74a2e4e681a061552e8c26e22070e41efa0..3d5aca28a0a0980922c83c0b197d1cf52cb27593 100644 (file)
@@ -153,7 +153,7 @@ static sector_t bfs_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping, block, bfs_get_block);
 }
 
-struct address_space_operations bfs_aops = {
+const struct address_space_operations bfs_aops = {
        .readpage       = bfs_readpage,
        .writepage      = bfs_writepage,
        .sync_page      = block_sync_page,
index 028d9fb9c2d536dafad7563e36874c0e8c934d91..7f7600e2381cdafab5c360101b6c2b9573b2765d 100644 (file)
@@ -1095,7 +1095,7 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
 }
 
-struct address_space_operations def_blk_aops = {
+const struct address_space_operations def_blk_aops = {
        .readpage       = blkdev_readpage,
        .writepage      = blkdev_writepage,
        .sync_page      = block_sync_page,
index 373bb6292bdc137a606296c7864093470d41b00f..e9994722f4a30959019e1df6e0516f8da23b9402 100644 (file)
@@ -564,7 +564,7 @@ still_busy:
  * Completion handler for block_write_full_page() - pages which are unlocked
  * during I/O, and which have PageWriteback cleared upon I/O completion.
  */
-void end_buffer_async_write(struct buffer_head *bh, int uptodate)
+static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
 {
        char b[BDEVNAME_SIZE];
        unsigned long flags;
@@ -2598,7 +2598,7 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from)
        unsigned offset = from & (PAGE_CACHE_SIZE-1);
        unsigned to;
        struct page *page;
-       struct address_space_operations *a_ops = mapping->a_ops;
+       const struct address_space_operations *a_ops = mapping->a_ops;
        char *kaddr;
        int ret = 0;
 
@@ -3166,7 +3166,6 @@ EXPORT_SYMBOL(block_sync_page);
 EXPORT_SYMBOL(block_truncate_page);
 EXPORT_SYMBOL(block_write_full_page);
 EXPORT_SYMBOL(cont_prepare_write);
-EXPORT_SYMBOL(end_buffer_async_write);
 EXPORT_SYMBOL(end_buffer_read_sync);
 EXPORT_SYMBOL(end_buffer_write_sync);
 EXPORT_SYMBOL(file_fsync);
index 7271bb0257f64f149d1fd3f9857416c1513787ae..a61d17ed1827e3552a6808a8f705fdd2281d7fe4 100644 (file)
@@ -1,9 +1,24 @@
+Version 1.44
+------------
+Rewritten sessionsetup support, including support for legacy SMB
+session setup needed for OS/2 and older servers such as Windows 95 and 98.
+Fix oops on ls to OS/2 servers.  Add support for level 1 FindFirst
+so we can do search (ls etc.) to OS/2.  Do not send NTCreateX
+or recent levels of FindFirst unless server says it supports NT SMBs
+(instead use legacy equivalents from LANMAN dialect). Fix to allow
+NTLMv2 authentication support (now can use stronger password hashing
+on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004).
+Allow override of global cifs security flags on mount via "sec=" option(s).
+
 Version 1.43
 ------------
 POSIX locking to servers which support CIFS POSIX Extensions
 (disabled by default controlled by proc/fs/cifs/Experimental).
 Handle conversion of long share names (especially Asian languages)
-to Unicode during mount. 
+to Unicode during mount. Fix memory leak in sess struct on reconnect.
+Fix rare oops after acpi suspend.  Fix O_TRUNC opens to overwrite on
+cifs open which helps rare case when setpathinfo fails or server does
+not support it. 
 
 Version 1.42
 ------------
index 58c77254a23b3dec24a11475a858aa2f96c1a6d2..a26f26ed5a17e78bb5caf31732be07d21e172a5f 100644 (file)
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CIFS) += cifs.o
 
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o ntlmssp.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o
index 0355003f4f0a3b69eb021606d96f9e5261480c40..7986d0d97ace4f97b3b3d10b0800d03fcaabb631 100644 (file)
@@ -443,7 +443,10 @@ A partial list of the supported mount options follows:
                SFU does).  In the future the bottom 9 bits of the mode
                mode also will be emulated using queries of the security
                descriptor (ACL).
-sec            Security mode.  Allowed values are:
+ sign           Must use packet signing (helps avoid unwanted data modification
+               by intermediate systems in the route).  Note that signing
+               does not work with lanman or plaintext authentication.
+ sec            Security mode.  Allowed values are:
                        none    attempt to connection as a null user (no name)
                        krb5    Use Kerberos version 5 authentication
                        krb5i   Use Kerberos authentication and packet signing
@@ -453,6 +456,8 @@ sec         Security mode.  Allowed values are:
                                server requires signing also can be the default) 
                        ntlmv2  Use NTLMv2 password hashing      
                        ntlmv2i Use NTLMv2 password hashing with packet signing
+                       lanman  (if configured in kernel config) use older
+                               lanman hash
 
 The mount.cifs mount helper also accepts a few mount options before -o
 including:
@@ -485,14 +490,34 @@ PacketSigningEnabled      If set to one, cifs packet signing is enabled
                        it.  If set to two, cifs packet signing is
                        required even if the server considers packet
                        signing optional. (default 1)
+SecurityFlags          Flags which control security negotiation and
+                       also packet signing. Authentication (may/must)
+                       flags (e.g. for NTLM and/or NTLMv2) may be combined with
+                       the signing flags.  Specifying two different password
+                       hashing mechanisms (as "must use") on the other hand 
+                       does not make much sense. Default flags are 
+                               0x07007 
+                       (NTLM, NTLMv2 and packet signing allowed).  Maximum 
+                       allowable flags if you want to allow mounts to servers
+                       using weaker password hashes is 0x37037 (lanman,
+                       plaintext, ntlm, ntlmv2, signing allowed):
+                       may use packet signing                          0x00001
+                       must use packet signing                         0x01001
+                       may use NTLM (most common password hash)        0x00002
+                       must use NTLM                                   0x02002
+                       may use NTLMv2                                  0x00004
+                       must use NTLMv2                                 0x04004
+                       may use Kerberos security (not implemented yet) 0x00008
+                       must use Kerberos (not implemented yet)         0x08008
+                       may use lanman (weak) password hash             0x00010
+                       must use lanman password hash                   0x10010
+                       may use plaintext passwords                     0x00020
+                       must use plaintext passwords                    0x20020
+                       (reserved for future packet encryption)         0x00040
+
 cifsFYI                        If set to one, additional debug information is
                        logged to the system error log. (default 0)
-ExtendedSecurity       If set to one, SPNEGO session establishment
-                       is allowed which enables more advanced 
-                       secure CIFS session establishment (default 0)
-NTLMV2Enabled          If set to one, more secure password hashes
-                       are used when the server supports them and
-                       when kerberos is not negotiated (default 0)
 traceSMB               If set to one, debug information is logged to the
                        system error log with the start of smb requests
                        and responses (default 0)
index 086ae8f4a207a22f0d1bfe2863439ed20bd88f89..031cdf2932568ae5dea33d4813d5b8bac314e1c5 100644 (file)
@@ -467,7 +467,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
        asn1_open(&ctx, security_blob, length);
 
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-               cFYI(1, ("Error decoding negTokenInit header "));
+               cFYI(1, ("Error decoding negTokenInit header"));
                return 0;
        } else if ((cls != ASN1_APL) || (con != ASN1_CON)
                   || (tag != ASN1_EOC)) {
@@ -495,7 +495,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
 
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding negTokenInit "));
+                       cFYI(1, ("Error decoding negTokenInit"));
                        return 0;
                } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
                           || (tag != ASN1_EOC)) {
@@ -505,7 +505,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
 
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding negTokenInit "));
+                       cFYI(1, ("Error decoding negTokenInit"));
                        return 0;
                } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
                           || (tag != ASN1_SEQ)) {
@@ -515,7 +515,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
 
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding 2nd part of negTokenInit "));
+                       cFYI(1, ("Error decoding 2nd part of negTokenInit"));
                        return 0;
                } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
                           || (tag != ASN1_EOC)) {
@@ -527,7 +527,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
 
                if (asn1_header_decode
                    (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding 2nd part of negTokenInit "));
+                       cFYI(1, ("Error decoding 2nd part of negTokenInit"));
                        return 0;
                } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
                           || (tag != ASN1_SEQ)) {
index f4124a32bef8974edd3f02111f8e382a63f02199..96abeb7389784d4e3f5fa6eb4ee72ea8d66b947a 100644 (file)
@@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length)
        char *charptr = data;
        char buf[10], line[80];
 
-       printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", 
+       printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n", 
                label, length, data);
        for (i = 0; i < length; i += 16) {
                line[0] = 0;
@@ -57,6 +57,57 @@ cifs_dump_mem(char *label, void *data, int length)
        }
 }
 
+#ifdef CONFIG_CIFS_DEBUG2
+void cifs_dump_detail(struct smb_hdr * smb)
+{
+       cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
+                 smb->Command, smb->Status.CifsError,
+                 smb->Flags, smb->Flags2, smb->Mid, smb->Pid));
+       cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb)));
+}
+
+
+void cifs_dump_mids(struct TCP_Server_Info * server)
+{
+       struct list_head *tmp;
+       struct mid_q_entry * mid_entry;
+
+       if(server == NULL)
+               return;
+
+       cERROR(1,("Dump pending requests:"));
+       spin_lock(&GlobalMid_Lock);
+       list_for_each(tmp, &server->pending_mid_q) {
+               mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+               if(mid_entry) {
+                       cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
+                               mid_entry->midState,
+                               (int)mid_entry->command,
+                               mid_entry->pid,
+                               mid_entry->tsk,
+                               mid_entry->mid));
+#ifdef CONFIG_CIFS_STATS2
+                       cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld",
+                               mid_entry->largeBuf,
+                               mid_entry->resp_buf,
+                               mid_entry->when_received,
+                               jiffies));
+#endif /* STATS2 */
+                       cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
+                                 mid_entry->multiEnd));
+                       if(mid_entry->resp_buf) {
+                               cifs_dump_detail(mid_entry->resp_buf);
+                               cifs_dump_mem("existing buf: ",
+                                       mid_entry->resp_buf,
+                                       62 /* fixme */);
+                       }
+                       
+               }
+       }
+       spin_unlock(&GlobalMid_Lock);
+}
+#endif /* CONFIG_CIFS_DEBUG2 */
+
 #ifdef CONFIG_PROC_FS
 static int
 cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
@@ -73,7 +124,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 
        *beginBuffer = buf + offset;
 
-       
        length =
            sprintf(buf,
                    "Display Internal CIFS Data Structures for Debugging\n"
@@ -395,12 +445,12 @@ static read_proc_t traceSMB_read;
 static write_proc_t traceSMB_write;
 static read_proc_t multiuser_mount_read;
 static write_proc_t multiuser_mount_write;
-static read_proc_t extended_security_read;
-static write_proc_t extended_security_write;
-static read_proc_t ntlmv2_enabled_read;
+static read_proc_t security_flags_read;
+static write_proc_t security_flags_write;
+/* static read_proc_t ntlmv2_enabled_read;
 static write_proc_t ntlmv2_enabled_write;
 static read_proc_t packet_signing_enabled_read;
-static write_proc_t packet_signing_enabled_write;
+static write_proc_t packet_signing_enabled_write;*/
 static read_proc_t experimEnabled_read;
 static write_proc_t experimEnabled_write;
 static read_proc_t linuxExtensionsEnabled_read;
@@ -458,10 +508,10 @@ cifs_proc_init(void)
                pde->write_proc = multiuser_mount_write;
 
        pde =
-           create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
-                               extended_security_read, NULL);
+           create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
+                               security_flags_read, NULL);
        if (pde)
-               pde->write_proc = extended_security_write;
+               pde->write_proc = security_flags_write;
 
        pde =
        create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
@@ -469,7 +519,7 @@ cifs_proc_init(void)
        if (pde)
                pde->write_proc = lookupFlag_write;
 
-       pde =
+/*     pde =
            create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
                                ntlmv2_enabled_read, NULL);
        if (pde)
@@ -479,7 +529,7 @@ cifs_proc_init(void)
            create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
                                packet_signing_enabled_read, NULL);
        if (pde)
-               pde->write_proc = packet_signing_enabled_write;
+               pde->write_proc = packet_signing_enabled_write;*/
 }
 
 void
@@ -496,9 +546,9 @@ cifs_proc_clean(void)
 #endif
        remove_proc_entry("MultiuserMount", proc_fs_cifs);
        remove_proc_entry("OplockEnabled", proc_fs_cifs);
-       remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
-       remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
-       remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
+/*     remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
+       remove_proc_entry("SecurityFlags",proc_fs_cifs);
+/*     remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
        remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
        remove_proc_entry("Experimental",proc_fs_cifs);
        remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
@@ -782,12 +832,12 @@ multiuser_mount_write(struct file *file, const char __user *buffer,
 }
 
 static int
-extended_security_read(char *page, char **start, off_t off,
+security_flags_read(char *page, char **start, off_t off,
                       int count, int *eof, void *data)
 {
        int len;
 
-       len = sprintf(page, "%d\n", extended_security);
+       len = sprintf(page, "0x%x\n", extended_security);
 
        len -= off;
        *start = page + off;
@@ -803,24 +853,52 @@ extended_security_read(char *page, char **start, off_t off,
        return len;
 }
 static int
-extended_security_write(struct file *file, const char __user *buffer,
+security_flags_write(struct file *file, const char __user *buffer,
                        unsigned long count, void *data)
 {
+       unsigned int flags;
+       char flags_string[12];
        char c;
-       int rc;
 
-       rc = get_user(c, buffer);
-       if (rc)
-               return rc;
-       if (c == '0' || c == 'n' || c == 'N')
-               extended_security = 0;
-       else if (c == '1' || c == 'y' || c == 'Y')
-               extended_security = 1;
+       if((count < 1) || (count > 11))
+               return -EINVAL;
+
+       memset(flags_string, 0, 12);
+
+       if(copy_from_user(flags_string, buffer, count))
+               return -EFAULT;
+
+       if(count < 3) {
+               /* single char or single char followed by null */
+               c = flags_string[0];
+               if (c == '0' || c == 'n' || c == 'N')
+                       extended_security = CIFSSEC_DEF; /* default */
+               else if (c == '1' || c == 'y' || c == 'Y')
+                       extended_security = CIFSSEC_MAX;
+               return count;
+       }
+       /* else we have a number */
+
+       flags = simple_strtoul(flags_string, NULL, 0);
+
+       cFYI(1,("sec flags 0x%x", flags));
+
+       if(flags <= 0)  {
+               cERROR(1,("invalid security flags %s",flags_string));
+               return -EINVAL;
+       }
 
+       if(flags & ~CIFSSEC_MASK) {
+               cERROR(1,("attempt to set unsupported security flags 0x%x",
+                       flags & ~CIFSSEC_MASK));
+               return -EINVAL;
+       }
+       /* flags look ok - update the global security flags for cifs module */
+       extended_security = flags;
        return count;
 }
 
-static int
+/* static int
 ntlmv2_enabled_read(char *page, char **start, off_t off,
                       int count, int *eof, void *data)
 {
@@ -855,6 +933,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer,
                ntlmv2_support = 0;
        else if (c == '1' || c == 'y' || c == 'Y')
                ntlmv2_support = 1;
+       else if (c == '2')
+               ntlmv2_support = 2;
 
        return count;
 }
@@ -898,7 +978,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer,
                sign_CIFS_PDUs = 2;
 
        return count;
-}
+} */
 
 
 #endif
index 4304d9dcfb6c6501853b533f7f3d320fcbcd95bf..c26cd0d2c6d525d64455dfba60e9fdd5b9a4243a 100644 (file)
 #define _H_CIFS_DEBUG
 
 void cifs_dump_mem(char *label, void *data, int length);
+#ifdef CONFIG_CIFS_DEBUG2
+void cifs_dump_detail(struct smb_hdr *);
+void cifs_dump_mids(struct TCP_Server_Info *);
+#endif
 extern int traceSMB;           /* flag which enables the function below */
 void dump_smb(struct smb_hdr *, int);
 #define CIFS_INFO      0x01
index d2b128255944269506f5395506528a4009d7d6dd..d2a8b2941fc26a2d752ccf8954f9fb31cfef026f 100644 (file)
@@ -22,6 +22,7 @@
 #include "cifs_unicode.h"
 #include "cifs_uniupr.h"
 #include "cifspdu.h"
+#include "cifsglob.h"
 #include "cifs_debug.h"
 
 /*
index e7d63737e65110c1be3fddb6f7974ab7a1f16c44..a89efaf78a266ef2d7a4c01d8f5876c5969504dc 100644 (file)
@@ -26,6 +26,8 @@
 #include "md5.h"
 #include "cifs_unicode.h"
 #include "cifsproto.h"
+#include <linux/ctype.h>
+#include <linux/random.h>
 
 /* Calculate and return the CIFS signature based on the mac key and the smb pdu */
 /* the 16 byte signature must be allocated by the caller  */
@@ -35,6 +37,8 @@
 
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+                       unsigned char *p24);
        
 static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, 
                                    const char * key, char * signature)
@@ -45,7 +49,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
                return -EINVAL;
 
        MD5Init(&context);
-       MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+       MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
        MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
        MD5Final(signature,&context);
        return 0;
@@ -90,7 +94,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
                return -EINVAL;
 
        MD5Init(&context);
-       MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+       MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
        for(i=0;i<n_vec;i++) {
                if(iov[i].iov_base == NULL) {
                        cERROR(1,("null iovec entry"));
@@ -204,11 +208,12 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
 
        E_md4hash(password, temp_key);
        mdfour(key,temp_key,16);
-       memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
+       memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
        return 0;
 }
 
-int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info)
+int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, 
+                               const struct nls_table * nls_info)
 {
        char temp_hash[16];
        struct HMACMD5Context ctx;
@@ -225,6 +230,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
        user_name_len = strlen(ses->userName);
        if(user_name_len > MAX_USERNAME_SIZE)
                return -EINVAL;
+       if(ses->domainName == NULL)
+               return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
        dom_name_len = strlen(ses->domainName);
        if(dom_name_len > MAX_USERNAME_SIZE)
                return -EINVAL;
@@ -259,16 +266,131 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
        kfree(unicode_buf);
        return 0;
 }
-void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
+{
+       int i;
+       char password_with_pad[CIFS_ENCPWD_SIZE];
+
+       if(ses->server == NULL)
+               return;
+
+       memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+       strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
+
+       if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
+               if(extended_security & CIFSSEC_MAY_PLNTXT) {
+                       memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); 
+                       return;
+               }
+
+       /* calculate old style session key */
+       /* calling toupper is less broken than repeatedly
+       calling nls_toupper would be since that will never
+       work for UTF8, but neither handles multibyte code pages
+       but the only alternative would be converting to UCS-16 (Unicode)
+       (using a routine something like UniStrupr) then
+       uppercasing and then converting back from Unicode - which
+       would only worth doing it if we knew it were utf8. Basically
+       utf8 and other multibyte codepages each need their own strupper
+       function since a byte at a time will ont work. */
+
+       for(i = 0; i < CIFS_ENCPWD_SIZE; i++) {
+               password_with_pad[i] = toupper(password_with_pad[i]);
+       }
+
+       SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
+       /* clear password before we return/free memory */
+       memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+}
+#endif /* CIFS_WEAK_PW_HASH */
+
+static int calc_ntlmv2_hash(struct cifsSesInfo *ses, 
+                           const struct nls_table * nls_cp)
+{
+       int rc = 0;
+       int len;
+       char nt_hash[16];
+       struct HMACMD5Context * pctxt;
+       wchar_t * user;
+       wchar_t * domain;
+
+       pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
+
+       if(pctxt == NULL)
+               return -ENOMEM;
+
+       /* calculate md4 hash of password */
+       E_md4hash(ses->password, nt_hash);
+
+       /* convert Domainname to unicode and uppercase */
+       hmac_md5_init_limK_to_64(nt_hash, 16, pctxt);
+
+       /* convert ses->userName to unicode and uppercase */
+       len = strlen(ses->userName);
+       user = kmalloc(2 + (len * 2), GFP_KERNEL);
+       if(user == NULL)
+               goto calc_exit_2;
+       len = cifs_strtoUCS(user, ses->userName, len, nls_cp);
+       UniStrupr(user);
+       hmac_md5_update((char *)user, 2*len, pctxt);
+
+       /* convert ses->domainName to unicode and uppercase */
+       if(ses->domainName) {
+               len = strlen(ses->domainName);
+
+               domain = kmalloc(2 + (len * 2), GFP_KERNEL);
+               if(domain == NULL)
+                       goto calc_exit_1;
+               len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
+               UniStrupr(domain);
+
+               hmac_md5_update((char *)domain, 2*len, pctxt);
+       
+               kfree(domain);
+       }
+calc_exit_1:
+       kfree(user);
+calc_exit_2:
+       /* BB FIXME what about bytes 24 through 40 of the signing key? 
+          compare with the NTLM example */
+       hmac_md5_final(ses->server->mac_signing_key, pctxt);
+
+       return rc;
+}
+
+void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, 
+                     const struct nls_table * nls_cp)
+{
+       int rc;
+       struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf;
+
+       buf->blob_signature = cpu_to_le32(0x00000101);
+       buf->reserved = 0;
+       buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+       get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
+       buf->reserved2 = 0;
+       buf->names[0].type = 0;
+       buf->names[0].length = 0;
+
+       /* calculate buf->ntlmv2_hash */
+       rc = calc_ntlmv2_hash(ses, nls_cp);
+       if(rc)
+               cERROR(1,("could not get v2 hash rc %d",rc));
+       CalcNTLMv2_response(ses, resp_buf);
+}
+
+void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response)
 {
        struct HMACMD5Context context;
+       /* rest of v2 struct already generated */
        memcpy(v2_session_response + 8, ses->server->cryptKey,8);
-       /* gen_blob(v2_session_response + 16); */
        hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
 
-       hmac_md5_update(ses->server->cryptKey,8,&context);
-/*     hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
+       hmac_md5_update(v2_session_response+8, 
+                       sizeof(struct ntlmv2_resp) - 8, &context);
 
        hmac_md5_final(v2_session_response,&context);
-       cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */
+/*     cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
 }
index 8b4de6eaabd0ee11bf329e02fa1060cd32a44d0c..c28ede599946842568356378cec5ed3eaff3f139 100644 (file)
@@ -56,8 +56,8 @@ unsigned int experimEnabled = 0;
 unsigned int linuxExtEnabled = 1;
 unsigned int lookupCacheEnabled = 1;
 unsigned int multiuser_mount = 0;
-unsigned int extended_security = 0;
-unsigned int ntlmv2_support = 0;
+unsigned int extended_security = CIFSSEC_DEF;
+/* unsigned int ntlmv2_support = 0; */
 unsigned int sign_CIFS_PDUs = 1;
 extern struct task_struct * oplockThread; /* remove sparse warning */
 struct task_struct * oplockThread = NULL;
@@ -908,7 +908,7 @@ static int cifs_dnotify_thread(void * dummyarg)
        struct cifsSesInfo *ses;
 
        do {
-               if(try_to_freeze())
+               if (try_to_freeze())
                        continue;
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(15*HZ);
index d56c0577c7103f95f1c8cd8068f1318cb45ab0cf..8f75c6f24701ff4e5a63f99cccb3b316830204bc 100644 (file)
@@ -32,7 +32,8 @@
 #define TRUE 1
 #endif
 
-extern struct address_space_operations cifs_addr_ops;
+extern const struct address_space_operations cifs_addr_ops;
+extern const struct address_space_operations cifs_addr_ops_smallbuf;
 
 /* Functions related to super block operations */
 extern struct super_operations cifs_super_ops;
@@ -99,5 +100,5 @@ extern ssize_t       cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
                       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.43"
+#define CIFS_VERSION   "1.44"
 #endif                         /* _CIFSFS_H */
index 006eb33bff5ff7e6a576b5804e95ec22eb50bb52..6d7cf5f3bc0bdb3549b7e038fdd099ada89bee3c 100644 (file)
@@ -88,7 +88,8 @@ enum statusEnum {
 };
 
 enum securityEnum {
-       NTLM = 0,               /* Legacy NTLM012 auth with NTLM hash */
+       LANMAN = 0,             /* Legacy LANMAN auth */
+       NTLM,                   /* Legacy NTLM012 auth with NTLM hash */
        NTLMv2,                 /* Legacy NTLM auth with NTLMv2 hash */
        RawNTLMSSP,             /* NTLMSSP without SPNEGO */
        NTLMSSP,                /* NTLMSSP via SPNEGO */
@@ -157,7 +158,7 @@ struct TCP_Server_Info {
        /* 16th byte of RFC1001 workstation name is always null */
        char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
        __u32 sequence_number; /* needed for CIFS PDU signature */
-       char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; 
+       char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; 
 };
 
 /*
@@ -179,10 +180,13 @@ struct cifsUidInfo {
 struct cifsSesInfo {
        struct list_head cifsSessionList;
        struct semaphore sesSem;
+#if 0
        struct cifsUidInfo *uidInfo;    /* pointer to user info */
+#endif
        struct TCP_Server_Info *server; /* pointer to server info */
        atomic_t inUse; /* # of mounts (tree connections) on this ses */
        enum statusEnum status;
+       unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
        __u16 flags;
        char *serverOS;         /* name of operating system underlying server */
@@ -194,7 +198,7 @@ struct cifsSesInfo {
        char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for 
                                TCP names - will ipv6 and sctp addresses fit? */
        char userName[MAX_USERNAME_SIZE + 1];
-       char domainName[MAX_USERNAME_SIZE + 1];
+       char * domainName;
        char * password;
 };
 /* session flags */
@@ -209,12 +213,12 @@ struct cifsTconInfo {
        struct list_head openFileList;
        struct semaphore tconSem;
        struct cifsSesInfo *ses;        /* pointer to session associated with */
-       char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */
+       char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
        char *nativeFileSystem;
        __u16 tid;              /* The 2 byte tree id */
        __u16 Flags;            /* optional support bits */
        enum statusEnum tidStatus;
-       atomic_t useCount;      /* how many mounts (explicit or implicit) to this share */
+       atomic_t useCount;      /* how many explicit/implicit mounts to share */
 #ifdef CONFIG_CIFS_STATS
        atomic_t num_smbs_sent;
        atomic_t num_writes;
@@ -254,7 +258,7 @@ struct cifsTconInfo {
        spinlock_t stat_lock;
 #endif /* CONFIG_CIFS_STATS */
        FILE_SYSTEM_DEVICE_INFO fsDevInfo;
-       FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo;  /* ok if file system name truncated */
+       FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
        FILE_SYSTEM_UNIX_INFO fsUnixInfo;
        unsigned retry:1;
        unsigned nocase:1;
@@ -305,7 +309,6 @@ struct cifsFileInfo {
        atomic_t wrtPending;   /* handle in use - defer close */
        struct semaphore fh_sem; /* prevents reopen race after dead ses*/
        char * search_resume_name; /* BB removeme BB */
-       unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
        struct cifs_search_info srch_inf;
 };
 
@@ -391,9 +394,9 @@ struct mid_q_entry {
        struct smb_hdr *resp_buf;       /* response buffer */
        int midState;   /* wish this were enum but can not pass to wait_event */
        __u8 command;   /* smb command code */
-       unsigned multiPart:1;   /* multiple responses to one SMB request */
        unsigned largeBuf:1;    /* if valid response, is pointer to large buf */
-       unsigned multiResp:1;   /* multiple trans2 responses for one request  */
+       unsigned multiRsp:1;   /* multiple trans2 responses for one request  */
+       unsigned multiEnd:1; /* both received */
 };
 
 struct oplock_q_entry {
@@ -430,15 +433,35 @@ struct dir_notify_req {
 #define   CIFS_LARGE_BUFFER     2
 #define   CIFS_IOVEC            4    /* array of response buffers */
 
-/* Type of session setup needed */
-#define   CIFS_PLAINTEXT       0
-#define   CIFS_LANMAN          1
-#define   CIFS_NTLM            2
-#define   CIFS_NTLMSSP_NEG     3
-#define   CIFS_NTLMSSP_AUTH    4
-#define   CIFS_SPNEGO_INIT     5
-#define   CIFS_SPNEGO_TARG     6
-
+/* Security Flags: indicate type of session setup needed */
+#define   CIFSSEC_MAY_SIGN     0x00001
+#define   CIFSSEC_MAY_NTLM     0x00002
+#define   CIFSSEC_MAY_NTLMV2   0x00004
+#define   CIFSSEC_MAY_KRB5     0x00008
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define   CIFSSEC_MAY_LANMAN   0x00010
+#define   CIFSSEC_MAY_PLNTXT   0x00020
+#endif /* weak passwords */
+#define   CIFSSEC_MAY_SEAL     0x00040 /* not supported yet */
+
+#define   CIFSSEC_MUST_SIGN    0x01001
+/* note that only one of the following can be set so the
+result of setting MUST flags more than once will be to
+require use of the stronger protocol */
+#define   CIFSSEC_MUST_NTLM    0x02002
+#define   CIFSSEC_MUST_NTLMV2  0x04004
+#define   CIFSSEC_MUST_KRB5    0x08008
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define   CIFSSEC_MUST_LANMAN  0x10010
+#define   CIFSSEC_MUST_PLNTXT  0x20020
+#define   CIFSSEC_MASK          0x37037 /* current flags supported if weak */
+#else    
+#define          CIFSSEC_MASK          0x07007 /* flags supported if no weak config */
+#endif /* WEAK_PW_HASH */
+#define   CIFSSEC_MUST_SEAL    0x40040 /* not supported yet */
+
+#define   CIFSSEC_DEF  CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2
+#define   CIFSSEC_MAX  CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2
 /*
  *****************************************************************
  * All constants go here
@@ -500,16 +523,16 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;  /* protects list inserts on 3 above */
 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
 
 GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */
-GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */
+GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */
 
 /*
  * Global transaction id (XID) information
  */
 GLOBAL_EXTERN unsigned int GlobalCurrentXid;   /* protected by GlobalMid_Sem */
-GLOBAL_EXTERN unsigned int GlobalTotalActiveXid;       /* prot by GlobalMid_Sem */
+GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
 GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
-GLOBAL_EXTERN spinlock_t GlobalMid_Lock;  /* protects above and list operations */
-                                       /* on midQ entries */
+GLOBAL_EXTERN spinlock_t GlobalMid_Lock;  /* protects above & list operations */
+                                         /* on midQ entries */
 GLOBAL_EXTERN char Local_System_Name[15];
 
 /*
@@ -531,7 +554,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount;
 GLOBAL_EXTERN atomic_t midCount;
 
 /* Misc globals */
-GLOBAL_EXTERN unsigned int multiuser_mount;    /* if enabled allows new sessions
+GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
                                to be established on existing mount if we
                                have the uid/password or Kerberos credential 
                                or equivalent for current user */
@@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled;
 GLOBAL_EXTERN unsigned int lookupCacheEnabled;
 GLOBAL_EXTERN unsigned int extended_security;  /* if on, session setup sent 
                                with more secure ntlmssp2 challenge/resp */
-GLOBAL_EXTERN unsigned int ntlmv2_support;  /* better optional password hash */
 GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
+GLOBAL_EXTERN unsigned int secFlags;
 GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
 GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
 GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
index b2233ac05bd2791f143a036fc95f313bb96bc13e..86239023545b2d65dd6bc7240df7c5d2b88f9614 100644 (file)
@@ -16,7 +16,7 @@
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #ifndef _CIFSPDU_H
 
 #include <net/sock.h>
 
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define LANMAN_PROT 0
+#define CIFS_PROT   1
+#else
 #define CIFS_PROT   0
-#define BAD_PROT    CIFS_PROT+1
+#endif
+#define POSIX_PROT  CIFS_PROT+1
+#define BAD_PROT 0xFFFF
 
 /* SMB command codes */
 /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
 /*
  * Size of the session key (crypto key encrypted with the password
  */
-#define CIFS_SESSION_KEY_SIZE (24)
+#define CIFS_SESS_KEY_SIZE (24)
 
 /*
  * Maximum user name length
@@ -400,6 +406,29 @@ typedef struct negotiate_req {
        unsigned char DialectsArray[1];
 } __attribute__((packed)) NEGOTIATE_REQ;
 
+/* Dialect index is 13 for LANMAN */
+
+typedef struct lanman_neg_rsp {
+       struct smb_hdr hdr;     /* wct = 13 */
+       __le16 DialectIndex;
+       __le16 SecurityMode;
+       __le16 MaxBufSize;
+       __le16 MaxMpxCount;
+       __le16 MaxNumberVcs;
+       __le16 RawMode;
+       __le32 SessionKey;
+       __le32 ServerTime;
+       __le16 ServerTimeZone;
+       __le16 EncryptionKeyLength;
+       __le16 Reserved;
+       __u16  ByteCount;
+       unsigned char EncryptionKey[1];
+} __attribute__((packed)) LANMAN_NEG_RSP;
+
+#define READ_RAW_ENABLE 1
+#define WRITE_RAW_ENABLE 2
+#define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE)
+
 typedef struct negotiate_rsp {
        struct smb_hdr hdr;     /* wct = 17 */
        __le16 DialectIndex;
@@ -509,7 +538,7 @@ typedef union smb_com_session_setup_andx {
 /*      unsigned char  * NativeOS;      */
 /*     unsigned char  * NativeLanMan;  */
 /*      unsigned char  * PrimaryDomain; */
-       } __attribute__((packed)) resp;                 /* NTLM response format (with or without extended security */
+       } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/
 
        struct {                /* request format */
                struct smb_hdr hdr;     /* wct = 10 */
@@ -520,8 +549,8 @@ typedef union smb_com_session_setup_andx {
                __le16 MaxMpxCount;
                __le16 VcNumber;
                __u32 SessionKey;
-               __le16 PassswordLength;
-               __u32 Reserved;
+               __le16 PasswordLength;
+               __u32 Reserved; /* encrypt key len and offset */
                __le16 ByteCount;
                unsigned char AccountPassword[1];       /* followed by */
                /* STRING AccountName */
@@ -543,6 +572,26 @@ typedef union smb_com_session_setup_andx {
        } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */
 } __attribute__((packed)) SESSION_SETUP_ANDX;
 
+/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */
+
+struct ntlmssp2_name {
+       __le16 type;
+       __le16 length;
+/*     char   name[length]; */
+} __attribute__((packed));
+
+struct ntlmv2_resp {
+       char ntlmv2_hash[CIFS_ENCPWD_SIZE];
+       __le32 blob_signature;
+       __u32  reserved;
+       __le64  time;
+       __u64  client_chal; /* random */
+       __u32  reserved2;
+       struct ntlmssp2_name names[1];
+       /* array of name entries could follow ending in minimum 4 byte struct */
+} __attribute__((packed));
+
+
 #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
 
 /* Capabilities bits (for NTLM SessSetup request) */
@@ -573,7 +622,9 @@ typedef struct smb_com_tconx_req {
 } __attribute__((packed)) TCONX_REQ;
 
 typedef struct smb_com_tconx_rsp {
-       struct smb_hdr hdr;     /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */
+       struct smb_hdr hdr;     /* wct = 3 note that Win2000 has sent wct = 7
+                                in some cases on responses. Four unspecified
+                                words followed OptionalSupport */
        __u8 AndXCommand;
        __u8 AndXReserved;
        __le16 AndXOffset;
@@ -1323,6 +1374,9 @@ struct smb_t2_rsp {
 #define SMB_FILE_MAXIMUM_INFO           0x40d
 
 /* Find File infolevels */
+#define SMB_FIND_FILE_INFO_STANDARD       0x001
+#define SMB_FIND_FILE_QUERY_EA_SIZE       0x002
+#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003
 #define SMB_FIND_FILE_DIRECTORY_INFO      0x101
 #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
 #define SMB_FIND_FILE_NAMES_INFO          0x103
@@ -1844,13 +1898,13 @@ typedef struct {
 typedef struct {
        __le32 DeviceType;
        __le32 DeviceCharacteristics;
-} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO;     /* device info, level 0x104 */
+} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
 
 typedef struct {
        __le32 Attributes;
        __le32 MaxPathNameComponentLength;
        __le32 FileSystemNameLen;
-       char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
+       char FileSystemName[52]; /* do not have to save this - get subset? */
 } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
 
 /******************************************************************************/
@@ -1947,7 +2001,8 @@ typedef struct {
 
 struct file_allocation_info {
        __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
-} __attribute__((packed));     /* size used on disk, level 0x103 for set, 0x105 for query */
+} __attribute__((packed));     /* size used on disk, for level 0x103 for set,
+                                  0x105 for query */
 
 struct file_end_of_file_info {
        __le64 FileSize;                /* offset to end of file */
@@ -2054,7 +2109,7 @@ typedef struct {
        __le32 ExtFileAttributes;
        __le32 FileNameLength;
        char FileName[1];
-} __attribute__((packed)) FILE_DIRECTORY_INFO;   /* level 0x101 FF response data area */
+} __attribute__((packed)) FILE_DIRECTORY_INFO;   /* level 0x101 FF resp data */
 
 typedef struct {
        __le32 NextEntryOffset;
@@ -2069,7 +2124,7 @@ typedef struct {
        __le32 FileNameLength;
        __le32 EaSize; /* length of the xattrs */
        char FileName[1];
-} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO;   /* level 0x102 FF response data area */
+} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */
 
 typedef struct {
        __le32 NextEntryOffset;
@@ -2086,7 +2141,7 @@ typedef struct {
        __le32 Reserved;
        __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
        char FileName[1];
-} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO;   /* level 0x105 FF response data area */
+} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */
 
 typedef struct {
        __le32 NextEntryOffset;
@@ -2104,7 +2159,22 @@ typedef struct {
        __u8   Reserved;
        __u8   ShortName[12];
        char FileName[1];
-} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO;   /* level 0x104 FF response data area */
+} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */
+
+typedef struct {
+       __u32  ResumeKey;
+       __le16 CreationDate; /* SMB Date */
+       __le16 CreationTime; /* SMB Time */
+       __le16 LastAccessDate;
+       __le16 LastAccessTime;
+       __le16 LastWriteDate;
+       __le16 LastWriteTime;
+       __le32 DataSize; /* File Size (EOF) */
+       __le32 AllocationSize;
+       __le16 Attributes; /* verify not u32 */
+       __u8   FileNameLength;
+       char FileName[1];
+} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */
 
 
 struct win_dev {
index 310ea2f0e0bfd27d6eacd91ffe0f695a0ca89322..a5ddc62d6fe6e2c09f4b70dcbf4f7a69a22c9b17 100644 (file)
@@ -64,14 +64,12 @@ extern int map_smb_to_linux_error(struct smb_hdr *smb);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
                            const struct cifsTconInfo *, int /* length of
                            fixed section (word count) in two byte units */);
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
                                struct cifsSesInfo *ses,
                                void ** request_buf);
 extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
-                            const int stage, int * pNTLMv2_flg,
+                            const int stage, 
                             const struct nls_table *nls_cp);
-#endif
 extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
                                                 struct cifsTconInfo *);
@@ -285,8 +283,14 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
 extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
        __u32 expected_sequence_number);
 extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
-extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
-extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
+extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, 
+                       const struct nls_table *);
+extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * );
+extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, 
+                            const struct nls_table *);
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
+#endif /* CIFS_WEAK_PW_HASH */
 extern int CIFSSMBCopy(int xid,
                        struct cifsTconInfo *source_tcon,
                        const char *fromName,
index 925881e00ff210e08822cc456337be1734f801d8..19678c575dfc4bcc786d158a20f56a450caccec1 100644 (file)
@@ -44,8 +44,11 @@ static struct {
        int index;
        char *name;
 } protocols[] = {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+       {LANMAN_PROT, "\2LM1.2X002"},
+#endif /* weak password hashing for legacy clients */
        {CIFS_PROT, "\2NT LM 0.12"}, 
-       {CIFS_PROT, "\2POSIX 2"},
+       {POSIX_PROT, "\2POSIX 2"},
        {BAD_PROT, "\2"}
 };
 #else
@@ -53,11 +56,29 @@ static struct {
        int index;
        char *name;
 } protocols[] = {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+       {LANMAN_PROT, "\2LM1.2X002"},
+#endif /* weak password hashing for legacy clients */
        {CIFS_PROT, "\2NT LM 0.12"}, 
        {BAD_PROT, "\2"}
 };
 #endif
 
+/* define the number of elements in the cifs dialect array */
+#ifdef CONFIG_CIFS_POSIX
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 3
+#else
+#define CIFS_NUM_PROT 2
+#endif /* CIFS_WEAK_PW_HASH */
+#else /* not posix */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 2
+#else
+#define CIFS_NUM_PROT 1
+#endif /* CONFIG_CIFS_WEAK_PW_HASH */
+#endif /* CIFS_POSIX */
+
 
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
@@ -188,7 +209,6 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
        return rc;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL  
 int
 small_smb_init_no_tc(const int smb_command, const int wct, 
                     struct cifsSesInfo *ses, void **request_buf)
@@ -214,7 +234,6 @@ small_smb_init_no_tc(const int smb_command, const int wct,
 
        return rc;
 }
-#endif  /* CONFIG_CIFS_EXPERIMENTAL */
 
 /* If the return code is zero, this function must fill in request_buf pointer */
 static int
@@ -322,7 +341,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
     /* potential retries of smb operations it turns out we can determine */
     /* from the mid flags when the request buffer can be resent without  */
     /* having to use a second distinct buffer for the response */
-       *response_buf = *request_buf; 
+       if(response_buf)
+               *response_buf = *request_buf; 
 
        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
                        wct /*wct */ );
@@ -373,8 +393,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        NEGOTIATE_RSP *pSMBr;
        int rc = 0;
        int bytes_returned;
+       int i;
        struct TCP_Server_Info * server;
        u16 count;
+       unsigned int secFlags;
 
        if(ses->server)
                server = ses->server;
@@ -386,101 +408,200 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                      (void **) &pSMB, (void **) &pSMBr);
        if (rc)
                return rc;
+
+       /* if any of auth flags (ie not sign or seal) are overriden use them */
+       if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+               secFlags = ses->overrideSecFlg;
+       else /* if override flags set only sign/seal OR them with global auth */
+               secFlags = extended_security | ses->overrideSecFlg;
+
+       cFYI(1,("secFlags 0x%x",secFlags));
+
        pSMB->hdr.Mid = GetNextMid(server);
        pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
-       if (extended_security)
+       if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-
-       count = strlen(protocols[0].name) + 1;
-       strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
-    /* null guaranteed to be at end of source and target buffers anyway */
-
+       
+       count = 0;
+       for(i=0;i<CIFS_NUM_PROT;i++) {
+               strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
+               count += strlen(protocols[i].name) + 1;
+               /* null at end of source and target buffers anyway */
+       }
        pSMB->hdr.smb_buf_length += count;
        pSMB->ByteCount = cpu_to_le16(count);
 
        rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc == 0) {
-               server->secMode = pSMBr->SecurityMode;
-               if((server->secMode & SECMODE_USER) == 0)
-                       cFYI(1,("share mode security"));
-               server->secType = NTLM; /* BB override default for
-                                          NTLMv2 or kerberos v5 */
-               /* one byte - no need to convert this or EncryptionKeyLen
-                  from little endian */
-               server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
-               /* probably no need to store and check maxvcs */
-               server->maxBuf =
-                       min(le32_to_cpu(pSMBr->MaxBufferSize),
+       if (rc != 0) 
+               goto neg_err_exit;
+
+       cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
+       /* Check wct = 1 error case */
+       if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
+               /* core returns wct = 1, but we do not ask for core - otherwise
+               small wct just comes when dialect index is -1 indicating we 
+               could not negotiate a common dialect */
+               rc = -EOPNOTSUPP;
+               goto neg_err_exit;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH 
+       } else if((pSMBr->hdr.WordCount == 13)
+                       && (pSMBr->DialectIndex == LANMAN_PROT)) {
+               struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
+
+               if((secFlags & CIFSSEC_MAY_LANMAN) || 
+                       (secFlags & CIFSSEC_MAY_PLNTXT))
+                       server->secType = LANMAN;
+               else {
+                       cERROR(1, ("mount failed weak security disabled"
+                                  " in /proc/fs/cifs/SecurityFlags"));
+                       rc = -EOPNOTSUPP;
+                       goto neg_err_exit;
+               }       
+               server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
+               server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+               server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
+                               (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+               GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
+               /* even though we do not use raw we might as well set this
+               accurately, in case we ever find a need for it */
+               if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
+                       server->maxRw = 0xFF00;
+                       server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
+               } else {
+                       server->maxRw = 0;/* we do not need to use raw anyway */
+                       server->capabilities = CAP_MPX_MODE;
+               }
+               server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
+
+               /* BB get server time for time conversions and add
+               code to use it and timezone since this is not UTC */    
+
+               if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+                       memcpy(server->cryptKey, rsp->EncryptionKey,
+                               CIFS_CRYPTO_KEY_SIZE);
+               } else if (server->secMode & SECMODE_PW_ENCRYPT) {
+                       rc = -EIO; /* need cryptkey unless plain text */
+                       goto neg_err_exit;
+               }
+
+               cFYI(1,("LANMAN negotiated"));
+               /* we will not end up setting signing flags - as no signing
+               was in LANMAN and server did not return the flags on */
+               goto signing_check;
+#else /* weak security disabled */
+       } else if(pSMBr->hdr.WordCount == 13) {
+               cERROR(1,("mount failed, cifs module not built "
+                         "with CIFS_WEAK_PW_HASH support"));
+                       rc = -EOPNOTSUPP;
+#endif /* WEAK_PW_HASH */
+               goto neg_err_exit;
+       } else if(pSMBr->hdr.WordCount != 17) {
+               /* unknown wct */
+               rc = -EOPNOTSUPP;
+               goto neg_err_exit;
+       }
+       /* else wct == 17 NTLM */
+       server->secMode = pSMBr->SecurityMode;
+       if((server->secMode & SECMODE_USER) == 0)
+               cFYI(1,("share mode security"));
+
+       if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
+#endif /* CIFS_WEAK_PW_HASH */
+                       cERROR(1,("Server requests plain text password"
+                                 " but client support disabled"));
+
+       if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
+               server->secType = NTLMv2;
+       else if(secFlags & CIFSSEC_MAY_NTLM)
+               server->secType = NTLM;
+       else if(secFlags & CIFSSEC_MAY_NTLMV2)
+               server->secType = NTLMv2;
+       /* else krb5 ... any others ... */
+
+       /* one byte, so no need to convert this or EncryptionKeyLen from
+          little endian */
+       server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+       /* probably no need to store and check maxvcs */
+       server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
                        (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
-               server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
-               cFYI(0, ("Max buf = %d", ses->server->maxBuf));
-               GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
-               server->capabilities = le32_to_cpu(pSMBr->Capabilities);
-               server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
-        /* BB with UTC do we ever need to be using srvr timezone? */
-               if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
-                       memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
-                              CIFS_CRYPTO_KEY_SIZE);
-               } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
-                          && (pSMBr->EncryptionKeyLength == 0)) {
-                       /* decode security blob */
-               } else
-                       rc = -EIO;
+       server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
+       cFYI(0, ("Max buf = %d", ses->server->maxBuf));
+       GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
+       server->capabilities = le32_to_cpu(pSMBr->Capabilities);
+       server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
+       if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+               memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
+                      CIFS_CRYPTO_KEY_SIZE);
+       } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
+                       && (pSMBr->EncryptionKeyLength == 0)) {
+               /* decode security blob */
+       } else if (server->secMode & SECMODE_PW_ENCRYPT) {
+               rc = -EIO; /* no crypt key only if plain text pwd */
+               goto neg_err_exit;
+       }
 
-               /* BB might be helpful to save off the domain of server here */
+       /* BB might be helpful to save off the domain of server here */
 
-               if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
-                       (server->capabilities & CAP_EXTENDED_SECURITY)) {
-                       count = pSMBr->ByteCount;
-                       if (count < 16)
-                               rc = -EIO;
-                       else if (count == 16) {
-                               server->secType = RawNTLMSSP;
-                               if (server->socketUseCount.counter > 1) {
-                                       if (memcmp
-                                               (server->server_GUID,
-                                               pSMBr->u.extended_response.
-                                               GUID, 16) != 0) {
-                                               cFYI(1, ("server UID changed"));
-                                               memcpy(server->
-                                                       server_GUID,
-                                                       pSMBr->u.
-                                                       extended_response.
-                                                       GUID, 16);
-                                       }
-                               } else
+       if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
+               (server->capabilities & CAP_EXTENDED_SECURITY)) {
+               count = pSMBr->ByteCount;
+               if (count < 16)
+                       rc = -EIO;
+               else if (count == 16) {
+                       server->secType = RawNTLMSSP;
+                       if (server->socketUseCount.counter > 1) {
+                               if (memcmp(server->server_GUID,
+                                          pSMBr->u.extended_response.
+                                          GUID, 16) != 0) {
+                                       cFYI(1, ("server UID changed"));
                                        memcpy(server->server_GUID,
-                                              pSMBr->u.extended_response.
-                                              GUID, 16);
-                       } else {
-                               rc = decode_negTokenInit(pSMBr->u.
-                                                        extended_response.
-                                                        SecurityBlob,
-                                                        count - 16,
-                                                        &server->secType);
-                               if(rc == 1) {
-                               /* BB Need to fill struct for sessetup here */
-                                       rc = -EOPNOTSUPP;
-                               } else {
-                                       rc = -EINVAL;
+                                               pSMBr->u.extended_response.GUID,
+                                               16);
                                }
+                       } else
+                               memcpy(server->server_GUID,
+                                      pSMBr->u.extended_response.GUID, 16);
+               } else {
+                       rc = decode_negTokenInit(pSMBr->u.extended_response.
+                                                SecurityBlob,
+                                                count - 16,
+                                                &server->secType);
+                       if(rc == 1) {
+                       /* BB Need to fill struct for sessetup here */
+                               rc = -EOPNOTSUPP;
+                       } else {
+                               rc = -EINVAL;
                        }
-               } else
-                       server->capabilities &= ~CAP_EXTENDED_SECURITY;
-               if(sign_CIFS_PDUs == FALSE) {        
-                       if(server->secMode & SECMODE_SIGN_REQUIRED)
-                               cERROR(1,
-                                ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
-                       server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-               } else if(sign_CIFS_PDUs == 1) {
-                       if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-                               server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
                }
-                               
+       } else
+               server->capabilities &= ~CAP_EXTENDED_SECURITY;
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+signing_check:
+#endif
+       if(sign_CIFS_PDUs == FALSE) {        
+               if(server->secMode & SECMODE_SIGN_REQUIRED)
+                       cERROR(1,("Server requires "
+                                "/proc/fs/cifs/PacketSigningEnabled to be on"));
+               server->secMode &= 
+                       ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+       } else if(sign_CIFS_PDUs == 1) {
+               if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
+                       server->secMode &= 
+                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+       } else if(sign_CIFS_PDUs == 2) {
+               if((server->secMode & 
+                       (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
+                       cERROR(1,("signing required but server lacks support"));
+               }
        }
-       
+neg_err_exit:  
        cifs_buf_release(pSMB);
+
+       cFYI(1,("negprot rc %d",rc));
        return rc;
 }
 
@@ -2239,7 +2360,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                        }
                        symlinkinfo[buflen] = 0; /* just in case so the caller
                                        does not go off the end of the buffer */
-                       cFYI(1,("readlink result - %s ",symlinkinfo));
+                       cFYI(1,("readlink result - %s",symlinkinfo));
                }
        }
 qreparse_out:
index bae1479318d10fc6fd34a141a564aeb49252ba80..876eb9ef85fecd83ae57042b2114cdd3b8355e00 100644 (file)
@@ -49,8 +49,6 @@
 
 static DECLARE_COMPLETION(cifsd_complete);
 
-extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
-                      unsigned char *p24);
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
                         unsigned char *p24);
 
@@ -70,6 +68,7 @@ struct smb_vol {
        gid_t linux_gid;
        mode_t file_mode;
        mode_t dir_mode;
+       unsigned secFlg;
        unsigned rw:1;
        unsigned retry:1;
        unsigned intr:1;
@@ -83,12 +82,7 @@ struct smb_vol {
        unsigned remap:1;   /* set to remap seven reserved chars in filenames */
        unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
        unsigned sfu_emul:1;
-       unsigned krb5:1;
-       unsigned ntlm:1;
-       unsigned ntlmv2:1;
        unsigned nullauth:1; /* attempt to authenticate with null user */
-       unsigned sign:1;
-       unsigned seal:1;     /* encrypt */
        unsigned nocase;     /* request case insensitive filenames */
        unsigned nobrl;      /* disable sending byte range locks to srv */
        unsigned int rsize;
@@ -369,21 +363,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        continue;
                if (bigbuf == NULL) {
                        bigbuf = cifs_buf_get();
-                       if(bigbuf == NULL) {
-                               cERROR(1,("No memory for large SMB response"));
+                       if (!bigbuf) {
+                               cERROR(1, ("No memory for large SMB response"));
                                msleep(3000);
                                /* retry will check if exiting */
                                continue;
                        }
-               } else if(isLargeBuf) {
-                       /* we are reusing a dirtry large buf, clear its start */
+               } else if (isLargeBuf) {
+                       /* we are reusing a dirty large buf, clear its start */
                        memset(bigbuf, 0, sizeof (struct smb_hdr));
                }
 
                if (smallbuf == NULL) {
                        smallbuf = cifs_small_buf_get();
-                       if(smallbuf == NULL) {
-                               cERROR(1,("No memory for SMB response"));
+                       if (!smallbuf) {
+                               cERROR(1, ("No memory for SMB response"));
                                msleep(1000);
                                /* retry will check if exiting */
                                continue;
@@ -403,12 +397,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                    kernel_recvmsg(csocket, &smb_msg,
                                 &iov, 1, 4, 0 /* BB see socket.h flags */);
 
-               if(server->tcpStatus == CifsExiting) {
+               if (server->tcpStatus == CifsExiting) {
                        break;
                } else if (server->tcpStatus == CifsNeedReconnect) {
-                       cFYI(1,("Reconnect after server stopped responding"));
+                       cFYI(1, ("Reconnect after server stopped responding"));
                        cifs_reconnect(server);
-                       cFYI(1,("call to reconnect done"));
+                       cFYI(1, ("call to reconnect done"));
                        csocket = server->ssocket;
                        continue;
                } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
@@ -417,15 +411,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                tcpStatus CifsNeedReconnect if server hung */
                        continue;
                } else if (length <= 0) {
-                       if(server->tcpStatus == CifsNew) {
-                               cFYI(1,("tcp session abend after SMBnegprot"));
+                       if (server->tcpStatus == CifsNew) {
+                               cFYI(1, ("tcp session abend after SMBnegprot"));
                                /* some servers kill the TCP session rather than
                                   returning an SMB negprot error, in which
                                   case reconnecting here is not going to help,
                                   and so simply return error to mount */
                                break;
                        }
-                       if(length == -EINTR) { 
+                       if (!try_to_freeze() && (length == -EINTR)) {
                                cFYI(1,("cifsd thread killed"));
                                break;
                        }
@@ -585,9 +579,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                                /* merge response - fix up 1st*/
                                                if(coalesce_t2(smb_buffer, 
                                                        mid_entry->resp_buf)) {
+                                                       mid_entry->multiRsp = 1;
                                                        break;
                                                } else {
                                                        /* all parts received */
+                                                       mid_entry->multiEnd = 1;
                                                        goto multi_t2_fnd; 
                                                }
                                        } else {
@@ -632,9 +628,14 @@ multi_t2_fnd:
                        wake_up_process(task_to_wake);
                } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
                    && (isMultiRsp == FALSE)) {                          
-                       cERROR(1, ("No task to wake, unknown frame rcvd!"));
+                       cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
                        cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
                                      sizeof(struct smb_hdr));
+#ifdef CONFIG_CIFS_DEBUG2
+                       cifs_dump_detail(smb_buffer);
+                       cifs_dump_mids(server);
+#endif /* CIFS_DEBUG2 */
+                       
                }
        } /* end while !EXITING */
 
@@ -784,7 +785,6 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
        vol->rw = TRUE;
-       vol->ntlm = TRUE;
        /* default is always to request posix paths. */
        vol->posix_paths = 1;
 
@@ -915,30 +915,35 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                cERROR(1,("no security value specified"));
                                 continue;
                         } else if (strnicmp(value, "krb5i", 5) == 0) {
-                               vol->sign = 1;
-                               vol->krb5 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_KRB5 | 
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "krb5p", 5) == 0) {
-                               /* vol->seal = 1; 
-                                  vol->krb5 = 1; */
+                               /* vol->secFlg |= CIFSSEC_MUST_SEAL | 
+                                       CIFSSEC_MAY_KRB5; */ 
                                cERROR(1,("Krb5 cifs privacy not supported"));
                                return 1;
                        } else if (strnicmp(value, "krb5", 4) == 0) {
-                               vol->krb5 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_KRB5;
                        } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
-                               vol->ntlmv2 = 1;
-                               vol->sign = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlmv2", 6) == 0) {
-                               vol->ntlmv2 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
                        } else if (strnicmp(value, "ntlmi", 5) == 0) {
-                               vol->ntlm = 1;
-                               vol->sign = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLM |
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlm", 4) == 0) {
                                /* ntlm is default so can be turned off too */
-                               vol->ntlm = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLM;
                        } else if (strnicmp(value, "nontlm", 6) == 0) {
-                               vol->ntlm = 0;
+                               /* BB is there a better way to do this? */
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+                       } else if (strnicmp(value, "lanman", 6) == 0) {
+                                vol->secFlg |= CIFSSEC_MAY_LANMAN;
+#endif
                        } else if (strnicmp(value, "none", 4) == 0) {
-                               vol->nullauth = 1; 
+                               vol->nullauth = 1;
                         } else {
                                 cERROR(1,("bad security option: %s", value));
                                 return 1;
@@ -976,7 +981,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        }
                        /* BB are there cases in which a comma can be valid in
                        a domain name and need special handling? */
-                       if (strnlen(value, 65) < 65) {
+                       if (strnlen(value, 256) < 256) {
                                vol->domainname = value;
                                cFYI(1, ("Domain name set"));
                        } else {
@@ -1168,6 +1173,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        vol->no_psx_acl = 0;
                } else if (strnicmp(data, "noacl",5) == 0) {
                        vol->no_psx_acl = 1;
+               } else if (strnicmp(data, "sign",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SIGN;
+/*             } else if (strnicmp(data, "seal",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SEAL; */
                } else if (strnicmp(data, "direct",6) == 0) {
                        vol->direct_io = 1;
                } else if (strnicmp(data, "forcedirectio",13) == 0) {
@@ -1762,11 +1771,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        if (volume_info.username)
                                strncpy(pSesInfo->userName,
                                        volume_info.username,MAX_USERNAME_SIZE);
-                       if (volume_info.domainname)
-                               strncpy(pSesInfo->domainName,
-                                       volume_info.domainname,MAX_USERNAME_SIZE);
+                       if (volume_info.domainname) {
+                               int len = strlen(volume_info.domainname);
+                               pSesInfo->domainName = 
+                                       kmalloc(len + 1, GFP_KERNEL);
+                               if(pSesInfo->domainName)
+                                       strcpy(pSesInfo->domainName,
+                                               volume_info.domainname);
+                       }
                        pSesInfo->linux_uid = volume_info.linux_uid;
+                       pSesInfo->overrideSecFlg = volume_info.secFlg;
                        down(&pSesInfo->sesSem);
+                       /* BB FIXME need to pass vol->secFlgs BB */
                        rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
                        up(&pSesInfo->sesSem);
                        if(!rc)
@@ -1980,7 +1996,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
 static int
 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-             char session_key[CIFS_SESSION_KEY_SIZE],
+             char session_key[CIFS_SESS_KEY_SIZE],
              const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -2038,15 +2054,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
 
        pSMB->req_no_secext.CaseInsensitivePasswordLength = 
-               cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+               cpu_to_le16(CIFS_SESS_KEY_SIZE);
 
        pSMB->req_no_secext.CaseSensitivePasswordLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        bcc_ptr = pByteArea(smb_buffer);
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
@@ -2054,7 +2070,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        bcc_ptr++;
                }
                if(user == NULL)
-                       bytes_returned = 0; /* skill null user */
+                       bytes_returned = 0; /* skip null user */
                else
                        bytes_returned =
                                cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
@@ -2162,8 +2178,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (remaining_words > 0) {
                                        len = UniStrnlen((wchar_t *)bcc_ptr,
                                                         remaining_words-1);
-                                       if(ses->serverNOS)
-                                               kfree(ses->serverNOS);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
@@ -2203,12 +2218,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        /* if these kcallocs fail not much we
                                           can do, but better to not fail the
                                           sesssetup itself */
-                                       if(ses->serverDomain)
-                                               kfree(ses->serverDomain);
+                                       kfree(ses->serverDomain);
                                        ses->serverDomain =
                                            kzalloc(2, GFP_KERNEL);
-                                       if(ses->serverNOS)
-                                               kfree(ses->serverNOS);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS =
                                            kzalloc(2, GFP_KERNEL);
                                }
@@ -2217,8 +2230,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (((long) bcc_ptr + len) - (long)
                                    pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
-                                       if(ses->serverOS)
-                                               kfree(ses->serverOS);
+                                       kfree(ses->serverOS);
                                        ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverOS == NULL)
                                                goto sesssetup_nomem;
@@ -2229,8 +2241,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       if(ses->serverNOS)
-                                               kfree(ses->serverNOS);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
@@ -2273,292 +2284,6 @@ sesssetup_nomem:        /* do not return an error on nomem for the info strings,
        return rc;
 }
 
-static int
-CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-               char *SecurityBlob,int SecurityBlobLength,
-               const struct nls_table *nls_codepage)
-{
-       struct smb_hdr *smb_buffer;
-       struct smb_hdr *smb_buffer_response;
-       SESSION_SETUP_ANDX *pSMB;
-       SESSION_SETUP_ANDX *pSMBr;
-       char *bcc_ptr;
-       char *user;
-       char *domain;
-       int rc = 0;
-       int remaining_words = 0;
-       int bytes_returned = 0;
-       int len;
-       __u32 capabilities;
-       __u16 count;
-
-       cFYI(1, ("In spnego sesssetup "));
-       if(ses == NULL)
-               return -EINVAL;
-       user = ses->userName;
-       domain = ses->domainName;
-
-       smb_buffer = cifs_buf_get();
-       if (smb_buffer == NULL) {
-               return -ENOMEM;
-       }
-       smb_buffer_response = smb_buffer;
-       pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
-
-       /* send SMBsessionSetup here */
-       header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
-                       NULL /* no tCon exists yet */ , 12 /* wct */ );
-
-       smb_buffer->Mid = GetNextMid(ses->server);
-       pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       pSMB->req.AndXCommand = 0xFF;
-       if(ses->server->maxBuf > 64*1024)
-               ses->server->maxBuf = (64*1023);
-       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
-       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
-
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-               smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
-       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
-           CAP_EXTENDED_SECURITY;
-       if (ses->capabilities & CAP_UNICODE) {
-               smb_buffer->Flags2 |= SMBFLG2_UNICODE;
-               capabilities |= CAP_UNICODE;
-       }
-       if (ses->capabilities & CAP_STATUS32) {
-               smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-               capabilities |= CAP_STATUS32;
-       }
-       if (ses->capabilities & CAP_DFS) {
-               smb_buffer->Flags2 |= SMBFLG2_DFS;
-               capabilities |= CAP_DFS;
-       }
-       pSMB->req.Capabilities = cpu_to_le32(capabilities);
-
-       pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
-       bcc_ptr = pByteArea(smb_buffer);
-       memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
-       bcc_ptr += SecurityBlobLength;
-
-       if (ses->capabilities & CAP_UNICODE) {
-               if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode strings */
-                       *bcc_ptr = 0;
-                       bcc_ptr++;
-               }
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;  /* convert num of 16 bit words to bytes */
-               bcc_ptr += 2;   /* trailing null */
-               if (domain == NULL)
-                       bytes_returned =
-                           cifs_strtoUCS((__le16 *) bcc_ptr,
-                                         "CIFS_LINUX_DOM", 32, nls_codepage);
-               else
-                       bytes_returned =
-                           cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
-                                         nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
-                                 32, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
-                                 nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
-                                 64, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-       } else {
-               strncpy(bcc_ptr, user, 200);
-               bcc_ptr += strnlen(user, 200);
-               *bcc_ptr = 0;
-               bcc_ptr++;
-               if (domain == NULL) {
-                       strcpy(bcc_ptr, "CIFS_LINUX_DOM");
-                       bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
-               } else {
-                       strncpy(bcc_ptr, domain, 64);
-                       bcc_ptr += strnlen(domain, 64);
-                       *bcc_ptr = 0;
-                       bcc_ptr++;
-               }
-               strcpy(bcc_ptr, "Linux version ");
-               bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, system_utsname.release);
-               bcc_ptr += strlen(system_utsname.release) + 1;
-               strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
-               bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
-       }
-       count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
-       smb_buffer->smb_buf_length += count;
-       pSMB->req.ByteCount = cpu_to_le16(count);
-
-       rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
-                        &bytes_returned, 1);
-       if (rc) {
-/*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
-       } else if ((smb_buffer_response->WordCount == 3)
-                  || (smb_buffer_response->WordCount == 4)) {
-               __u16 action = le16_to_cpu(pSMBr->resp.Action);
-               __u16 blob_len =
-                   le16_to_cpu(pSMBr->resp.SecurityBlobLength);
-               if (action & GUEST_LOGIN)
-                       cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
-               if (ses) {
-                       ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
-                       cFYI(1, ("UID = %d ", ses->Suid));
-                       bcc_ptr = pByteArea(smb_buffer_response);       /* response can have either 3 or 4 word count - Samba sends 3 */
-
-                       /* BB Fix below to make endian neutral !! */
-
-                       if ((pSMBr->resp.hdr.WordCount == 3)
-                           || ((pSMBr->resp.hdr.WordCount == 4)
-                               && (blob_len <
-                                   pSMBr->resp.ByteCount))) {
-                               if (pSMBr->resp.hdr.WordCount == 4) {
-                                       bcc_ptr +=
-                                           blob_len;
-                                       cFYI(1,
-                                            ("Security Blob Length %d ",
-                                             blob_len));
-                               }
-
-                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
-                                       if ((long) (bcc_ptr) % 2) {
-                                               remaining_words =
-                                                   (BCC(smb_buffer_response)
-                                                    - 1) / 2;
-                                               bcc_ptr++;      /* Unicode strings must be word aligned */
-                                       } else {
-                                               remaining_words =
-                                                   BCC
-                                                   (smb_buffer_response) / 2;
-                                       }
-                                       len =
-                                           UniStrnlen((wchar_t *) bcc_ptr,
-                                                      remaining_words - 1);
-/* We look for obvious messed up bcc or strings in response so we do not go off
-   the end since (at least) WIN2K and Windows XP have a major bug in not null
-   terminating last Unicode string in response  */
-                                       if(ses->serverOS)
-                                               kfree(ses->serverOS);
-                                       ses->serverOS =
-                                           kzalloc(2 * (len + 1), GFP_KERNEL);
-                                       cifs_strfromUCS_le(ses->serverOS,
-                                                          (__le16 *)
-                                                          bcc_ptr, len,
-                                                          nls_codepage);
-                                       bcc_ptr += 2 * (len + 1);
-                                       remaining_words -= len + 1;
-                                       ses->serverOS[2 * len] = 0;
-                                       ses->serverOS[1 + (2 * len)] = 0;
-                                       if (remaining_words > 0) {
-                                               len = UniStrnlen((wchar_t *)bcc_ptr,
-                                                                remaining_words
-                                                                - 1);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
-                                               ses->serverNOS =
-                                                   kzalloc(2 * (len + 1),
-                                                           GFP_KERNEL);
-                                               cifs_strfromUCS_le(ses->serverNOS,
-                                                                  (__le16 *)bcc_ptr,
-                                                                  len,
-                                                                  nls_codepage);
-                                               bcc_ptr += 2 * (len + 1);
-                                               ses->serverNOS[2 * len] = 0;
-                                               ses->serverNOS[1 + (2 * len)] = 0;
-                                               remaining_words -= len + 1;
-                                               if (remaining_words > 0) {
-                                                       len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
-                     /* last string not null terminated (e.g.Windows XP/2000) */
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
-                                                       ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
-                                                       cifs_strfromUCS_le(ses->serverDomain,
-                                                            (__le16 *)bcc_ptr, 
-                                                            len, nls_codepage);
-                                                       bcc_ptr += 2*(len+1);
-                                                       ses->serverDomain[2*len] = 0;
-                                                       ses->serverDomain[1+(2*len)] = 0;
-                                               } /* else no more room so create dummy domain string */
-                                               else {
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
-                                                       ses->serverDomain =
-                                                           kzalloc(2,GFP_KERNEL);
-                                               }
-                                       } else {/* no room use dummy domain&NOS */
-                                               if(ses->serverDomain)
-                                                       kfree(ses->serverDomain);
-                                               ses->serverDomain = kzalloc(2, GFP_KERNEL);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
-                                               ses->serverNOS = kzalloc(2, GFP_KERNEL);
-                                       }
-                               } else {        /* ASCII */
-
-                                       len = strnlen(bcc_ptr, 1024);
-                                       if (((long) bcc_ptr + len) - (long)
-                                           pByteArea(smb_buffer_response)
-                                           <= BCC(smb_buffer_response)) {
-                                               if(ses->serverOS)
-                                                       kfree(ses->serverOS);
-                                               ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
-                                               strncpy(ses->serverOS, bcc_ptr, len);
-
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0; /* null terminate the string */
-                                               bcc_ptr++;
-
-                                               len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
-                                               ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
-                                               strncpy(ses->serverNOS, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
-
-                                               len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverDomain)
-                                                       kfree(ses->serverDomain);
-                                               ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
-                                               strncpy(ses->serverDomain, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
-                                       } else
-                                               cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb ",
-                                                     len));
-                               }
-                       } else {
-                               cERROR(1,
-                                      (" Security Blob Length extends beyond end of SMB"));
-                       }
-               } else {
-                       cERROR(1, ("No session structure passed in."));
-               }
-       } else {
-               cERROR(1,
-                      (" Invalid Word count %d: ",
-                       smb_buffer_response->WordCount));
-               rc = -EIO;
-       }
-
-       if (smb_buffer)
-               cifs_buf_release(smb_buffer);
-
-       return rc;
-}
-
 static int
 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                              struct cifsSesInfo *ses, int * pNTLMv2_flag,
@@ -2635,8 +2360,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
            /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
        if(sign_CIFS_PDUs)
                negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
-       if(ntlmv2_support)
-               negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
+/*     if(ntlmv2_support)
+               negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
        /* setup pointers to domain name and workstation name */
        bcc_ptr += SecurityBlobLength;
 
@@ -2783,8 +2508,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
@@ -2802,8 +2526,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                if (remaining_words > 0) {
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
+                                                       kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2 *
                                                                    (len +
@@ -2822,19 +2545,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
                                                else {
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
+                                                       kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2,
                                                                    GFP_KERNEL);
                                                }
                                        } else {        /* no room so create dummy domain and NOS string */
-                                               if(ses->serverDomain);
-                                                       kfree(ses->serverDomain);
+                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
                                                    kzalloc(2, GFP_KERNEL);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2, GFP_KERNEL);
                                        }
@@ -2856,8 +2576,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2867,8 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverDomain)
-                                                       kfree(ses->serverDomain);
+                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2994,14 +2712,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        SecurityBlob->LmChallengeResponse.Buffer = 0;
 
        SecurityBlob->NtChallengeResponse.Length =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.MaximumLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
+       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.Buffer =
            cpu_to_le32(SecurityBlobLength);
-       SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       SecurityBlobLength += CIFS_SESS_KEY_SIZE;
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if (domain == NULL) {
@@ -3190,8 +2908,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
@@ -3244,8 +2961,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                if(ses->serverDomain)
                                                        kfree(ses->serverDomain);
                                                ses->serverDomain = kzalloc(2, GFP_KERNEL);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS = kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
@@ -3263,8 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);  
                                                bcc_ptr += len;
@@ -3340,22 +3055,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        bcc_ptr = &pSMB->Password[0];
        if((ses->server->secMode) & SECMODE_USER) {
                pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
+               *bcc_ptr = 0; /* password is null byte */
                bcc_ptr++;              /* skip password */
+               /* already aligned so no need to do it below */
        } else {
-               pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+               pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
                /* BB FIXME add code to fail this if NTLMv2 or Kerberos
                   specified as required (when that support is added to
                   the vfs in the future) as only NTLM or the much
-                  weaker LANMAN (which we do not send) is accepted
+                  weaker LANMAN (which we do not send by default) is accepted
                   by Samba (not sure whether other servers allow
                   NTLMv2 password here) */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               if((extended_security & CIFSSEC_MAY_LANMAN) && 
+                       (ses->server->secType == LANMAN))
+                       calc_lanman_hash(ses, bcc_ptr);
+               else
+#endif /* CIFS_WEAK_PW_HASH */
                SMBNTencrypt(ses->password,
                             ses->server->cryptKey,
                             bcc_ptr);
 
-               bcc_ptr += CIFS_SESSION_KEY_SIZE;
-               *bcc_ptr = 0;
-               bcc_ptr++; /* align */
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               if(ses->capabilities & CAP_UNICODE) {
+                       /* must align unicode strings */
+                       *bcc_ptr = 0; /* null byte password */
+                       bcc_ptr++;
+               }
        }
 
        if(ses->server->secMode & 
@@ -3429,7 +3155,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                        }
                        /* else do not bother copying these informational fields */
                }
-               tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+               if(smb_buffer_response->WordCount == 3)
+                       tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+               else
+                       tcon->Flags = 0;
                cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
        } else if ((rc == 0) && tcon == NULL) {
         /* all we need to save for IPC$ connection */
@@ -3494,7 +3223,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                           struct nls_table * nls_info)
 {
        int rc = 0;
-       char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+       char ntlm_session_key[CIFS_SESS_KEY_SIZE];
        int ntlmv2_flag = FALSE;
        int first_time = 0;
 
@@ -3526,20 +3255,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
                        pSesInfo->server->timeZone));
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-               if(experimEnabled > 1)
-                       rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */,
-                                           &ntlmv2_flag, nls_info);    
-               else
-#endif
-               if (extended_security
+               if(experimEnabled < 2)
+                       rc = CIFS_SessSetup(xid, pSesInfo,
+                                           first_time, nls_info);
+               else if (extended_security
                                && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
-                       cFYI(1, ("New style sesssetup"));
-                       rc = CIFSSpnegoSessSetup(xid, pSesInfo,
-                               NULL /* security blob */, 
-                               0 /* blob length */,
-                               nls_info);
+                       rc = -EOPNOTSUPP;
                } else if (extended_security
                           && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                           && (pSesInfo->server->secType == RawNTLMSSP)) {
index 82315edc77d7daaaaaca6865ca44e4946807190c..ba4cbe9b0684dd0a6ae66d65f8486462ab80e778 100644 (file)
@@ -113,7 +113,7 @@ cifs_bp_rename_retry:
        full_path[namelen+2] = 0;
 BB remove above eight lines BB */
 
-/* Inode operations in similar order to how they appear in the Linux file fs.h */
+/* Inode operations in similar order to how they appear in Linux file fs.h */
 
 int
 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
@@ -178,11 +178,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                FreeXid(xid);
                return -ENOMEM;
        }
-
-       rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
+       if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) 
+               rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
                         desiredAccess, CREATE_NOT_DIR,
                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       else
+               rc = -EIO; /* no NT SMB support fall into legacy open below */
+
        if(rc == -EIO) {
                /* old server, retry the open legacy style */
                rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
@@ -191,7 +194,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        } 
        if (rc) {
-               cFYI(1, ("cifs_create returned 0x%x ", rc));
+               cFYI(1, ("cifs_create returned 0x%x", rc));
        } else {
                /* If Open reported that we actually created a file
                then we now have to set the mode if possible */
@@ -369,6 +372,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                                         cifs_sb->mnt_cifs_flags & 
                                            CIFS_MOUNT_MAP_SPECIAL_CHR);
 
+                       /* BB FIXME - add handling for backlevel servers
+                          which need legacy open and check for all
+                          calls to SMBOpen for fallback to 
+                          SMBLeagcyOpen */
                        if(!rc) {
                                /* BB Do not bother to decode buf since no
                                   local inode yet to put timestamps in,
index 633a938113287f2d0a75c6ba58953e800b755747..d91a3d44e9e30ce1f36b67b650482212355d8629 100644 (file)
@@ -91,14 +91,14 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
        if(full_path == NULL) {
                rc = -ENOMEM;
        } else {
-               cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */
+               cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg));
                rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, 
                        GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
                        &netfid, &oplock,NULL, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
                /* BB fixme - add this handle to a notify handle list */
                if(rc) {
-                       cERROR(1,("Could not open directory for notify"));  /* BB remove BB */
+                       cFYI(1,("Could not open directory for notify"));
                } else {
                        filter = convert_to_cifs_notify_flags(arg);
                        if(filter != 0) {
index b4a18c1cab0a878dca81359c032a8f8b7f2bf83b..5861eb42e6260135ff491f95512e961e60c3e11a 100644 (file)
@@ -110,7 +110,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
                         &pCifsInode->openFileList);
        }
        write_unlock(&GlobalSMBSeslock);
-       write_unlock(&file->f_owner.lock);
        if (pCifsInode->clientCanCacheRead) {
                /* we have the inode open somewhere else
                   no need to discard cache data */
@@ -201,7 +200,7 @@ int cifs_open(struct inode *inode, struct file *file)
                } else {
                        if (file->f_flags & O_EXCL)
                                cERROR(1, ("could not find file instance for "
-                                          "new file %p ", file));
+                                          "new file %p", file));
                }
        }
 
@@ -260,10 +259,15 @@ int cifs_open(struct inode *inode, struct file *file)
                rc = -ENOMEM;
                goto out;
        }
-       rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
-                        CREATE_NOT_DIR, &netfid, &oplock, buf,
+
+       if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
+               rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 
+                        desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
                                 & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       else
+               rc = -EIO; /* no NT SMB support fall into legacy open below */
+
        if (rc == -EIO) {
                /* Old server, try legacy style OpenX */
                rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
@@ -272,7 +276,7 @@ int cifs_open(struct inode *inode, struct file *file)
                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
        }
        if (rc) {
-               cFYI(1, ("cifs_open returned 0x%x ", rc));
+               cFYI(1, ("cifs_open returned 0x%x", rc));
                goto out;
        }
        file->private_data =
@@ -282,7 +286,6 @@ int cifs_open(struct inode *inode, struct file *file)
                goto out;
        }
        pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
-       write_lock(&file->f_owner.lock);
        write_lock(&GlobalSMBSeslock);
        list_add(&pCifsFile->tlist, &pTcon->openFileList);
 
@@ -293,7 +296,6 @@ int cifs_open(struct inode *inode, struct file *file)
                                            &oplock, buf, full_path, xid);
        } else {
                write_unlock(&GlobalSMBSeslock);
-               write_unlock(&file->f_owner.lock);
        }
 
        if (oplock & CIFS_CREATE_ACTION) {           
@@ -409,8 +411,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
                up(&pCifsFile->fh_sem);
-               cFYI(1, ("cifs_open returned 0x%x ", rc));
-               cFYI(1, ("oplock: %d ", oplock));
+               cFYI(1, ("cifs_open returned 0x%x", rc));
+               cFYI(1, ("oplock: %d", oplock));
        } else {
                pCifsFile->netfid = netfid;
                pCifsFile->invalidHandle = FALSE;
@@ -472,7 +474,6 @@ int cifs_close(struct inode *inode, struct file *file)
        pTcon = cifs_sb->tcon;
        if (pSMBFile) {
                pSMBFile->closePend = TRUE;
-               write_lock(&file->f_owner.lock);
                if (pTcon) {
                        /* no sense reconnecting to close a file that is
                           already closed */
@@ -487,23 +488,18 @@ int cifs_close(struct inode *inode, struct file *file)
                                        the struct would be in each open file,
                                        but this should give enough time to 
                                        clear the socket */
-                                       write_unlock(&file->f_owner.lock);
                                        cERROR(1,("close with pending writes"));
                                        msleep(timeout);
-                                       write_lock(&file->f_owner.lock);
                                        timeout *= 4;
                                } 
-                               write_unlock(&file->f_owner.lock);
                                rc = CIFSSMBClose(xid, pTcon,
                                                  pSMBFile->netfid);
-                               write_lock(&file->f_owner.lock);
                        }
                }
                write_lock(&GlobalSMBSeslock);
                list_del(&pSMBFile->flist);
                list_del(&pSMBFile->tlist);
                write_unlock(&GlobalSMBSeslock);
-               write_unlock(&file->f_owner.lock);
                kfree(pSMBFile->search_resume_name);
                kfree(file->private_data);
                file->private_data = NULL;
@@ -531,7 +527,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
            (struct cifsFileInfo *)file->private_data;
        char *ptmp;
 
-       cFYI(1, ("Closedir inode = 0x%p with ", inode));
+       cFYI(1, ("Closedir inode = 0x%p", inode));
 
        xid = GetXid();
 
@@ -605,7 +601,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
        }
        if (pfLock->fl_flags & FL_ACCESS)
                cFYI(1, ("Process suspended by mandatory locking - "
-                        "not implemented yet "));
+                        "not implemented yet"));
        if (pfLock->fl_flags & FL_LEASE)
                cFYI(1, ("Lease on file - not implemented yet"));
        if (pfLock->fl_flags & 
@@ -1375,7 +1371,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 
        xid = GetXid();
 
-       cFYI(1, ("Sync file - name: %s datasync: 0x%x ", 
+       cFYI(1, ("Sync file - name: %s datasync: 0x%x", 
                dentry->d_name.name, datasync));
        
        rc = filemap_fdatawrite(inode->i_mapping);
@@ -1404,7 +1400,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 /*     fill in rpages then 
        result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
 
-/*     cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
+/*     cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
 
 #if 0
        if (rc < 0)
@@ -1836,7 +1832,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
        if (rc < 0)
                goto io_error;
        else
-               cFYI(1, ("Bytes read %d ",rc));
+               cFYI(1, ("Bytes read %d",rc));
                                                                                                                            
        file->f_dentry->d_inode->i_atime =
                current_fs_time(file->f_dentry->d_inode->i_sb);
@@ -1946,7 +1942,7 @@ static int cifs_prepare_write(struct file *file, struct page *page,
        return 0;
 }
 
-struct address_space_operations cifs_addr_ops = {
+const struct address_space_operations cifs_addr_ops = {
        .readpage = cifs_readpage,
        .readpages = cifs_readpages,
        .writepage = cifs_writepage,
@@ -1957,3 +1953,19 @@ struct address_space_operations cifs_addr_ops = {
        /* .sync_page = cifs_sync_page, */
        /* .direct_IO = */
 };
+
+/*
+ * cifs_readpages requires the server to support a buffer large enough to
+ * contain the header plus one complete page of data.  Otherwise, we need
+ * to leave cifs_readpages out of the address space operations.
+ */
+const struct address_space_operations cifs_addr_ops_smallbuf = {
+       .readpage = cifs_readpage,
+       .writepage = cifs_writepage,
+       .writepages = cifs_writepages,
+       .prepare_write = cifs_prepare_write,
+       .commit_write = cifs_commit_write,
+       .set_page_dirty = __set_page_dirty_nobuffers,
+       /* .sync_page = cifs_sync_page, */
+       /* .direct_IO = */
+};
index 4093764ef461e1797ac5e7403a238c3c12891ea3..b88147c1dc27f0df435b6251376a73b7dfc531cb 100644 (file)
@@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
        char *tmp_path;
 
        pTcon = cifs_sb->tcon;
-       cFYI(1, ("Getting info on %s ", search_path));
+       cFYI(1, ("Getting info on %s", search_path));
        /* could have done a find first instead but this returns more info */
        rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
                                  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
@@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                inode = *pinode;
                cifsInfo = CIFS_I(inode);
 
-               cFYI(1, ("Old time %ld ", cifsInfo->time));
+               cFYI(1, ("Old time %ld", cifsInfo->time));
                cifsInfo->time = jiffies;
-               cFYI(1, ("New time %ld ", cifsInfo->time));
+               cFYI(1, ("New time %ld", cifsInfo->time));
                /* this is ok to set on every inode revalidate */
                atomic_set(&cifsInfo->inUse,1);
 
@@ -180,11 +180,12 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                        else /* not direct, send byte range locks */ 
                                inode->i_fop = &cifs_file_ops;
 
-                       inode->i_data.a_ops = &cifs_addr_ops;
                        /* check if server can support readpages */
                        if(pTcon->ses->server->maxBuf < 
-                           4096 + MAX_CIFS_HDR_SIZE)
-                               inode->i_data.a_ops->readpages = NULL;
+                           PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
+                               inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+                       else
+                               inode->i_data.a_ops = &cifs_addr_ops;
                } else if (S_ISDIR(inode->i_mode)) {
                        cFYI(1, ("Directory inode"));
                        inode->i_op = &cifs_dir_inode_ops;
@@ -421,23 +422,23 @@ int cifs_get_inode_info(struct inode **pinode,
                inode = *pinode;
                cifsInfo = CIFS_I(inode);
                cifsInfo->cifsAttrs = attr;
-               cFYI(1, ("Old time %ld ", cifsInfo->time));
+               cFYI(1, ("Old time %ld", cifsInfo->time));
                cifsInfo->time = jiffies;
-               cFYI(1, ("New time %ld ", cifsInfo->time));
+               cFYI(1, ("New time %ld", cifsInfo->time));
 
                /* blksize needs to be multiple of two. So safer to default to
                blksize and blkbits set in superblock so 2**blkbits and blksize
                will match rather than setting to:
                (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
 
-               /* Linux can not store file creation time unfortunately so we ignore it */
+               /* Linux can not store file creation time so ignore it */
                inode->i_atime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
                inode->i_mtime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
                inode->i_ctime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
-               cFYI(0, ("Attributes came in as 0x%x ", attr));
+               cFYI(0, ("Attributes came in as 0x%x", attr));
 
                /* set default mode. will override for dirs below */
                if (atomic_read(&cifsInfo->inUse) == 0)
@@ -519,10 +520,11 @@ int cifs_get_inode_info(struct inode **pinode,
                        else /* not direct, send byte range locks */
                                inode->i_fop = &cifs_file_ops;
 
-                       inode->i_data.a_ops = &cifs_addr_ops;
                        if(pTcon->ses->server->maxBuf < 
-                            4096 + MAX_CIFS_HDR_SIZE)
-                               inode->i_data.a_ops->readpages = NULL;
+                            PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
+                               inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+                       else
+                               inode->i_data.a_ops = &cifs_addr_ops;
                } else if (S_ISDIR(inode->i_mode)) {
                        cFYI(1, ("Directory inode"));
                        inode->i_op = &cifs_dir_inode_ops;
@@ -731,7 +733,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
        rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
-               cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
+               cFYI(1, ("cifs_mkdir returned 0x%x", rc));
                d_drop(direntry);
        } else {
                inode->i_nlink++;
@@ -798,7 +800,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        char *full_path = NULL;
        struct cifsInodeInfo *cifsInode;
 
-       cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode));
+       cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
 
        xid = GetXid();
 
@@ -1121,7 +1123,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 
        xid = GetXid();
 
-       cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ",
+       cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
                 direntry->d_name.name, attrs->ia_valid));
 
        cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
@@ -1157,6 +1159,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                   when the local oplock break takes longer to flush
                   writebehind data than the SMB timeout for the SetPathInfo
                   request would allow */
+
                open_file = find_writable_file(cifsInode);
                if (open_file) {
                        __u16 nfid = open_file->netfid;
@@ -1289,7 +1292,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                it may be useful to Windows - but we do
                not want to set ctime unless some other
                timestamp is changing */
-               cFYI(1, ("CIFS - CTIME changed "));
+               cFYI(1, ("CIFS - CTIME changed"));
                time_buf.ChangeTime =
                    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
        } else
@@ -1356,7 +1359,7 @@ cifs_setattr_exit:
 
 void cifs_delete_inode(struct inode *inode)
 {
-       cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
+       cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
        /* may have to add back in if and when safe distributed caching of
           directories added e.g. via FindNotify */
 }
index 2ec99f8331422a2e089cc8f0b0b1381eddc6e131..a57f5d6e6213d6f23e693c88a98c3d539eb4ae6a 100644 (file)
@@ -167,7 +167,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
                return -ENOMEM;
        }
 
-       cFYI(1, ("Full path: %s ", full_path));
+       cFYI(1, ("Full path: %s", full_path));
        cFYI(1, ("symname is %s", symname));
 
        /* BB what if DFS and this volume is on different share? BB */
@@ -186,8 +186,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
                                                 inode->i_sb,xid);
 
                if (rc != 0) {
-                       cFYI(1,
-                            ("Create symlink worked but get_inode_info failed with rc = %d ",
+                       cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
                              rc));
                } else {
                        if (pTcon->nocase)
@@ -289,7 +288,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
                                        else {
                                                cFYI(1,("num referral: %d",num_referrals));
                                                if(referrals) {
-                                                       cFYI(1,("referral string: %s ",referrals));
+                                                       cFYI(1,("referral string: %s",referrals));
                                                        strncpy(tmpbuffer, referrals, len-1);                            
                                                }
                                        }
index fafd056426e4b1d9b3c7fea6c0d3fe2ea7c9340f..22c937e5884f36baf85e49cb9f3c3fc014de4522 100644 (file)
@@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
        kfree(buf_to_free->serverDomain);
        kfree(buf_to_free->serverNOS);
        kfree(buf_to_free->password);
+       kfree(buf_to_free->domainName);
        kfree(buf_to_free);
 }
 
@@ -499,11 +500,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
                if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
                        data_offset = le32_to_cpu(pSMBr->DataOffset);
 
-                       pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol
-                               + data_offset);
-                       cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName,
+                       pnotify = (struct file_notify_information *)
+                               ((char *)&pSMBr->hdr.Protocol + data_offset);
+                       cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
                                pnotify->Action));  /* BB removeme BB */
-                    /*   cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
+                    /*   cifs_dump_mem("Rcvd notify Data: ",buf,
+                               sizeof(struct smb_hdr)+60); */
                        return TRUE;
                }
                if(pSMBr->hdr.Status.CifsError) {
index 5de74d216fdd75533f23e89ef465823ea63d5ffc..b66eff5dc62445b1e4478811e26ddccaea2a0c85 100644 (file)
@@ -84,11 +84,11 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
 
 static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
        {ERRerror, -EIO},
-       {ERRbadpw, -EPERM},
+       {ERRbadpw, -EACCES},  /* was EPERM */
        {ERRbadtype, -EREMOTE},
        {ERRaccess, -EACCES},
        {ERRinvtid, -ENXIO},
-       {ERRinvnetname, -ENODEV},
+       {ERRinvnetname, -ENXIO},
        {ERRinvdevice, -ENXIO},
        {ERRqfull, -ENOSPC},
        {ERRqtoobig, -ENOSPC},
diff --git a/fs/cifs/ntlmssp.c b/fs/cifs/ntlmssp.c
deleted file mode 100644 (file)
index 115359c..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- *   fs/cifs/ntlmssp.h
- *
- *   Copyright (c) International Business Machines  Corp., 2006
- *   Author(s): Steve French (sfrench@us.ibm.com)
- *
- *   This library is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License as published
- *   by the Free Software Foundation; either version 2.1 of the License, or
- *   (at your option) any later version.
- *
- *   This library 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 Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "cifspdu.h"
-#include "cifsglob.h"
-#include "cifsproto.h"
-#include "cifs_unicode.h"
-#include "cifs_debug.h"
-#include "ntlmssp.h"
-#include "nterr.h"
-
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
-{
-       __u32 capabilities = 0;
-
-       /* init fields common to all four types of SessSetup */
-       /* note that header is initialized to zero in header_assemble */
-       pSMB->req.AndXCommand = 0xFF;
-       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
-       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
-
-       /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
-
-       /* BB verify whether signing required on neg or just on auth frame 
-          (and NTLM case) */
-
-       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
-                       CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
-
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-               pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
-       if (ses->capabilities & CAP_UNICODE) {
-               pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
-               capabilities |= CAP_UNICODE;
-       }
-       if (ses->capabilities & CAP_STATUS32) {
-               pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
-               capabilities |= CAP_STATUS32;
-       }
-       if (ses->capabilities & CAP_DFS) {
-               pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
-               capabilities |= CAP_DFS;
-       }
-
-       /* BB check whether to init vcnum BB */
-       return capabilities;
-}
-int 
-CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type,
-                 int * pNTLMv2_flg, const struct nls_table *nls_cp)
-{
-       int rc = 0;
-       int wct;
-       struct smb_hdr *smb_buffer;
-       char *bcc_ptr;
-       SESSION_SETUP_ANDX *pSMB;
-       __u32 capabilities;
-
-       if(ses == NULL)
-               return -EINVAL;
-
-       cFYI(1,("SStp type: %d",type));
-       if(type < CIFS_NTLM) {
-#ifndef CONFIG_CIFS_WEAK_PW_HASH
-               /* LANMAN and plaintext are less secure and off by default.
-               So we make this explicitly be turned on in kconfig (in the
-               build) and turned on at runtime (changed from the default)
-               in proc/fs/cifs or via mount parm.  Unfortunately this is
-               needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
-               return -EOPNOTSUPP;
-#endif
-               wct = 10; /* lanman 2 style sessionsetup */
-       } else if(type < CIFS_NTLMSSP_NEG)
-               wct = 13; /* old style NTLM sessionsetup */
-       else /* same size for negotiate or auth, NTLMSSP or extended security */
-               wct = 12;
-
-       rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
-                           (void **)&smb_buffer);
-       if(rc)
-               return rc;
-
-       pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
-
-       capabilities = cifs_ssetup_hdr(ses, pSMB);
-       bcc_ptr = pByteArea(smb_buffer);
-       if(type > CIFS_NTLM) {
-               pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
-               capabilities |= CAP_EXTENDED_SECURITY;
-               pSMB->req.Capabilities = cpu_to_le32(capabilities);
-               /* BB set password lengths */
-       } else if(type < CIFS_NTLM) /* lanman */ {
-               /* no capabilities flags in old lanman negotiation */
-               /* pSMB->old_req.PasswordLength = */ /* BB fixme BB */
-       } else /* type CIFS_NTLM */ {
-               pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
-               pSMB->req_no_secext.CaseInsensitivePasswordLength =
-                       cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-               pSMB->req_no_secext.CaseSensitivePasswordLength =
-                       cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-       }
-
-
-       /* copy session key */
-
-       /* if Unicode, align strings to two byte boundary */
-
-       /* copy user name */ /* BB Do we need to special case null user name? */
-
-       /* copy domain name */
-
-       /* copy Linux version */
-
-       /* copy network operating system name */
-
-       /* update bcc and smb buffer length */
-
-/*     rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */
-       /* SMB request buf freed in SendReceive2 */
-
-       return rc;
-}
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
index b689c5035124d137d1b019393cbad2d0b1123bf9..03bbcb3779136b1546da05e4d5de0367b0d43d23 100644 (file)
@@ -21,6 +21,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/fs.h>
+#include <linux/pagemap.h>
 #include <linux/stat.h>
 #include <linux/smp_lock.h>
 #include "cifspdu.h"
@@ -31,8 +32,8 @@
 #include "cifs_fs_sb.h"
 #include "cifsfs.h"
 
-/* BB fixme - add debug wrappers around this function to disable it fixme BB */
-/* static void dump_cifs_file_struct(struct file *file, char *label)
+#ifdef CONFIG_CIFS_DEBUG2
+static void dump_cifs_file_struct(struct file *file, char *label)
 {
        struct cifsFileInfo * cf;
 
@@ -53,7 +54,8 @@
                }
                
        }
-} */
+}
+#endif /* DEBUG2 */
 
 /* Returns one if new inode created (which therefore needs to be hashed) */
 /* Might check in the future if inode number changed so we can rehash inode */
@@ -107,32 +109,52 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
        return rc;
 }
 
-static void fill_in_inode(struct inode *tmp_inode,
-       FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
+static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
+               char * buf, int *pobject_type, int isNewInode)
 {
        loff_t local_size;
        struct timespec local_mtime;
 
        struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-       __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
-       __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
-       __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
-
-       cifsInfo->cifsAttrs = attr;
-       cifsInfo->time = jiffies;
+       __u32 attr;
+       __u64 allocation_size;
+       __u64 end_of_file;
 
        /* save mtime and size */
        local_mtime = tmp_inode->i_mtime;
        local_size  = tmp_inode->i_size;
 
+       if(new_buf_type) {
+               FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
+
+               attr = le32_to_cpu(pfindData->ExtFileAttributes);
+               allocation_size = le64_to_cpu(pfindData->AllocationSize);
+               end_of_file = le64_to_cpu(pfindData->EndOfFile);
+               tmp_inode->i_atime =
+                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+               tmp_inode->i_mtime =
+                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
+               tmp_inode->i_ctime =
+                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+       } else { /* legacy, OS2 and DOS style */
+               FIND_FILE_STANDARD_INFO * pfindData = 
+                       (FIND_FILE_STANDARD_INFO *)buf;
+
+               attr = le16_to_cpu(pfindData->Attributes);
+               allocation_size = le32_to_cpu(pfindData->AllocationSize);
+               end_of_file = le32_to_cpu(pfindData->DataSize);
+               tmp_inode->i_atime = CURRENT_TIME;
+               /* tmp_inode->i_mtime =  BB FIXME - add dos time handling
+               tmp_inode->i_ctime = 0;   BB FIXME */
+
+       }
+
        /* Linux can not store file creation time unfortunately so ignore it */
-       tmp_inode->i_atime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
-       tmp_inode->i_mtime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
-       tmp_inode->i_ctime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+
+       cifsInfo->cifsAttrs = attr;
+       cifsInfo->time = jiffies;
+
        /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
        /* 2767 perms - indicate mandatory locking */
                /* BB fill in uid and gid here? with help from winbind? 
@@ -215,11 +237,13 @@ static void fill_in_inode(struct inode *tmp_inode,
                else
                        tmp_inode->i_fop = &cifs_file_ops;
 
-               tmp_inode->i_data.a_ops = &cifs_addr_ops;
                if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
                   (cifs_sb->tcon->ses->server->maxBuf <
-                       4096 + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops->readpages = NULL;
+                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+               else
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
                if(isNewInode)
                        return; /* No sense invalidating pages for new inode
                                   since have not started caching readahead file
@@ -338,11 +362,12 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
                else
                        tmp_inode->i_fop = &cifs_file_ops;
 
-               tmp_inode->i_data.a_ops = &cifs_addr_ops;
                if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
                   (cifs_sb->tcon->ses->server->maxBuf < 
-                       4096 + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops->readpages = NULL;
+                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+               else
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
                if(isNewInode)
                        return; /* No sense invalidating pages for new inode since we
@@ -415,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file)
 ffirst_retry:
        /* test for Unix extensions */
        if (pTcon->ses->capabilities & CAP_UNIX) {
-               cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 
+               cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
+       } else if ((pTcon->ses->capabilities & 
+                       (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
+               cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
        } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
        } else /* not srvinos - BB fixme add check for backlevel? */ {
@@ -451,12 +479,19 @@ static int cifs_unicode_bytelen(char *str)
        return len << 1;
 }
 
-static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
+static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
 {
        char * new_entry;
        FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
 
-       new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
+       if(level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO * pfData;
+               pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
+
+               new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
+                               pfData->FileNameLength;
+       } else
+               new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
        cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
        /* validate that new_entry is not past end of SMB */
        if(new_entry >= end_of_smb) {
@@ -464,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
                      ("search entry %p began after end of SMB %p old entry %p",
                        new_entry, end_of_smb, old_entry)); 
                return NULL;
-       } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) {
+       } else if(((level == SMB_FIND_FILE_INFO_STANDARD) &&
+                  (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
+                 ((level != SMB_FIND_FILE_INFO_STANDARD) &&
+                  (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
                cERROR(1,("search entry %p extends after end of SMB %p",
                        new_entry, end_of_smb));
                return NULL;
@@ -482,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
        char * filename = NULL;
        int len = 0; 
 
-       if(cfile->srch_inf.info_level == 0x202) {
+       if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
                FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                if(cfile->srch_inf.unicode) {
@@ -491,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
                        /* BB should we make this strnlen of PATH_MAX? */
                        len = strnlen(filename, 5);
                }
-       } else if(cfile->srch_inf.info_level == 0x101) {
+       } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
                FILE_DIRECTORY_INFO * pFindData = 
                        (FILE_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
-       } else if(cfile->srch_inf.info_level == 0x102) {
+       } else if(cfile->srch_inf.info_level == 
+                       SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
                FILE_FULL_DIRECTORY_INFO * pFindData = 
                        (FILE_FULL_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
-       } else if(cfile->srch_inf.info_level == 0x105) {
+       } else if(cfile->srch_inf.info_level ==
+                       SMB_FIND_FILE_ID_FULL_DIR_INFO) {
                SEARCH_ID_FULL_DIR_INFO * pFindData = 
                        (SEARCH_ID_FULL_DIR_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
-       } else if(cfile->srch_inf.info_level == 0x104) {
+       } else if(cfile->srch_inf.info_level == 
+                       SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
                FILE_BOTH_DIRECTORY_INFO * pFindData = 
                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
+       } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO * pFindData =
+                       (FIND_FILE_STANDARD_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
        } else {
                cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
        }
@@ -597,7 +643,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
        . and .. for the root of a drive and for those we need
        to start two entries earlier */
 
-/*     dump_cifs_file_struct(file, "In fce ");*/
+#ifdef CONFIG_CIFS_DEBUG2
+       dump_cifs_file_struct(file, "In fce ");
+#endif
        if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
             is_dir_changed(file)) || 
           (index_to_find < first_entry_in_buffer)) {
@@ -644,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
                                        - cifsFile->srch_inf.entries_in_buffer;
                pos_in_buf = index_to_find - first_entry_in_buffer;
-               cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 
+               cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
+
                for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
                        /* go entry by entry figuring out which is first */
-                       current_entry = nxt_dir_entry(current_entry,end_of_smb);
+                       current_entry = nxt_dir_entry(current_entry,end_of_smb,
+                                               cifsFile->srch_inf.info_level);
                }
                if((current_entry == NULL) && (i < pos_in_buf)) {
                        /* BB fixme - check if we should flag this error */
@@ -674,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 /* inode num, inode type and filename returned */
 static int cifs_get_name_from_search_buf(struct qstr *pqst,
        char *current_entry, __u16 level, unsigned int unicode,
-       struct cifs_sb_info * cifs_sb, ino_t *pinum)
+       struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum)
 {
        int rc = 0;
        unsigned int len = 0;
@@ -718,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
+       } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO * pFindData =
+                       (FIND_FILE_STANDARD_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               /* one byte length, no name conversion */
+               len = (unsigned int)pFindData->FileNameLength;
        } else {
                cFYI(1,("Unknown findfirst level %d",level));
                return -EINVAL;
        }
+
+       if(len > max_len) {
+               cERROR(1,("bad search response length %d past smb end", len));
+               return -EINVAL;
+       }
+
        if(unicode) {
                /* BB fixme - test with long names */
                /* Note converted filename can be longer than in unicode */
@@ -741,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
 }
 
 static int cifs_filldir(char *pfindEntry, struct file *file,
-       filldir_t filldir, void *direntry, char *scratch_buf)
+       filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
 {
        int rc = 0;
        struct qstr qstring;
@@ -777,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
                        pCifsF->srch_inf.info_level,
                        pCifsF->srch_inf.unicode,cifs_sb,
+                       max_len,
                        &inum /* returned */);
 
        if(rc)
@@ -798,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        /* we pass in rc below, indicating whether it is a new inode,
           so we can figure out whether to invalidate the inode cached
           data if the file has changed */
-       if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
+       if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
                unix_fill_in_inode(tmp_inode,
-                                  (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
-       } else {
-               fill_in_inode(tmp_inode,
-                             (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
-       }
+                                  (FILE_UNIX_INFO *)pfindEntry,
+                                  &obj_type, rc);
+       else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
+               fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
+                               pfindEntry, &obj_type, rc);
+       else
+               fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
+       
        
        rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
                     tmp_inode->i_ino,obj_type);
@@ -864,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry,
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO * pFindData =
+                       (FIND_FILE_STANDARD_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               /* one byte length, no name conversion */
+               len = (unsigned int)pFindData->FileNameLength;
        } else {
                cFYI(1,("Unknown findfirst level %d",level));
                return -EINVAL;
@@ -884,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
        int num_to_fill = 0;
        char * tmp_buf = NULL;
        char * end_of_smb;
+       int max_len;
 
        xid = GetXid();
 
@@ -909,7 +982,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
        case 1:
                if (filldir(direntry, "..", 2, file->f_pos,
                     file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
-                       cERROR(1, ("Filldir for parent dir failed "));
+                       cERROR(1, ("Filldir for parent dir failed"));
                        rc = -ENOMEM;
                        break;
                }
@@ -959,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                        goto rddir2_exit;
                }
                cFYI(1,("loop through %d times filling dir for net buf %p",
-                       num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); 
-               end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
-                       smbCalcSize((struct smb_hdr *)
-                                   cifsFile->srch_inf.ntwrk_buf_start);
+                       num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
+               max_len = smbCalcSize((struct smb_hdr *)
+                               cifsFile->srch_inf.ntwrk_buf_start);
+               end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
+
                /* To be safe - for UCS to UTF-8 with strings loaded
                with the rare long characters alloc more to account for
                such multibyte target UTF-8 characters. cifs_unicode.c,
@@ -977,17 +1051,19 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                        }
                        /* if buggy server returns . and .. late do
                        we want to check for that here? */
-                       rc = cifs_filldir(current_entry, file, 
-                                       filldir, direntry,tmp_buf);
+                       rc = cifs_filldir(current_entry, file,
+                                       filldir, direntry, tmp_buf, max_len);
                        file->f_pos++;
-                       if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
+                       if(file->f_pos == 
+                               cifsFile->srch_inf.index_of_last_entry) {
                                cFYI(1,("last entry in buf at pos %lld %s",
-                                       file->f_pos,tmp_buf)); /* BB removeme BB */
+                                       file->f_pos,tmp_buf));
                                cifs_save_resume_key(current_entry,cifsFile);
                                break;
                        } else 
-                               current_entry = nxt_dir_entry(current_entry,
-                                                             end_of_smb);
+                               current_entry = 
+                                       nxt_dir_entry(current_entry, end_of_smb,
+                                               cifsFile->srch_inf.info_level);
                }
                kfree(tmp_buf);
                break;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
new file mode 100644 (file)
index 0000000..7202d53
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ *   fs/cifs/sess.c
+ *
+ *   SMB/CIFS session setup handling routines
+ *
+ *   Copyright (c) International Business Machines  Corp., 2006
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+#include <linux/utsname.h>
+
+extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
+                         unsigned char *p24);
+
+static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
+{
+       __u32 capabilities = 0;
+
+       /* init fields common to all four types of SessSetup */
+       /* note that header is initialized to zero in header_assemble */
+       pSMB->req.AndXCommand = 0xFF;
+       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+       /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
+
+       /* BB verify whether signing required on neg or just on auth frame 
+          (and NTLM case) */
+
+       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+                       CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
+
+       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+               pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+       if (ses->capabilities & CAP_UNICODE) {
+               pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
+               capabilities |= CAP_UNICODE;
+       }
+       if (ses->capabilities & CAP_STATUS32) {
+               pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+               capabilities |= CAP_STATUS32;
+       }
+       if (ses->capabilities & CAP_DFS) {
+               pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
+               capabilities |= CAP_DFS;
+       }
+       if (ses->capabilities & CAP_UNIX) {
+               capabilities |= CAP_UNIX;
+       }
+
+       /* BB check whether to init vcnum BB */
+       return capabilities;
+}
+
+static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+                           const struct nls_table * nls_cp)
+{
+       char * bcc_ptr = *pbcc_area;
+       int bytes_ret = 0;
+
+       /* BB FIXME add check that strings total less
+       than 335 or will need to send them as arrays */
+
+       /* unicode strings, must be word aligned before the call */
+/*     if ((long) bcc_ptr % 2) {
+               *bcc_ptr = 0;
+               bcc_ptr++;
+       } */
+       /* copy user */
+       if(ses->userName == NULL) {
+               /* BB what about null user mounts - check that we do this BB */
+       } else { /* 300 should be long enough for any conceivable user name */
+               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
+                                         300, nls_cp);
+       }
+       bcc_ptr += 2 * bytes_ret;
+       bcc_ptr += 2; /* account for null termination */
+       /* copy domain */
+       if(ses->domainName == NULL)
+               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
+                                         "CIFS_LINUX_DOM", 32, nls_cp);
+       else
+               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, 
+                                         256, nls_cp);
+       bcc_ptr += 2 * bytes_ret;
+       bcc_ptr += 2;  /* account for null terminator */
+
+       /* Copy OS version */
+       bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
+                                 nls_cp);
+       bcc_ptr += 2 * bytes_ret;
+       bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
+                                 32, nls_cp);
+       bcc_ptr += 2 * bytes_ret;
+       bcc_ptr += 2; /* trailing null */
+
+       bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
+                                  32, nls_cp);
+       bcc_ptr += 2 * bytes_ret;
+       bcc_ptr += 2; /* trailing null */
+
+       *pbcc_area = bcc_ptr;
+}
+
+static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+                         const struct nls_table * nls_cp)
+{
+       char * bcc_ptr = *pbcc_area;
+
+       /* copy user */
+       /* BB what about null user mounts - check that we do this BB */
+        /* copy user */
+        if(ses->userName == NULL) {
+                /* BB what about null user mounts - check that we do this BB */
+        } else { /* 300 should be long enough for any conceivable user name */
+                strncpy(bcc_ptr, ses->userName, 300);
+        }
+       /* BB improve check for overflow */
+        bcc_ptr += strnlen(ses->userName, 300);
+       *bcc_ptr = 0;
+        bcc_ptr++; /* account for null termination */
+
+        /* copy domain */
+       
+        if(ses->domainName == NULL) {
+                strcpy(bcc_ptr, "CIFS_LINUX_DOM");
+               bcc_ptr += 14;  /* strlen(CIFS_LINUX_DOM) */
+       } else {
+                strncpy(bcc_ptr, ses->domainName, 256); 
+               bcc_ptr += strnlen(ses->domainName, 256);
+       }
+       *bcc_ptr = 0;
+       bcc_ptr++;
+
+       /* BB check for overflow here */
+
+       strcpy(bcc_ptr, "Linux version ");
+       bcc_ptr += strlen("Linux version ");
+       strcpy(bcc_ptr, system_utsname.release);
+       bcc_ptr += strlen(system_utsname.release) + 1;
+
+       strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+       bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+
+        *pbcc_area = bcc_ptr;
+}
+
+static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+                            const struct nls_table * nls_cp)
+{
+       int rc = 0;
+       int words_left, len;
+       char * data = *pbcc_area;
+
+
+
+       cFYI(1,("bleft %d",bleft));
+
+
+       /* word align, if bytes remaining is not even */
+       if(bleft % 2) {
+               bleft--;
+               data++;
+       }
+       words_left = bleft / 2;
+
+       /* save off server operating system */
+       len = UniStrnlen((wchar_t *) data, words_left);
+
+/* We look for obvious messed up bcc or strings in response so we do not go off
+   the end since (at least) WIN2K and Windows XP have a major bug in not null
+   terminating last Unicode string in response  */
+       if(len >= words_left)
+               return rc;
+
+       if(ses->serverOS)
+               kfree(ses->serverOS);
+       /* UTF-8 string will not grow more than four times as big as UCS-16 */
+       ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
+       if(ses->serverOS != NULL) {
+               cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
+                                  nls_cp);
+       }
+       data += 2 * (len + 1);
+       words_left -= len + 1;
+
+       /* save off server network operating system */
+       len = UniStrnlen((wchar_t *) data, words_left);
+
+       if(len >= words_left)
+               return rc;
+
+       if(ses->serverNOS)
+               kfree(ses->serverNOS);
+       ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
+       if(ses->serverNOS != NULL) {
+               cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
+                                  nls_cp);
+               if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
+                       cFYI(1,("NT4 server"));
+                       ses->flags |= CIFS_SES_NT4;
+               }
+       }
+       data += 2 * (len + 1);
+       words_left -= len + 1;
+
+        /* save off server domain */
+        len = UniStrnlen((wchar_t *) data, words_left);
+
+        if(len > words_left)
+                return rc;
+
+        if(ses->serverDomain)
+                kfree(ses->serverDomain);
+        ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
+        if(ses->serverDomain != NULL) {
+                cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
+                                   nls_cp);
+                ses->serverDomain[2*len] = 0;
+                ses->serverDomain[(2*len) + 1] = 0;
+        }
+        data += 2 * (len + 1);
+        words_left -= len + 1;
+       
+       cFYI(1,("words left: %d",words_left));
+
+       return rc;
+}
+
+static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+                            const struct nls_table * nls_cp)
+{
+       int rc = 0;
+       int len;
+       char * bcc_ptr = *pbcc_area;
+
+       cFYI(1,("decode sessetup ascii. bleft %d", bleft));
+       
+       len = strnlen(bcc_ptr, bleft);
+       if(len >= bleft)
+               return rc;
+       
+       if(ses->serverOS)
+               kfree(ses->serverOS);
+
+       ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
+       if(ses->serverOS)
+               strncpy(ses->serverOS, bcc_ptr, len);
+
+       bcc_ptr += len + 1;
+       bleft -= len + 1;
+
+       len = strnlen(bcc_ptr, bleft);
+       if(len >= bleft)
+               return rc;
+
+       if(ses->serverNOS)
+               kfree(ses->serverNOS);
+
+       ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
+       if(ses->serverNOS)
+               strncpy(ses->serverNOS, bcc_ptr, len);
+
+       bcc_ptr += len + 1;
+       bleft -= len + 1;
+
+        len = strnlen(bcc_ptr, bleft);
+        if(len > bleft)
+                return rc;
+
+        if(ses->serverDomain)
+                kfree(ses->serverDomain);
+
+        ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
+        if(ses->serverOS)
+                strncpy(ses->serverOS, bcc_ptr, len);
+
+        bcc_ptr += len + 1;
+       bleft -= len + 1;
+
+       cFYI(1,("ascii: bytes left %d",bleft));
+
+       return rc;
+}
+
+int 
+CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
+               const struct nls_table *nls_cp)
+{
+       int rc = 0;
+       int wct;
+       struct smb_hdr *smb_buf;
+       char *bcc_ptr;
+       char *str_area;
+       SESSION_SETUP_ANDX *pSMB;
+       __u32 capabilities;
+       int count;
+       int resp_buf_type = 0;
+       struct kvec iov[2];
+       enum securityEnum type;
+       __u16 action;
+       int bytes_remaining;
+
+       if(ses == NULL)
+               return -EINVAL;
+
+       type = ses->server->secType;
+
+       cFYI(1,("sess setup type %d",type));
+       if(type == LANMAN) {
+#ifndef CONFIG_CIFS_WEAK_PW_HASH
+               /* LANMAN and plaintext are less secure and off by default.
+               So we make this explicitly be turned on in kconfig (in the
+               build) and turned on at runtime (changed from the default)
+               in proc/fs/cifs or via mount parm.  Unfortunately this is
+               needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
+               return -EOPNOTSUPP;
+#endif
+               wct = 10; /* lanman 2 style sessionsetup */
+       } else if((type == NTLM) || (type == NTLMv2)) { 
+               /* For NTLMv2 failures eventually may need to retry NTLM */
+               wct = 13; /* old style NTLM sessionsetup */
+       } else /* same size for negotiate or auth, NTLMSSP or extended security */
+               wct = 12;
+
+       rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
+                           (void **)&smb_buf);
+       if(rc)
+               return rc;
+
+       pSMB = (SESSION_SETUP_ANDX *)smb_buf;
+
+       capabilities = cifs_ssetup_hdr(ses, pSMB);
+
+       /* we will send the SMB in two pieces,
+       a fixed length beginning part, and a
+       second part which will include the strings
+       and rest of bcc area, in order to avoid having
+       to do a large buffer 17K allocation */
+        iov[0].iov_base = (char *)pSMB;
+        iov[0].iov_len = smb_buf->smb_buf_length + 4;
+
+       /* 2000 big enough to fit max user, domain, NOS name etc. */
+       str_area = kmalloc(2000, GFP_KERNEL);
+       bcc_ptr = str_area;
+
+       if(type == LANMAN) {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               char lnm_session_key[CIFS_SESS_KEY_SIZE];
+
+               /* no capabilities flags in old lanman negotiation */
+
+               pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; 
+               /* BB calculate hash with password */
+               /* and copy into bcc */
+
+               calc_lanman_hash(ses, lnm_session_key);
+
+/* #ifdef CONFIG_CIFS_DEBUG2
+               cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
+                       CIFS_SESS_KEY_SIZE);
+#endif */
+               memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+
+               /* can not sign if LANMAN negotiated so no need
+               to calculate signing key? but what if server
+               changed to do higher than lanman dialect and
+               we reconnected would we ever calc signing_key? */
+
+               cFYI(1,("Negotiating LANMAN setting up strings"));
+               /* Unicode not allowed for LANMAN dialects */
+               ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+#endif    
+       } else if (type == NTLM) {
+               char ntlm_session_key[CIFS_SESS_KEY_SIZE];
+
+               pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+               pSMB->req_no_secext.CaseInsensitivePasswordLength =
+                       cpu_to_le16(CIFS_SESS_KEY_SIZE);
+               pSMB->req_no_secext.CaseSensitivePasswordLength =
+                       cpu_to_le16(CIFS_SESS_KEY_SIZE);
+       
+               /* calculate session key */
+               SMBNTencrypt(ses->password, ses->server->cryptKey,
+                            ntlm_session_key);
+
+               if(first_time) /* should this be moved into common code 
+                                 with similar ntlmv2 path? */
+                       cifs_calculate_mac_key(ses->server->mac_signing_key,
+                               ntlm_session_key, ses->password);
+               /* copy session key */
+
+               memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               if(ses->capabilities & CAP_UNICODE) {
+                       /* unicode strings must be word aligned */
+                       if (iov[0].iov_len % 2) {
+                               *bcc_ptr = 0;
+                               bcc_ptr++;              
+                       }       
+                       unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
+               } else
+                       ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+       } else if (type == NTLMv2) {
+               char * v2_sess_key = 
+                       kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL);
+
+               /* BB FIXME change all users of v2_sess_key to
+                  struct ntlmv2_resp */
+
+               if(v2_sess_key == NULL) {
+                       cifs_small_buf_release(smb_buf);
+                       return -ENOMEM;
+               }
+
+               pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+
+               /* LM2 password would be here if we supported it */
+               pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+               /*      cpu_to_le16(LM2_SESS_KEY_SIZE); */
+
+               pSMB->req_no_secext.CaseSensitivePasswordLength =
+                       cpu_to_le16(sizeof(struct ntlmv2_resp));
+
+               /* calculate session key */
+               setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
+               if(first_time) /* should this be moved into common code
+                                 with similar ntlmv2 path? */
+               /*   cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
+                               response BB FIXME, v2_sess_key); */
+
+               /* copy session key */
+
+       /*      memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
+               bcc_ptr += LM2_SESS_KEY_SIZE; */
+               memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp));
+               bcc_ptr += sizeof(struct ntlmv2_resp);
+               kfree(v2_sess_key);
+               if(ses->capabilities & CAP_UNICODE) {
+                       if(iov[0].iov_len % 2) {
+                               *bcc_ptr = 0;
+                       }       bcc_ptr++;
+                       unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
+               } else
+                       ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+       } else /* NTLMSSP or SPNEGO */ {
+               pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+               capabilities |= CAP_EXTENDED_SECURITY;
+               pSMB->req.Capabilities = cpu_to_le32(capabilities);
+               /* BB set password lengths */
+       }
+
+       count = (long) bcc_ptr - (long) str_area;
+       smb_buf->smb_buf_length += count;
+
+       BCC_LE(smb_buf) = cpu_to_le16(count);
+
+       iov[1].iov_base = str_area;
+       iov[1].iov_len = count; 
+       rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0);
+       /* SMB request buf freed in SendReceive2 */
+
+       cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
+       if(rc)
+               goto ssetup_exit;
+
+       pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
+       smb_buf = (struct smb_hdr *)iov[0].iov_base;
+
+       if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
+               rc = -EIO;
+               cERROR(1,("bad word count %d", smb_buf->WordCount));
+               goto ssetup_exit;
+       }
+       action = le16_to_cpu(pSMB->resp.Action);
+       if (action & GUEST_LOGIN)
+               cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
+       ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
+       cFYI(1, ("UID = %d ", ses->Suid));
+       /* response can have either 3 or 4 word count - Samba sends 3 */
+       /* and lanman response is 3 */
+       bytes_remaining = BCC(smb_buf);
+       bcc_ptr = pByteArea(smb_buf);
+
+       if(smb_buf->WordCount == 4) {
+               __u16 blob_len;
+               blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
+               bcc_ptr += blob_len;
+               if(blob_len > bytes_remaining) {
+                       cERROR(1,("bad security blob length %d", blob_len));
+                       rc = -EINVAL;
+                       goto ssetup_exit;
+               }
+               bytes_remaining -= blob_len;
+       }       
+
+       /* BB check if Unicode and decode strings */
+       if(smb_buf->Flags2 & SMBFLG2_UNICODE)
+               rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
+                                                  ses, nls_cp);
+       else
+               rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
+       
+ssetup_exit:
+       kfree(str_area);
+       if(resp_buf_type == CIFS_SMALL_BUFFER) {
+               cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
+               cifs_small_buf_release(iov[0].iov_base);
+       } else if(resp_buf_type == CIFS_LARGE_BUFFER)
+               cifs_buf_release(iov[0].iov_base);
+
+       return rc;
+}
index 6103bcdfb16d9e425525bf20ec87fabb2da5ec2d..f518c5e45035c50955b51c55d08ab86b66127842 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/random.h>
 #include "cifs_unicode.h"
 #include "cifspdu.h"
+#include "cifsglob.h"
 #include "md5.h"
 #include "cifs_debug.h"
 #include "cifsencrypt.h"
index 3da80409466cff7e30dc428cdfb0321828a8a094..17ba329e2b3de5cbf02b973cf0b3a04515736b43 100644 (file)
@@ -654,8 +654,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 
        if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
                up(&ses->server->tcpSem);
-               cERROR(1,
-                      ("Illegal length, greater than maximum frame, %d ",
+               cERROR(1, ("Illegal length, greater than maximum frame, %d",
                        in_buf->smb_buf_length));
                DeleteMidQEntry(midQ);
                /* If not lock req, update # of requests on wire to server */
index b35e5bbd9c99b54047e843297d8c1e36b07bfb1e..76e00a65a75be512d0838d8d3b21e19873b1a6d1 100644 (file)
@@ -50,6 +50,6 @@ fail:
        return error;
 }
 
-struct address_space_operations coda_symlink_aops = {
+const struct address_space_operations coda_symlink_aops = {
        .readpage       = coda_symlink_filler,
 };
index c153bd9534cb6d72066094c8110ce0f35fec3ff3..e14488ca6411fef8db1fb86e1252f49b99f9b2a7 100644 (file)
@@ -38,7 +38,7 @@
 
 extern struct super_block * configfs_sb;
 
-static struct address_space_operations configfs_aops = {
+static const struct address_space_operations configfs_aops = {
        .readpage       = simple_readpage,
        .prepare_write  = simple_prepare_write,
        .commit_write   = simple_commit_write
index c45d738608039c5a20a4b2055bc3dd8e4c40cfcf..223c0431042deaa8fb77aa99626100338e546f4e 100644 (file)
@@ -30,7 +30,7 @@
 static struct super_operations cramfs_ops;
 static struct inode_operations cramfs_dir_inode_operations;
 static const struct file_operations cramfs_directory_operations;
-static struct address_space_operations cramfs_aops;
+static const struct address_space_operations cramfs_aops;
 
 static DEFINE_MUTEX(read_mutex);
 
@@ -501,7 +501,7 @@ static int cramfs_readpage(struct file *file, struct page * page)
        return 0;
 }
 
-static struct address_space_operations cramfs_aops = {
+static const struct address_space_operations cramfs_aops = {
        .readpage = cramfs_readpage
 };
 
index 180607f9314dc9368b2f90cbd4bac7d8542a4425..174696f9bf14eb5c803d9200b89da6e97b68b5f0 100644 (file)
@@ -21,7 +21,7 @@ static sector_t _efs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,efs_get_block);
 }
-static struct address_space_operations efs_aops = {
+static const struct address_space_operations efs_aops = {
        .readpage = efs_readpage,
        .sync_page = block_sync_page,
        .bmap = _efs_bmap
index 3d9a350e3e7f6f8687726c7e962a55dbca39a3a8..e249cf733a6bdb9b728b664a9910dff59edb8101 100644 (file)
@@ -53,6 +53,6 @@ fail:
        return err;
 }
 
-struct address_space_operations efs_symlink_aops = {
+const struct address_space_operations efs_symlink_aops = {
        .readpage       = efs_symlink_readpage
 };
index 9f74a62be555f1cc84da03e9455d8efb27652a5e..e65a019fc7a58b87f80c64fcaa7944b06bd30242 100644 (file)
@@ -162,9 +162,9 @@ extern const struct file_operations ext2_file_operations;
 extern const struct file_operations ext2_xip_file_operations;
 
 /* inode.c */
-extern struct address_space_operations ext2_aops;
-extern struct address_space_operations ext2_aops_xip;
-extern struct address_space_operations ext2_nobh_aops;
+extern const struct address_space_operations ext2_aops;
+extern const struct address_space_operations ext2_aops_xip;
+extern const struct address_space_operations ext2_nobh_aops;
 
 /* namei.c */
 extern struct inode_operations ext2_dir_inode_operations;
index 04af9c45dce23a0f50df3bf735a8749c092c3a85..fb4d3220eb8d717918445b13d8f920023e3a13fb 100644 (file)
@@ -684,7 +684,7 @@ ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
        return mpage_writepages(mapping, wbc, ext2_get_block);
 }
 
-struct address_space_operations ext2_aops = {
+const struct address_space_operations ext2_aops = {
        .readpage               = ext2_readpage,
        .readpages              = ext2_readpages,
        .writepage              = ext2_writepage,
@@ -697,12 +697,12 @@ struct address_space_operations ext2_aops = {
        .migratepage            = buffer_migrate_page,
 };
 
-struct address_space_operations ext2_aops_xip = {
+const struct address_space_operations ext2_aops_xip = {
        .bmap                   = ext2_bmap,
        .get_xip_page           = ext2_get_xip_page,
 };
 
-struct address_space_operations ext2_nobh_aops = {
+const struct address_space_operations ext2_nobh_aops = {
        .readpage               = ext2_readpage,
        .readpages              = ext2_readpages,
        .writepage              = ext2_nobh_writepage,
index 0321e1b9034a9e71db80c43cc372402ef3371c8c..f804d5e9d60c6cc81cf35c33b42b4a8d9d2fc896 100644 (file)
@@ -1698,7 +1698,7 @@ static int ext3_journalled_set_page_dirty(struct page *page)
        return __set_page_dirty_nobuffers(page);
 }
 
-static struct address_space_operations ext3_ordered_aops = {
+static const struct address_space_operations ext3_ordered_aops = {
        .readpage       = ext3_readpage,
        .readpages      = ext3_readpages,
        .writepage      = ext3_ordered_writepage,
@@ -1712,7 +1712,7 @@ static struct address_space_operations ext3_ordered_aops = {
        .migratepage    = buffer_migrate_page,
 };
 
-static struct address_space_operations ext3_writeback_aops = {
+static const struct address_space_operations ext3_writeback_aops = {
        .readpage       = ext3_readpage,
        .readpages      = ext3_readpages,
        .writepage      = ext3_writeback_writepage,
@@ -1726,7 +1726,7 @@ static struct address_space_operations ext3_writeback_aops = {
        .migratepage    = buffer_migrate_page,
 };
 
-static struct address_space_operations ext3_journalled_aops = {
+static const struct address_space_operations ext3_journalled_aops = {
        .readpage       = ext3_readpage,
        .readpages      = ext3_readpages,
        .writepage      = ext3_journalled_writepage,
index 7c35d582ec104c080cc5e760178b9986588f1362..31b7174176ba76798284286e8f6767419cef7e12 100644 (file)
@@ -196,7 +196,7 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping, block, fat_get_block);
 }
 
-static struct address_space_operations fat_aops = {
+static const struct address_space_operations fat_aops = {
        .readpage       = fat_readpage,
        .readpages      = fat_readpages,
        .writepage      = fat_writepage,
index 6f5df1700e9506b230d973ec0b88b546bd98805b..4e25f3fbed86c71d7a92722ea00bfbb82711860f 100644 (file)
@@ -56,7 +56,7 @@ struct inode_operations vxfs_immed_symlink_iops = {
 /*
  * Adress space operations for immed files and directories.
  */
-struct address_space_operations vxfs_immed_aops = {
+const struct address_space_operations vxfs_immed_aops = {
        .readpage =             vxfs_immed_readpage,
 };
 
index f544aae9169fb86847a0794006dde0a73910291e..ca6a39714771e317a89ad31c48e08c541438206a 100644 (file)
@@ -41,8 +41,8 @@
 #include "vxfs_extern.h"
 
 
-extern struct address_space_operations vxfs_aops;
-extern struct address_space_operations vxfs_immed_aops;
+extern const struct address_space_operations vxfs_aops;
+extern const struct address_space_operations vxfs_immed_aops;
 
 extern struct inode_operations vxfs_immed_symlink_iops;
 
@@ -295,7 +295,7 @@ vxfs_read_inode(struct inode *ip)
 {
        struct super_block              *sbp = ip->i_sb;
        struct vxfs_inode_info          *vip;
-       struct address_space_operations *aops;
+       const struct address_space_operations   *aops;
        ino_t                           ino = ip->i_ino;
 
        if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist)))
index c1be118fc0670a079099909c824535b599bc7423..decac62efe570ce9f81e0522eeadcbb765da9566 100644 (file)
@@ -42,7 +42,7 @@
 static int             vxfs_readpage(struct file *, struct page *);
 static sector_t                vxfs_bmap(struct address_space *, sector_t);
 
-struct address_space_operations vxfs_aops = {
+const struct address_space_operations vxfs_aops = {
        .readpage =             vxfs_readpage,
        .bmap =                 vxfs_bmap,
        .sync_page =            block_sync_page,
index 28aa81eae2cc6ddee6a2c41c5dee99254ea90f75..63614ed16336d7dec7bd4902a9c43d582e48842e 100644 (file)
@@ -770,7 +770,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
        /* no mmap and sendfile */
 };
 
-static struct address_space_operations fuse_file_aops  = {
+static const struct address_space_operations fuse_file_aops  = {
        .readpage       = fuse_readpage,
        .prepare_write  = fuse_prepare_write,
        .commit_write   = fuse_commit_write,
index 3ed8663a8db1ea792d14d0ab9ab6d0821d2521ce..735332dfd1b8a70283d1c02b0de09b3272b485d7 100644 (file)
@@ -182,8 +182,8 @@ extern void hfs_file_truncate(struct inode *);
 extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 /* inode.c */
-extern struct address_space_operations hfs_aops;
-extern struct address_space_operations hfs_btree_aops;
+extern const struct address_space_operations hfs_aops;
+extern const struct address_space_operations hfs_btree_aops;
 
 extern struct inode *hfs_new_inode(struct inode *, struct qstr *, int);
 extern void hfs_inode_write_fork(struct inode *, struct hfs_extent *, __be32 *, __be32 *);
index 2d4ced22201ba18d3b8e81eb5b1860d63011897b..315cf44a90b23e60a55910c484a71d661e64fbd2 100644 (file)
@@ -114,7 +114,7 @@ static int hfs_writepages(struct address_space *mapping,
        return mpage_writepages(mapping, wbc, hfs_get_block);
 }
 
-struct address_space_operations hfs_btree_aops = {
+const struct address_space_operations hfs_btree_aops = {
        .readpage       = hfs_readpage,
        .writepage      = hfs_writepage,
        .sync_page      = block_sync_page,
@@ -124,7 +124,7 @@ struct address_space_operations hfs_btree_aops = {
        .releasepage    = hfs_releasepage,
 };
 
-struct address_space_operations hfs_aops = {
+const struct address_space_operations hfs_aops = {
        .readpage       = hfs_readpage,
        .writepage      = hfs_writepage,
        .sync_page      = block_sync_page,
index 7ae393637a0ccc688dbfd38f674123d673081471..8a1ca5ef7ada1f26468d031ee0882d61e350ca36 100644 (file)
@@ -323,8 +323,8 @@ int hfsplus_file_extend(struct inode *);
 void hfsplus_file_truncate(struct inode *);
 
 /* inode.c */
-extern struct address_space_operations hfsplus_aops;
-extern struct address_space_operations hfsplus_btree_aops;
+extern const struct address_space_operations hfsplus_aops;
+extern const struct address_space_operations hfsplus_btree_aops;
 
 void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *);
 void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *);
index acf66dba3e01ddc5256469ef5183853128107ee6..924ecdef8091fa0323ae03e62417263cbc055330 100644 (file)
@@ -109,7 +109,7 @@ static int hfsplus_writepages(struct address_space *mapping,
        return mpage_writepages(mapping, wbc, hfsplus_get_block);
 }
 
-struct address_space_operations hfsplus_btree_aops = {
+const struct address_space_operations hfsplus_btree_aops = {
        .readpage       = hfsplus_readpage,
        .writepage      = hfsplus_writepage,
        .sync_page      = block_sync_page,
@@ -119,7 +119,7 @@ struct address_space_operations hfsplus_btree_aops = {
        .releasepage    = hfsplus_releasepage,
 };
 
-struct address_space_operations hfsplus_aops = {
+const struct address_space_operations hfsplus_aops = {
        .readpage       = hfsplus_readpage,
        .writepage      = hfsplus_writepage,
        .sync_page      = block_sync_page,
index 8e0d37743e7ce54f698e9839ebf142e0941abaff..b82e3d9c879021ae9882158aa8df2080c73f144e 100644 (file)
@@ -54,7 +54,7 @@ static int append = 0;
 
 static struct inode_operations hostfs_iops;
 static struct inode_operations hostfs_dir_iops;
-static struct address_space_operations hostfs_link_aops;
+static const struct address_space_operations hostfs_link_aops;
 
 #ifndef MODULE
 static int __init hostfs_args(char *options, int *add)
@@ -518,7 +518,7 @@ int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
        return(err);
 }
 
-static struct address_space_operations hostfs_aops = {
+static const struct address_space_operations hostfs_aops = {
        .writepage      = hostfs_writepage,
        .readpage       = hostfs_readpage,
        .set_page_dirty = __set_page_dirty_nobuffers,
@@ -935,7 +935,7 @@ int hostfs_link_readpage(struct file *file, struct page *page)
        return(err);
 }
 
-static struct address_space_operations hostfs_link_aops = {
+static const struct address_space_operations hostfs_link_aops = {
        .readpage       = hostfs_link_readpage,
 };
 
index d3b9fffe45a140bedc792f9022f4af7c8f7908ce..d9eb19b7b8aecef05ef1d49d0a12feca4b184755 100644 (file)
@@ -99,7 +99,7 @@ static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,hpfs_get_block);
 }
-struct address_space_operations hpfs_aops = {
+const struct address_space_operations hpfs_aops = {
        .readpage = hpfs_readpage,
        .writepage = hpfs_writepage,
        .sync_page = block_sync_page,
index 29b7a3e55173e8825ed63d8f899076e045641c75..f687d54ed4422469ff43086b8b030e0b06b88e00 100644 (file)
@@ -268,7 +268,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int);
 int hpfs_file_fsync(struct file *, struct dentry *, int);
 extern const struct file_operations hpfs_file_ops;
 extern struct inode_operations hpfs_file_iops;
-extern struct address_space_operations hpfs_aops;
+extern const struct address_space_operations hpfs_aops;
 
 /* inode.c */
 
@@ -304,7 +304,7 @@ void hpfs_decide_conv(struct inode *, unsigned char *, unsigned);
 /* namei.c */
 
 extern struct inode_operations hpfs_dir_iops;
-extern struct address_space_operations hpfs_symlink_aops;
+extern const struct address_space_operations hpfs_symlink_aops;
 
 static inline struct hpfs_inode_info *hpfs_i(struct inode *inode)
 {
index a03abb12c610e7e535725b8c00901c928dd0626f..59e7dc182a0c760ff78631cf162313ff6b2f97d4 100644 (file)
@@ -538,7 +538,7 @@ fail:
        return err;
 }
 
-struct address_space_operations hpfs_symlink_aops = {
+const struct address_space_operations hpfs_symlink_aops = {
        .readpage       = hpfs_symlink_readpage
 };
        
index e6410d8edd0e4751a6ada441c5a8f469dcd0fd29..6449cb697967d28818016b9ee4fbbc7519202203 100644 (file)
@@ -34,7 +34,7 @@
 #define HUGETLBFS_MAGIC        0x958458f6
 
 static struct super_operations hugetlbfs_ops;
-static struct address_space_operations hugetlbfs_aops;
+static const struct address_space_operations hugetlbfs_aops;
 const struct file_operations hugetlbfs_file_operations;
 static struct inode_operations hugetlbfs_dir_inode_operations;
 static struct inode_operations hugetlbfs_inode_operations;
@@ -547,7 +547,7 @@ static void hugetlbfs_destroy_inode(struct inode *inode)
        kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode));
 }
 
-static struct address_space_operations hugetlbfs_aops = {
+static const struct address_space_operations hugetlbfs_aops = {
        .readpage       = hugetlbfs_readpage,
        .prepare_write  = hugetlbfs_prepare_write,
        .commit_write   = hugetlbfs_commit_write,
index 3a2446a27d2c29c9bd6172f8f4e17b9871453d3e..f42961eb983b476f66e591939e42450eb64641d0 100644 (file)
@@ -102,7 +102,7 @@ static kmem_cache_t * inode_cachep __read_mostly;
 
 static struct inode *alloc_inode(struct super_block *sb)
 {
-       static struct address_space_operations empty_aops;
+       static const struct address_space_operations empty_aops;
        static struct inode_operations empty_iops;
        static const struct file_operations empty_fops;
        struct inode *inode;
index 4917315db732e881cecbd50e89573333205d9959..3a39158cca964384e12d73bdbf9b4f7b84c645c6 100644 (file)
@@ -312,7 +312,7 @@ eio:
        return err;
 }
 
-struct address_space_operations zisofs_aops = {
+const struct address_space_operations zisofs_aops = {
        .readpage = zisofs_readpage,
        /* No sync_page operation supported? */
        /* No bmap operation supported */
index 3f9c8ba1fa1f95db3c3e622a17cefd5533087eee..bb11c7fb4019b4c8c1a860f661e704158d8a1321 100644 (file)
@@ -1054,7 +1054,7 @@ static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping,block,isofs_get_block);
 }
 
-static struct address_space_operations isofs_aops = {
+static const struct address_space_operations isofs_aops = {
        .readpage = isofs_readpage,
        .sync_page = block_sync_page,
        .bmap = _isofs_bmap
index b87ba066f5e76f42debee19fcfb5336c896f33f9..e6308c8b57359e728be75de3e23d9e1b2cb974fb 100644 (file)
@@ -176,5 +176,5 @@ isofs_normalize_block_and_offset(struct iso_directory_record* de,
 
 extern struct inode_operations isofs_dir_inode_operations;
 extern const struct file_operations isofs_dir_operations;
-extern struct address_space_operations isofs_symlink_aops;
+extern const struct address_space_operations isofs_symlink_aops;
 extern struct export_operations isofs_export_ops;
index 4326cb47f8fa267667311d2b65b361aa66508858..f3a1db3098deadef58b46d7cec786d9fe8c6dae9 100644 (file)
@@ -754,6 +754,6 @@ error:
        return -EIO;
 }
 
-struct address_space_operations isofs_symlink_aops = {
+const struct address_space_operations isofs_symlink_aops = {
        .readpage = rock_ridge_symlink_readpage
 };
index d78485d101c21e203b669afe23aed5f7fcc5a771..2737957091555fd20e6cd04fd528c871e35b1187 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #ifdef CONFIG_ZISOFS
-extern struct address_space_operations zisofs_aops;
+extern const struct address_space_operations zisofs_aops;
 extern int __init zisofs_init(void);
 extern void zisofs_cleanup(void);
 #endif
index 7f96b5cb67816109e38a51b79a6ee80364e48c5d..8c9b28dff1197d85a3a720f2988b25834f7c495b 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/pagemap.h>
 #include <linux/kthread.h>
+#include <linux/poison.h>
 #include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
@@ -1675,7 +1676,7 @@ static void journal_free_journal_head(struct journal_head *jh)
 {
 #ifdef CONFIG_JBD_DEBUG
        atomic_dec(&nr_journal_heads);
-       memset(jh, 0x5b, sizeof(*jh));
+       memset(jh, JBD_POISON_FREE, sizeof(*jh));
 #endif
        kmem_cache_free(journal_head_cache, jh);
 }
index 9e46ea6da75205e949d5d0c7d0df143c5650a4e5..93068697a9bf2cf5b8a438ea96cf72da2d59be1a 100644 (file)
@@ -59,7 +59,7 @@ static const struct file_operations jffs_file_operations;
 static struct inode_operations jffs_file_inode_operations;
 static const struct file_operations jffs_dir_operations;
 static struct inode_operations jffs_dir_inode_operations;
-static struct address_space_operations jffs_address_operations;
+static const struct address_space_operations jffs_address_operations;
 
 kmem_cache_t     *node_cache = NULL;
 kmem_cache_t     *fm_cache = NULL;
@@ -1614,7 +1614,7 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 } /* jffs_ioctl()  */
 
 
-static struct address_space_operations jffs_address_operations = {
+static const struct address_space_operations jffs_address_operations = {
        .readpage       = jffs_readpage,
        .prepare_write  = jffs_prepare_write,
        .commit_write   = jffs_commit_write,
index 320dd48b834ee48beaa821daede6fd1d2c9f99ae..9c2077e7e081c7375b3df564fa1b8e3b6e2d4722 100644 (file)
@@ -267,6 +267,8 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        }
 
        rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
+       if (!value && rc == -ENODATA)
+               rc = 0;
        if (value)
                kfree(value);
        if (!rc) {
index b8886f048eaad020cce632318b50d4a02cdfb737..ad0121088dde3883ec964e6e90568b0abffe4733 100644 (file)
@@ -225,7 +225,6 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
                           at the end of the linked list. Stash it and continue
                           from the beginning of the list */
                        ic = (struct jffs2_inode_cache *)(*prev);
-                       BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE);
                        prev = &ic->nodes;
                        continue;
                }
@@ -249,7 +248,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
 
        /* PARANOIA */
        if (!ic) {
-               printk(KERN_WARNING "inode_cache not found in remove_node_refs()!!\n");
+               JFFS2_WARNING("inode_cache/xattr_datum/xattr_ref"
+                             " not found in remove_node_refs()!!\n");
                return;
        }
 
@@ -274,8 +274,19 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
                printk("\n");
        });
 
-       if (ic->nodes == (void *)ic && ic->nlink == 0)
-               jffs2_del_ino_cache(c, ic);
+       switch (ic->class) {
+#ifdef CONFIG_JFFS2_FS_XATTR
+               case RAWNODE_CLASS_XATTR_DATUM:
+                       jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+                       break;
+               case RAWNODE_CLASS_XATTR_REF:
+                       jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+                       break;
+#endif
+               default:
+                       if (ic->nodes == (void *)ic && ic->nlink == 0)
+                               jffs2_del_ino_cache(c, ic);
+       }
 }
 
 void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
index bb8844f40e48e3ecfd6327496a470ffc7bff6814..3ed6e3e120b602fb814051606dc7fc7f89edc430 100644 (file)
@@ -62,7 +62,7 @@ struct inode_operations jffs2_file_inode_operations =
        .removexattr =  jffs2_removexattr
 };
 
-struct address_space_operations jffs2_file_address_operations =
+const struct address_space_operations jffs2_file_address_operations =
 {
        .readpage =     jffs2_readpage,
        .prepare_write =jffs2_prepare_write,
index 2900ec3ec3afb79614a5479179880d0682dddf20..97caa77d60cf23db5ce8dc98848780e2a1caf49c 100644 (file)
@@ -227,8 +227,6 @@ void jffs2_clear_inode (struct inode *inode)
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
 
        D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
-
-       jffs2_xattr_delete_inode(c, f->inocache);
        jffs2_do_clear_inode(c, f);
 }
 
index 477c526d638b979efb7506ba18195ad9b14b2269..daff3341ff92b58cb72916678f69603e64ed5972 100644 (file)
@@ -165,6 +165,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                        D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
                                  ic->ino));
                        spin_unlock(&c->inocache_lock);
+                       jffs2_xattr_delete_inode(c, ic);
                        continue;
                }
                switch(ic->state) {
@@ -275,13 +276,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
         * We can decide whether this node is inode or xattr by ic->class.     */
        if (ic->class == RAWNODE_CLASS_XATTR_DATUM
            || ic->class == RAWNODE_CLASS_XATTR_REF) {
-               BUG_ON(raw->next_in_ino != (void *)ic);
                spin_unlock(&c->erase_completion_lock);
 
                if (ic->class == RAWNODE_CLASS_XATTR_DATUM) {
-                       ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+                       ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic, raw);
                } else {
-                       ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+                       ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
                }
                goto release_sem;
        }
index 935fec1b1201bdea3cfa25a0cf665ea6f69ed028..b98594992eed530a7431a8db7c85f104ba734d73 100644 (file)
@@ -119,8 +119,11 @@ struct jffs2_sb_info {
 #ifdef CONFIG_JFFS2_FS_XATTR
 #define XATTRINDEX_HASHSIZE    (57)
        uint32_t highest_xid;
+       uint32_t highest_xseqno;
        struct list_head xattrindex[XATTRINDEX_HASHSIZE];
        struct list_head xattr_unchecked;
+       struct list_head xattr_dead_list;
+       struct jffs2_xattr_ref *xref_dead_list;
        struct jffs2_xattr_ref *xref_temp;
        struct rw_semaphore xattr_sem;
        uint32_t xdatum_mem_usage;
index 4889d0700c0e6a32e7e998bf2785438f301613dd..8310c95478e9201dfbe2422bb640340aa1c32e90 100644 (file)
@@ -291,6 +291,7 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void)
 
        memset(xd, 0, sizeof(struct jffs2_xattr_datum));
        xd->class = RAWNODE_CLASS_XATTR_DATUM;
+       xd->node = (void *)xd;
        INIT_LIST_HEAD(&xd->xindex);
        return xd;
 }
@@ -309,6 +310,7 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
 
        memset(ref, 0, sizeof(struct jffs2_xattr_ref));
        ref->class = RAWNODE_CLASS_XATTR_REF;
+       ref->node = (void *)ref;
        return ref;
 }
 
index 927dfe42ba76cab92b6fae6a39c09baa71d7f607..7675b33396c7d7c307c803d0a3db57c95e8371a7 100644 (file)
@@ -906,6 +906,9 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
 {
        struct jffs2_inode_cache **prev;
 
+#ifdef CONFIG_JFFS2_FS_XATTR
+       BUG_ON(old->xref);
+#endif
        dbg_inocache("del %p (ino #%u)\n", old, old->ino);
        spin_lock(&c->inocache_lock);
 
index ac0c350ed7d7bbebad5b2bb69d6f453ea3893c80..d88376992ed9b094cc23f7b75f7b8c07870468ba 100644 (file)
@@ -683,19 +683,26 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                spin_lock(&c->erase_completion_lock);
 
                ic = jffs2_raw_ref_to_ic(ref);
-               /* It seems we should never call jffs2_mark_node_obsolete() for
-                  XATTR nodes.... yet. Make sure we notice if/when we change
-                  that :) */
-               BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE);
                for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino))
                        ;
 
                *p = ref->next_in_ino;
                ref->next_in_ino = NULL;
 
-               if (ic->nodes == (void *)ic && ic->nlink == 0)
-                       jffs2_del_ino_cache(c, ic);
-
+               switch (ic->class) {
+#ifdef CONFIG_JFFS2_FS_XATTR
+                       case RAWNODE_CLASS_XATTR_DATUM:
+                               jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+                               break;
+                       case RAWNODE_CLASS_XATTR_REF:
+                               jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+                               break;
+#endif
+                       default:
+                               if (ic->nodes == (void *)ic && ic->nlink == 0)
+                                       jffs2_del_ino_cache(c, ic);
+                               break;
+               }
                spin_unlock(&c->erase_completion_lock);
        }
 
index 6b522356540555c15c9cb9e37d2a8a9b317999be..9f41fc01a371b7b1a87d1eff853db3cc46d0018c 100644 (file)
@@ -158,7 +158,7 @@ extern struct inode_operations jffs2_dir_inode_operations;
 /* file.c */
 extern const struct file_operations jffs2_file_operations;
 extern struct inode_operations jffs2_file_inode_operations;
-extern struct address_space_operations jffs2_file_address_operations;
+extern const struct address_space_operations jffs2_file_address_operations;
 int jffs2_fsync(struct file *, struct dentry *, int);
 int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
 
index 5fec012b02ed59a1fa5f8ca871849af4c24e4e40..cc1899268c439a0c68e8bc877c6f4c56854bd3ba 100644 (file)
@@ -968,6 +968,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
        struct jffs2_full_dirent *fd, *fds;
        int deleted;
 
+       jffs2_xattr_delete_inode(c, f->inocache);
        down(&f->sem);
        deleted = f->inocache && !f->inocache->nlink;
 
index 61618080b86f0a9bfe3202e39c8e452f13a21ec5..2bfdc33752d38c69c959729d5d9f462882ef54f6 100644 (file)
@@ -317,20 +317,23 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
                                 struct jffs2_summary *s)
 {
        struct jffs2_xattr_datum *xd;
-       uint32_t totlen, crc;
+       uint32_t xid, version, totlen, crc;
        int err;
 
        crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4);
        if (crc != je32_to_cpu(rx->node_crc)) {
-               if (je32_to_cpu(rx->node_crc) != 0xffffffff)
-                       JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                     ofs, je32_to_cpu(rx->node_crc), crc);
+               JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                             ofs, je32_to_cpu(rx->node_crc), crc);
                if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen))))
                        return err;
                return 0;
        }
 
-       totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len));
+       xid = je32_to_cpu(rx->xid);
+       version = je32_to_cpu(rx->version);
+
+       totlen = PAD(sizeof(struct jffs2_raw_xattr)
+                       + rx->name_len + 1 + je16_to_cpu(rx->value_len));
        if (totlen != je32_to_cpu(rx->totlen)) {
                JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
                              ofs, je32_to_cpu(rx->totlen), totlen);
@@ -339,22 +342,24 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
                return 0;
        }
 
-       xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version));
-       if (IS_ERR(xd)) {
-               if (PTR_ERR(xd) == -EEXIST) {
-                       if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen)))))
-                               return err;
-                       return 0;
-               }
+       xd = jffs2_setup_xattr_datum(c, xid, version);
+       if (IS_ERR(xd))
                return PTR_ERR(xd);
-       }
-       xd->xprefix = rx->xprefix;
-       xd->name_len = rx->name_len;
-       xd->value_len = je16_to_cpu(rx->value_len);
-       xd->data_crc = je32_to_cpu(rx->data_crc);
 
-       xd->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL);
-       /* FIXME */ xd->node->next_in_ino = (void *)xd;
+       if (xd->version > version) {
+               struct jffs2_raw_node_ref *raw
+                       = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL);
+               raw->next_in_ino = xd->node->next_in_ino;
+               xd->node->next_in_ino = raw;
+       } else {
+               xd->version = version;
+               xd->xprefix = rx->xprefix;
+               xd->name_len = rx->name_len;
+               xd->value_len = je16_to_cpu(rx->value_len);
+               xd->data_crc = je32_to_cpu(rx->data_crc);
+
+               jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, (void *)xd);
+       }
 
        if (jffs2_sum_active())
                jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset);
@@ -373,9 +378,8 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
 
        crc = crc32(0, rr, sizeof(*rr) - 4);
        if (crc != je32_to_cpu(rr->node_crc)) {
-               if (je32_to_cpu(rr->node_crc) != 0xffffffff)
-                       JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                     ofs, je32_to_cpu(rr->node_crc), crc);
+               JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                             ofs, je32_to_cpu(rr->node_crc), crc);
                if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rr->totlen)))))
                        return err;
                return 0;
@@ -395,6 +399,7 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
                return -ENOMEM;
 
        /* BEFORE jffs2_build_xattr_subsystem() called, 
+        * and AFTER xattr_ref is marked as a dead xref,
         * ref->xid is used to store 32bit xid, xd is not used
         * ref->ino is used to store 32bit inode-number, ic is not used
         * Thoes variables are declared as union, thus using those
@@ -404,11 +409,13 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
         */
        ref->ino = je32_to_cpu(rr->ino);
        ref->xid = je32_to_cpu(rr->xid);
+       ref->xseqno = je32_to_cpu(rr->xseqno);
+       if (ref->xseqno > c->highest_xseqno)
+               c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER);
        ref->next = c->xref_temp;
        c->xref_temp = ref;
 
-       ref->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), NULL);
-       /* FIXME */ ref->node->next_in_ino = (void *)ref;
+       jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), (void *)ref);
 
        if (jffs2_sum_active())
                jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset);
index be1acc3dad97a7d340b56c82c5db59fd64436ce3..c19bd476e8ec785abbdcaf9edc9c9ff2e0446678 100644 (file)
@@ -5,7 +5,7 @@
  *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
  *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
  *                     University of Szeged, Hungary
- *               2005  KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *               2006  KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
@@ -310,8 +310,6 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
 #ifdef CONFIG_JFFS2_FS_XATTR
                case JFFS2_NODETYPE_XATTR: {
                        struct jffs2_sum_xattr_mem *temp;
-                       if (je32_to_cpu(node->x.version) == 0xffffffff)
-                               return 0;
                        temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
                        if (!temp)
                                goto no_mem;
@@ -327,10 +325,6 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
                }
                case JFFS2_NODETYPE_XREF: {
                        struct jffs2_sum_xref_mem *temp;
-
-                       if (je32_to_cpu(node->r.ino) == 0xffffffff
-                           && je32_to_cpu(node->r.xid) == 0xffffffff)
-                               return 0;
                        temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
                        if (!temp)
                                goto no_mem;
@@ -483,22 +477,20 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
 
                                xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
                                                                je32_to_cpu(spx->version));
-                               if (IS_ERR(xd)) {
-                                       if (PTR_ERR(xd) == -EEXIST) {
-                                               /* a newer version of xd exists */
-                                               if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen))))
-                                                       return err;
-                                               sp += JFFS2_SUMMARY_XATTR_SIZE;
-                                               break;
-                                       }
-                                       JFFS2_NOTICE("allocation of xattr_datum failed\n");
+                               if (IS_ERR(xd))
                                        return PTR_ERR(xd);
+                               if (xd->version > je32_to_cpu(spx->version)) {
+                                       /* node is not the newest one */
+                                       struct jffs2_raw_node_ref *raw
+                                               = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
+                                                                   PAD(je32_to_cpu(spx->totlen)), NULL);
+                                       raw->next_in_ino = xd->node->next_in_ino;
+                                       xd->node->next_in_ino = raw;
+                               } else {
+                                       xd->version = je32_to_cpu(spx->version);
+                                       sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
+                                                         PAD(je32_to_cpu(spx->totlen)), (void *)xd);
                                }
-
-                               xd->node = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
-                                                            PAD(je32_to_cpu(spx->totlen)), NULL);
-                               /* FIXME */ xd->node->next_in_ino = (void *)xd;
-
                                *pseudo_random += je32_to_cpu(spx->xid);
                                sp += JFFS2_SUMMARY_XATTR_SIZE;
 
@@ -519,14 +511,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                        JFFS2_NOTICE("allocation of xattr_datum failed\n");
                                        return -ENOMEM;
                                }
-                               ref->ino = 0xfffffffe;
-                               ref->xid = 0xfffffffd;
                                ref->next = c->xref_temp;
                                c->xref_temp = ref;
 
-                               ref->node = sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
-                                                             PAD(sizeof(struct jffs2_raw_xref)), NULL);
-                               /* FIXME */ ref->node->next_in_ino = (void *)ref;
+                               sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
+                                                 PAD(sizeof(struct jffs2_raw_xref)), (void *)ref);
 
                                *pseudo_random += ref->node->flash_offset;
                                sp += JFFS2_SUMMARY_XREF_SIZE;
index 2d82e250be34e234ec6f533b8f37b1620b88e04c..18e66dbf23b497d456a191c75c9d7cb1b52edd65 100644 (file)
  * xattr_datum_hashkey(xprefix, xname, xvalue, xsize)
  *   is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is
  *   the index of the xattr name/value pair cache (c->xattrindex).
+ * is_xattr_datum_unchecked(c, xd)
+ *   returns 1, if xdatum contains any unchecked raw nodes. if all raw nodes are not
+ *   unchecked, it returns 0.
  * unload_xattr_datum(c, xd)
  *   is used to release xattr name/value pair and detach from c->xattrindex.
  * reclaim_xattr_datum(c)
  *   is used to reclaim xattr name/value pairs on the xattr name/value pair cache when
  *   memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold 
  *   is hard coded as 32KiB.
- * delete_xattr_datum_node(c, xd)
- *   is used to delete a jffs2 node is dominated by xdatum. When EBS(Erase Block Summary) is
- *   enabled, it overwrites the obsolete node by myself.
- * delete_xattr_datum(c, xd)
- *   is used to delete jffs2_xattr_datum object. It must be called with 0-value of reference
- *   counter. (It means how many jffs2_xattr_ref object refers this xdatum.)
  * do_verify_xattr_datum(c, xd)
  *   is used to load the xdatum informations without name/value pair from the medium.
  *   It's necessary once, because those informations are not collected during mounting
  *   is used to write xdatum to medium. xd->version will be incremented.
  * create_xattr_datum(c, xprefix, xname, xvalue, xsize)
  *   is used to create new xdatum and write to medium.
+ * delete_xattr_datum(c, xd)
+ *   is used to delete a xdatum. It marks xd JFFS2_XFLAGS_DEAD, and allows
+ *   GC to reclaim those physical nodes.
  * -------------------------------------------------- */
-
 static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
 {
        int name_len = strlen(xname);
@@ -62,6 +61,22 @@ static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *
        return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize);
 }
 
+static int is_xattr_datum_unchecked(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+       struct jffs2_raw_node_ref *raw;
+       int rc = 0;
+
+       spin_lock(&c->erase_completion_lock);
+       for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+               if (ref_flags(raw) == REF_UNCHECKED) {
+                       rc = 1;
+                       break;
+               }
+       }
+       spin_unlock(&c->erase_completion_lock);
+       return rc;
+}
+
 static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
        /* must be called under down_write(xattr_sem) */
@@ -107,77 +122,33 @@ static void reclaim_xattr_datum(struct jffs2_sb_info *c)
                     before, c->xdatum_mem_usage, before - c->xdatum_mem_usage);
 }
 
-static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
-{
-       /* must be called under down_write(xattr_sem) */
-       struct jffs2_raw_xattr rx;
-       size_t length;
-       int rc;
-
-       if (!xd->node) {
-               JFFS2_WARNING("xdatum (xid=%u) is removed twice.\n", xd->xid);
-               return;
-       }
-       if (jffs2_sum_active()) {
-               memset(&rx, 0xff, sizeof(struct jffs2_raw_xattr));
-               rc = jffs2_flash_read(c, ref_offset(xd->node),
-                                     sizeof(struct jffs2_unknown_node),
-                                     &length, (char *)&rx);
-               if (rc || length != sizeof(struct jffs2_unknown_node)) {
-                       JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-                                   rc, sizeof(struct jffs2_unknown_node),
-                                   length, ref_offset(xd->node));
-               }
-               rc = jffs2_flash_write(c, ref_offset(xd->node), sizeof(rx),
-                                      &length, (char *)&rx);
-               if (rc || length != sizeof(struct jffs2_raw_xattr)) {
-                       JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu ar %#08x\n",
-                                   rc, sizeof(rx), length, ref_offset(xd->node));
-               }
-       }
-       spin_lock(&c->erase_completion_lock);
-       xd->node->next_in_ino = NULL;
-       spin_unlock(&c->erase_completion_lock);
-       jffs2_mark_node_obsolete(c, xd->node);
-       xd->node = NULL;
-}
-
-static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
-{
-       /* must be called under down_write(xattr_sem) */
-       BUG_ON(xd->refcnt);
-
-       unload_xattr_datum(c, xd);
-       if (xd->node) {
-               delete_xattr_datum_node(c, xd);
-               xd->node = NULL;
-       }
-       jffs2_free_xattr_datum(xd);
-}
-
 static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
        /* must be called under down_write(xattr_sem) */
        struct jffs2_eraseblock *jeb;
+       struct jffs2_raw_node_ref *raw;
        struct jffs2_raw_xattr rx;
        size_t readlen;
-       uint32_t crc, totlen;
+       uint32_t crc, offset, totlen;
        int rc;
 
-       BUG_ON(!xd->node);
-       BUG_ON(ref_flags(xd->node) != REF_UNCHECKED);
+       spin_lock(&c->erase_completion_lock);
+       offset = ref_offset(xd->node);
+       if (ref_flags(xd->node) == REF_PRISTINE)
+               goto complete;
+       spin_unlock(&c->erase_completion_lock);
 
-       rc = jffs2_flash_read(c, ref_offset(xd->node), sizeof(rx), &readlen, (char *)&rx);
+       rc = jffs2_flash_read(c, offset, sizeof(rx), &readlen, (char *)&rx);
        if (rc || readlen != sizeof(rx)) {
                JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-                             rc, sizeof(rx), readlen, ref_offset(xd->node));
+                             rc, sizeof(rx), readlen, offset);
                return rc ? rc : -EIO;
        }
        crc = crc32(0, &rx, sizeof(rx) - 4);
        if (crc != je32_to_cpu(rx.node_crc)) {
-               if (je32_to_cpu(rx.node_crc) != 0xffffffff)
-                       JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                   ref_offset(xd->node), je32_to_cpu(rx.hdr_crc), crc);
+               JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                           offset, je32_to_cpu(rx.hdr_crc), crc);
+               xd->flags |= JFFS2_XFLAGS_INVALID;
                return EIO;
        }
        totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
@@ -188,11 +159,12 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
            || je32_to_cpu(rx.version) != xd->version) {
                JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, "
                            "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n",
-                           ref_offset(xd->node), je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
+                           offset, je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
                            je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR,
                            je32_to_cpu(rx.totlen), totlen,
                            je32_to_cpu(rx.xid), xd->xid,
                            je32_to_cpu(rx.version), xd->version);
+               xd->flags |= JFFS2_XFLAGS_INVALID;
                return EIO;
        }
        xd->xprefix = rx.xprefix;
@@ -200,14 +172,17 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
        xd->value_len = je16_to_cpu(rx.value_len);
        xd->data_crc = je32_to_cpu(rx.data_crc);
 
-       /* This JFFS2_NODETYPE_XATTR node is checked */
-       jeb = &c->blocks[ref_offset(xd->node) / c->sector_size];
-       totlen = PAD(je32_to_cpu(rx.totlen));
-
        spin_lock(&c->erase_completion_lock);
-       c->unchecked_size -= totlen; c->used_size += totlen;
-       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
-       xd->node->flash_offset = ref_offset(xd->node) | REF_PRISTINE;
+ complete:
+       for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+               jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+               totlen = PAD(ref_totlen(c, jeb, raw));
+               if (ref_flags(raw) == REF_UNCHECKED) {
+                       c->unchecked_size -= totlen; c->used_size += totlen;
+                       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+               }
+               raw->flash_offset = ref_offset(raw) | ((xd->node==raw) ? REF_PRISTINE : REF_NORMAL);
+       }
        spin_unlock(&c->erase_completion_lock);
 
        /* unchecked xdatum is chained with c->xattr_unchecked */
@@ -227,7 +202,6 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum
        uint32_t crc, length;
        int i, ret, retry = 0;
 
-       BUG_ON(!xd->node);
        BUG_ON(ref_flags(xd->node) != REF_PRISTINE);
        BUG_ON(!list_empty(&xd->xindex));
  retry:
@@ -253,6 +227,7 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum
                              " at %#08x, read: 0x%08x calculated: 0x%08x\n",
                              ref_offset(xd->node), xd->data_crc, crc);
                kfree(data);
+               xd->flags |= JFFS2_XFLAGS_INVALID;
                return EIO;
        }
 
@@ -286,16 +261,14 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
         * rc > 0 : Unrecoverable error, this node should be deleted.
         */
        int rc = 0;
-       BUG_ON(xd->xname);
-       if (!xd->node)
+
+       BUG_ON(xd->flags & JFFS2_XFLAGS_DEAD);
+       if (xd->xname)
+               return 0;
+       if (xd->flags & JFFS2_XFLAGS_INVALID)
                return EIO;
-       if (unlikely(ref_flags(xd->node) != REF_PRISTINE)) {
+       if (unlikely(is_xattr_datum_unchecked(c, xd)))
                rc = do_verify_xattr_datum(c, xd);
-               if (rc > 0) {
-                       list_del_init(&xd->xindex);
-                       delete_xattr_datum_node(c, xd);
-               }
-       }
        if (!rc)
                rc = do_load_xattr_datum(c, xd);
        return rc;
@@ -304,7 +277,6 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
 static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
        /* must be called under down_write(xattr_sem) */
-       struct jffs2_raw_node_ref *raw;
        struct jffs2_raw_xattr rx;
        struct kvec vecs[2];
        size_t length;
@@ -312,14 +284,16 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
        uint32_t phys_ofs = write_ofs(c);
 
        BUG_ON(!xd->xname);
+       BUG_ON(xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID));
 
        vecs[0].iov_base = &rx;
-       vecs[0].iov_len = PAD(sizeof(rx));
+       vecs[0].iov_len = sizeof(rx);
        vecs[1].iov_base = xd->xname;
        vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
        totlen = vecs[0].iov_len + vecs[1].iov_len;
 
        /* Setup raw-xattr */
+       memset(&rx, 0, sizeof(rx));
        rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
        rx.totlen = cpu_to_je32(PAD(totlen));
@@ -343,14 +317,8 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
 
                return rc;
        }
-
        /* success */
-       raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), NULL);
-       /* FIXME */ raw->next_in_ino = (void *)xd;
-
-       if (xd->node)
-               delete_xattr_datum_node(c, xd);
-       xd->node = raw;
+       jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), (void *)xd);
 
        dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n",
                  xd->xid, xd->version, xd->xprefix, xd->xname);
@@ -377,7 +345,7 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
                    && xd->value_len==xsize
                    && !strcmp(xd->xname, xname)
                    && !memcmp(xd->xvalue, xvalue, xsize)) {
-                       xd->refcnt++;
+                       atomic_inc(&xd->refcnt);
                        return xd;
                }
        }
@@ -397,7 +365,7 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
        strcpy(data, xname);
        memcpy(data + name_len + 1, xvalue, xsize);
 
-       xd->refcnt = 1;
+       atomic_set(&xd->refcnt, 1);
        xd->xid = ++c->highest_xid;
        xd->flags |= JFFS2_XFLAGS_HOT;
        xd->xprefix = xprefix;
@@ -426,20 +394,36 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
        return xd;
 }
 
+static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+       /* must be called under down_write(xattr_sem) */
+       BUG_ON(atomic_read(&xd->refcnt));
+
+       unload_xattr_datum(c, xd);
+       xd->flags |= JFFS2_XFLAGS_DEAD;
+       spin_lock(&c->erase_completion_lock);
+       if (xd->node == (void *)xd) {
+               BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID));
+               jffs2_free_xattr_datum(xd);
+       } else {
+               list_add(&xd->xindex, &c->xattr_dead_list);
+       }
+       spin_unlock(&c->erase_completion_lock);
+       dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xd->xid, xd->version);
+}
+
 /* -------- xref related functions ------------------
  * verify_xattr_ref(c, ref)
  *   is used to load xref information from medium. Because summary data does not
  *   contain xid/ino, it's necessary to verify once while mounting process.
- * delete_xattr_ref_node(c, ref)
- *   is used to delete a jffs2 node is dominated by xref. When EBS is enabled,
- *   it overwrites the obsolete node by myself. 
- * delete_xattr_ref(c, ref)
- *   is used to delete jffs2_xattr_ref object. If the reference counter of xdatum
- *   is refered by this xref become 0, delete_xattr_datum() is called later.
  * save_xattr_ref(c, ref)
- *   is used to write xref to medium.
+ *   is used to write xref to medium. If delete marker is marked, it write
+ *   a delete marker of xref into medium.
  * create_xattr_ref(c, ic, xd)
  *   is used to create a new xref and write to medium.
+ * delete_xattr_ref(c, ref)
+ *   is used to delete jffs2_xattr_ref. It marks xref XREF_DELETE_MARKER,
+ *   and allows GC to reclaim those physical nodes.
  * jffs2_xattr_delete_inode(c, ic)
  *   is called to remove xrefs related to obsolete inode when inode is unlinked.
  * jffs2_xattr_free_inode(c, ic)
@@ -450,25 +434,29 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
 static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 {
        struct jffs2_eraseblock *jeb;
+       struct jffs2_raw_node_ref *raw;
        struct jffs2_raw_xref rr;
        size_t readlen;
-       uint32_t crc, totlen;
+       uint32_t crc, offset, totlen;
        int rc;
 
-       BUG_ON(ref_flags(ref->node) != REF_UNCHECKED);
+       spin_lock(&c->erase_completion_lock);
+       if (ref_flags(ref->node) != REF_UNCHECKED)
+               goto complete;
+       offset = ref_offset(ref->node);
+       spin_unlock(&c->erase_completion_lock);
 
-       rc = jffs2_flash_read(c, ref_offset(ref->node), sizeof(rr), &readlen, (char *)&rr);
+       rc = jffs2_flash_read(c, offset, sizeof(rr), &readlen, (char *)&rr);
        if (rc || sizeof(rr) != readlen) {
                JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu, at %#08x\n",
-                             rc, sizeof(rr), readlen, ref_offset(ref->node));
+                             rc, sizeof(rr), readlen, offset);
                return rc ? rc : -EIO;
        }
        /* obsolete node */
        crc = crc32(0, &rr, sizeof(rr) - 4);
        if (crc != je32_to_cpu(rr.node_crc)) {
-               if (je32_to_cpu(rr.node_crc) != 0xffffffff)
-                       JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                   ref_offset(ref->node), je32_to_cpu(rr.node_crc), crc);
+               JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                           offset, je32_to_cpu(rr.node_crc), crc);
                return EIO;
        }
        if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
@@ -476,22 +464,28 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
            || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) {
                JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, "
                            "nodetype=%#04x/%#04x, totlen=%u/%zu\n",
-                           ref_offset(ref->node), je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
+                           offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
                            je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
                            je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
                return EIO;
        }
        ref->ino = je32_to_cpu(rr.ino);
        ref->xid = je32_to_cpu(rr.xid);
-
-       /* fixup superblock/eraseblock info */
-       jeb = &c->blocks[ref_offset(ref->node) / c->sector_size];
-       totlen = PAD(sizeof(rr));
+       ref->xseqno = je32_to_cpu(rr.xseqno);
+       if (ref->xseqno > c->highest_xseqno)
+               c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER);
 
        spin_lock(&c->erase_completion_lock);
-       c->unchecked_size -= totlen; c->used_size += totlen;
-       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
-       ref->node->flash_offset = ref_offset(ref->node) | REF_PRISTINE;
+ complete:
+       for (raw=ref->node; raw != (void *)ref; raw=raw->next_in_ino) {
+               jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+               totlen = PAD(ref_totlen(c, jeb, raw));
+               if (ref_flags(raw) == REF_UNCHECKED) {
+                       c->unchecked_size -= totlen; c->used_size += totlen;
+                       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+               }
+               raw->flash_offset = ref_offset(raw) | ((ref->node==raw) ? REF_PRISTINE : REF_NORMAL);
+       }
        spin_unlock(&c->erase_completion_lock);
 
        dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n",
@@ -499,58 +493,12 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
        return 0;
 }
 
-static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
-{
-       struct jffs2_raw_xref rr;
-       size_t length;
-       int rc;
-
-       if (jffs2_sum_active()) {
-               memset(&rr, 0xff, sizeof(rr));
-               rc = jffs2_flash_read(c, ref_offset(ref->node),
-                                     sizeof(struct jffs2_unknown_node),
-                                     &length, (char *)&rr);
-               if (rc || length != sizeof(struct jffs2_unknown_node)) {
-                       JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-                                   rc, sizeof(struct jffs2_unknown_node),
-                                   length, ref_offset(ref->node));
-               }
-               rc = jffs2_flash_write(c, ref_offset(ref->node), sizeof(rr),
-                                      &length, (char *)&rr);
-               if (rc || length != sizeof(struct jffs2_raw_xref)) {
-                       JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu at %#08x\n",
-                                   rc, sizeof(rr), length, ref_offset(ref->node));
-               }
-       }
-       spin_lock(&c->erase_completion_lock);
-       ref->node->next_in_ino = NULL;
-       spin_unlock(&c->erase_completion_lock);
-       jffs2_mark_node_obsolete(c, ref->node);
-       ref->node = NULL;
-}
-
-static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
-{
-       /* must be called under down_write(xattr_sem) */
-       struct jffs2_xattr_datum *xd;
-
-       BUG_ON(!ref->node);
-       delete_xattr_ref_node(c, ref);
-
-       xd = ref->xd;
-       xd->refcnt--;
-       if (!xd->refcnt)
-               delete_xattr_datum(c, xd);
-       jffs2_free_xattr_ref(ref);
-}
-
 static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 {
        /* must be called under down_write(xattr_sem) */
-       struct jffs2_raw_node_ref *raw;
        struct jffs2_raw_xref rr;
        size_t length;
-       uint32_t phys_ofs = write_ofs(c);
+       uint32_t xseqno, phys_ofs = write_ofs(c);
        int ret;
 
        rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -558,8 +506,16 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
        rr.totlen = cpu_to_je32(PAD(sizeof(rr)));
        rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4));
 
-       rr.ino = cpu_to_je32(ref->ic->ino);
-       rr.xid = cpu_to_je32(ref->xd->xid);
+       xseqno = (c->highest_xseqno += 2);
+       if (is_xattr_ref_dead(ref)) {
+               xseqno |= XREF_DELETE_MARKER;
+               rr.ino = cpu_to_je32(ref->ino);
+               rr.xid = cpu_to_je32(ref->xid);
+       } else {
+               rr.ino = cpu_to_je32(ref->ic->ino);
+               rr.xid = cpu_to_je32(ref->xd->xid);
+       }
+       rr.xseqno = cpu_to_je32(xseqno);
        rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4));
 
        ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr);
@@ -572,12 +528,9 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 
                return ret;
        }
-
-       raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), NULL);
-       /* FIXME */ raw->next_in_ino = (void *)ref;
-       if (ref->node)
-               delete_xattr_ref_node(c, ref);
-       ref->node = raw;
+       /* success */
+       ref->xseqno = xseqno;
+       jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), (void *)ref);
 
        dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid);
 
@@ -610,6 +563,27 @@ static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct
        return ref; /* success */
 }
 
+static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+       /* must be called under down_write(xattr_sem) */
+       struct jffs2_xattr_datum *xd;
+
+       xd = ref->xd;
+       ref->xseqno |= XREF_DELETE_MARKER;
+       ref->ino = ref->ic->ino;
+       ref->xid = ref->xd->xid;
+       spin_lock(&c->erase_completion_lock);
+       ref->next = c->xref_dead_list;
+       c->xref_dead_list = ref;
+       spin_unlock(&c->erase_completion_lock);
+
+       dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
+                 ref->ino, ref->xid, ref->xseqno);
+
+       if (atomic_dec_and_test(&xd->refcnt))
+               delete_xattr_datum(c, xd);
+}
+
 void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
 {
        /* It's called from jffs2_clear_inode() on inode removing.
@@ -638,8 +612,7 @@ void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
        for (ref = ic->xref; ref; ref = _ref) {
                _ref = ref->next;
                xd = ref->xd;
-               xd->refcnt--;
-               if (!xd->refcnt) {
+               if (atomic_dec_and_test(&xd->refcnt)) {
                        unload_xattr_datum(c, xd);
                        jffs2_free_xattr_datum(xd);
                }
@@ -655,7 +628,7 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac
         * duplicate name/value pairs. If duplicate name/value pair would be found,
         * one will be removed.
         */
-       struct jffs2_xattr_ref *ref, *cmp, **pref;
+       struct jffs2_xattr_ref *ref, *cmp, **pref, **pcmp;
        int rc = 0;
 
        if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED))
@@ -673,13 +646,13 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac
                        } else if (unlikely(rc < 0))
                                goto out;
                }
-               for (cmp=ref->next, pref=&ref->next; cmp; pref=&cmp->next, cmp=cmp->next) {
+               for (cmp=ref->next, pcmp=&ref->next; cmp; pcmp=&cmp->next, cmp=cmp->next) {
                        if (!cmp->xd->xname) {
                                ref->xd->flags |= JFFS2_XFLAGS_BIND;
                                rc = load_xattr_datum(c, cmp->xd);
                                ref->xd->flags &= ~JFFS2_XFLAGS_BIND;
                                if (unlikely(rc > 0)) {
-                                       *pref = cmp->next;
+                                       *pcmp = cmp->next;
                                        delete_xattr_ref(c, cmp);
                                        goto retry;
                                } else if (unlikely(rc < 0))
@@ -687,8 +660,13 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac
                        }
                        if (ref->xd->xprefix == cmp->xd->xprefix
                            && !strcmp(ref->xd->xname, cmp->xd->xname)) {
-                               *pref = cmp->next;
-                               delete_xattr_ref(c, cmp);
+                               if (ref->xseqno > cmp->xseqno) {
+                                       *pcmp = cmp->next;
+                                       delete_xattr_ref(c, cmp);
+                               } else {
+                                       *pref = ref->next;
+                                       delete_xattr_ref(c, ref);
+                               }
                                goto retry;
                        }
                }
@@ -719,9 +697,13 @@ void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c)
        for (i=0; i < XATTRINDEX_HASHSIZE; i++)
                INIT_LIST_HEAD(&c->xattrindex[i]);
        INIT_LIST_HEAD(&c->xattr_unchecked);
+       INIT_LIST_HEAD(&c->xattr_dead_list);
+       c->xref_dead_list = NULL;
        c->xref_temp = NULL;
 
        init_rwsem(&c->xattr_sem);
+       c->highest_xid = 0;
+       c->highest_xseqno = 0;
        c->xdatum_mem_usage = 0;
        c->xdatum_mem_threshold = 32 * 1024;    /* Default 32KB */
 }
@@ -751,7 +733,11 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
                _ref = ref->next;
                jffs2_free_xattr_ref(ref);
        }
-       c->xref_temp = NULL;
+
+       for (ref=c->xref_dead_list; ref; ref = _ref) {
+               _ref = ref->next;
+               jffs2_free_xattr_ref(ref);
+       }
 
        for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
                list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
@@ -761,100 +747,143 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
                        jffs2_free_xattr_datum(xd);
                }
        }
+
+       list_for_each_entry_safe(xd, _xd, &c->xattr_dead_list, xindex) {
+               list_del(&xd->xindex);
+               jffs2_free_xattr_datum(xd);
+       }
 }
 
+#define XREF_TMPHASH_SIZE      (128)
 void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
 {
        struct jffs2_xattr_ref *ref, *_ref;
+       struct jffs2_xattr_ref *xref_tmphash[XREF_TMPHASH_SIZE];
        struct jffs2_xattr_datum *xd, *_xd;
        struct jffs2_inode_cache *ic;
-       int i, xdatum_count =0, xdatum_unchecked_count = 0, xref_count = 0;
+       struct jffs2_raw_node_ref *raw;
+       int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0;
+       int xdatum_orphan_count = 0, xref_orphan_count = 0, xref_dead_count = 0;
 
        BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING));
 
-       /* Phase.1 */
+       /* Phase.1 : Merge same xref */
+       for (i=0; i < XREF_TMPHASH_SIZE; i++)
+               xref_tmphash[i] = NULL;
        for (ref=c->xref_temp; ref; ref=_ref) {
+               struct jffs2_xattr_ref *tmp;
+
                _ref = ref->next;
-               /* checking REF_UNCHECKED nodes */
                if (ref_flags(ref->node) != REF_PRISTINE) {
                        if (verify_xattr_ref(c, ref)) {
-                               delete_xattr_ref_node(c, ref);
+                               BUG_ON(ref->node->next_in_ino != (void *)ref);
+                               ref->node->next_in_ino = NULL;
+                               jffs2_mark_node_obsolete(c, ref->node);
                                jffs2_free_xattr_ref(ref);
                                continue;
                        }
                }
-               /* At this point, ref->xid and ref->ino contain XID and inode number.
-                  ref->xd and ref->ic are not valid yet. */
-               xd = jffs2_find_xattr_datum(c, ref->xid);
-               ic = jffs2_get_ino_cache(c, ref->ino);
-               if (!xd || !ic) {
-                       if (ref_flags(ref->node) != REF_UNCHECKED)
-                               JFFS2_WARNING("xref(ino=%u, xid=%u) is orphan. \n",
-                                             ref->ino, ref->xid);
-                       delete_xattr_ref_node(c, ref);
+
+               i = (ref->ino ^ ref->xid) % XREF_TMPHASH_SIZE;
+               for (tmp=xref_tmphash[i]; tmp; tmp=tmp->next) {
+                       if (tmp->ino == ref->ino && tmp->xid == ref->xid)
+                               break;
+               }
+               if (tmp) {
+                       raw = ref->node;
+                       if (ref->xseqno > tmp->xseqno) {
+                               tmp->xseqno = ref->xseqno;
+                               raw->next_in_ino = tmp->node;
+                               tmp->node = raw;
+                       } else {
+                               raw->next_in_ino = tmp->node->next_in_ino;
+                               tmp->node->next_in_ino = raw;
+                       }
                        jffs2_free_xattr_ref(ref);
                        continue;
+               } else {
+                       ref->next = xref_tmphash[i];
+                       xref_tmphash[i] = ref;
                }
-               ref->xd = xd;
-               ref->ic = ic;
-               xd->refcnt++;
-               ref->next = ic->xref;
-               ic->xref = ref;
-               xref_count++;
        }
        c->xref_temp = NULL;
-       /* After this, ref->xid/ino are NEVER used. */
 
-       /* Phase.2 */
+       /* Phase.2 : Bind xref with inode_cache and xattr_datum */
+       for (i=0; i < XREF_TMPHASH_SIZE; i++) {
+               for (ref=xref_tmphash[i]; ref; ref=_ref) {
+                       xref_count++;
+                       _ref = ref->next;
+                       if (is_xattr_ref_dead(ref)) {
+                               ref->next = c->xref_dead_list;
+                               c->xref_dead_list = ref;
+                               xref_dead_count++;
+                               continue;
+                       }
+                       /* At this point, ref->xid and ref->ino contain XID and inode number.
+                          ref->xd and ref->ic are not valid yet. */
+                       xd = jffs2_find_xattr_datum(c, ref->xid);
+                       ic = jffs2_get_ino_cache(c, ref->ino);
+                       if (!xd || !ic) {
+                               dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
+                                         ref->ino, ref->xid, ref->xseqno);
+                               ref->xseqno |= XREF_DELETE_MARKER;
+                               ref->next = c->xref_dead_list;
+                               c->xref_dead_list = ref;
+                               xref_orphan_count++;
+                               continue;
+                       }
+                       ref->xd = xd;
+                       ref->ic = ic;
+                       atomic_inc(&xd->refcnt);
+                       ref->next = ic->xref;
+                       ic->xref = ref;
+               }
+       }
+
+       /* Phase.3 : Link unchecked xdatum to xattr_unchecked list */
        for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
                list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
+                       xdatum_count++;
                        list_del_init(&xd->xindex);
-                       if (!xd->refcnt) {
-                               if (ref_flags(xd->node) != REF_UNCHECKED)
-                                       JFFS2_WARNING("orphan xdatum(xid=%u, version=%u) at %#08x\n",
-                                                     xd->xid, xd->version, ref_offset(xd->node));
-                               delete_xattr_datum(c, xd);
+                       if (!atomic_read(&xd->refcnt)) {
+                               dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n",
+                                         xd->xid, xd->version);
+                               xd->flags |= JFFS2_XFLAGS_DEAD;
+                               list_add(&xd->xindex, &c->xattr_unchecked);
+                               xdatum_orphan_count++;
                                continue;
                        }
-                       if (ref_flags(xd->node) != REF_PRISTINE) {
-                               dbg_xattr("unchecked xdatum(xid=%u) at %#08x\n",
-                                         xd->xid, ref_offset(xd->node));
+                       if (is_xattr_datum_unchecked(c, xd)) {
+                               dbg_xattr("unchecked xdatum(xid=%u, version=%u)\n",
+                                         xd->xid, xd->version);
                                list_add(&xd->xindex, &c->xattr_unchecked);
                                xdatum_unchecked_count++;
                        }
-                       xdatum_count++;
                }
        }
        /* build complete */
-       JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and "
-                    "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count);
+       JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum"
+                    " (%u unchecked, %u orphan) and "
+                    "%u of xref (%u dead, %u orphan) found.\n",
+                    xdatum_count, xdatum_unchecked_count, xdatum_orphan_count,
+                    xref_count, xref_dead_count, xref_orphan_count);
 }
 
 struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
                                                  uint32_t xid, uint32_t version)
 {
-       struct jffs2_xattr_datum *xd, *_xd;
+       struct jffs2_xattr_datum *xd;
 
-       _xd = jffs2_find_xattr_datum(c, xid);
-       if (_xd) {
-               dbg_xattr("duplicate xdatum (xid=%u, version=%u/%u) at %#08x\n",
-                         xid, version, _xd->version, ref_offset(_xd->node));
-               if (version < _xd->version)
-                       return ERR_PTR(-EEXIST);
-       }
-       xd = jffs2_alloc_xattr_datum();
-       if (!xd)
-               return ERR_PTR(-ENOMEM);
-       xd->xid = xid;
-       xd->version = version;
-       if (xd->xid > c->highest_xid)
-               c->highest_xid = xd->xid;
-       list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
-
-       if (_xd) {
-               list_del_init(&_xd->xindex);
-               delete_xattr_datum_node(c, _xd);
-               jffs2_free_xattr_datum(_xd);
+       xd = jffs2_find_xattr_datum(c, xid);
+       if (!xd) {
+               xd = jffs2_alloc_xattr_datum();
+               if (!xd)
+                       return ERR_PTR(-ENOMEM);
+               xd->xid = xid;
+               xd->version = version;
+               if (xd->xid > c->highest_xid)
+                       c->highest_xid = xd->xid;
+               list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
        }
        return xd;
 }
@@ -1080,9 +1109,23 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
                                goto out;
                        }
                        if (!buffer) {
-                               *pref = ref->next;
-                               delete_xattr_ref(c, ref);
-                               rc = 0;
+                               ref->ino = ic->ino;
+                               ref->xid = xd->xid;
+                               ref->xseqno |= XREF_DELETE_MARKER;
+                               rc = save_xattr_ref(c, ref);
+                               if (!rc) {
+                                       *pref = ref->next;
+                                       spin_lock(&c->erase_completion_lock);
+                                       ref->next = c->xref_dead_list;
+                                       c->xref_dead_list = ref;
+                                       spin_unlock(&c->erase_completion_lock);
+                                       if (atomic_dec_and_test(&xd->refcnt))
+                                               delete_xattr_datum(c, xd);
+                               } else {
+                                       ref->ic = ic;
+                                       ref->xd = xd;
+                                       ref->xseqno &= ~XREF_DELETE_MARKER;
+                               }
                                goto out;
                        }
                        goto found;
@@ -1094,7 +1137,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
                goto out;
        }
        if (!buffer) {
-               rc = -EINVAL;
+               rc = -ENODATA;
                goto out;
        }
  found:
@@ -1110,16 +1153,14 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
        request = PAD(sizeof(struct jffs2_raw_xref));
        rc = jffs2_reserve_space(c, request, &length,
                                 ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE);
+       down_write(&c->xattr_sem);
        if (rc) {
                JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
-               down_write(&c->xattr_sem);
-               xd->refcnt--;
-               if (!xd->refcnt)
+               if (atomic_dec_and_test(&xd->refcnt))
                        delete_xattr_datum(c, xd);
                up_write(&c->xattr_sem);
                return rc;
        }
-       down_write(&c->xattr_sem);
        if (ref)
                *pref = ref->next;
        newref = create_xattr_ref(c, ic, xd);
@@ -1129,8 +1170,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
                        ic->xref = ref;
                }
                rc = PTR_ERR(newref);
-               xd->refcnt--;
-               if (!xd->refcnt)
+               if (atomic_dec_and_test(&xd->refcnt))
                        delete_xattr_datum(c, xd);
        } else if (ref) {
                delete_xattr_ref(c, ref);
@@ -1142,38 +1182,40 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
 }
 
 /* -------- garbage collector functions -------------
- * jffs2_garbage_collect_xattr_datum(c, xd)
+ * jffs2_garbage_collect_xattr_datum(c, xd, raw)
  *   is used to move xdatum into new node.
- * jffs2_garbage_collect_xattr_ref(c, ref)
+ * jffs2_garbage_collect_xattr_ref(c, ref, raw)
  *   is used to move xref into new node.
  * jffs2_verify_xattr(c)
  *   is used to call do_verify_xattr_datum() before garbage collecting.
+ * jffs2_release_xattr_datum(c, xd)
+ *   is used to release an in-memory object of xdatum.
+ * jffs2_release_xattr_ref(c, ref)
+ *   is used to release an in-memory object of xref.
  * -------------------------------------------------- */
-int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd,
+                                     struct jffs2_raw_node_ref *raw)
 {
        uint32_t totlen, length, old_ofs;
-       int rc = -EINVAL;
+       int rc = 0;
 
        down_write(&c->xattr_sem);
-       BUG_ON(!xd->node);
-
-       old_ofs = ref_offset(xd->node);
-       totlen = ref_totlen(c, c->gcblock, xd->node);
-       if (totlen < sizeof(struct jffs2_raw_xattr))
+       if (xd->node != raw)
+               goto out;
+       if (xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID))
                goto out;
 
-       if (!xd->xname) {
-               rc = load_xattr_datum(c, xd);
-               if (unlikely(rc > 0)) {
-                       delete_xattr_datum_node(c, xd);
-                       rc = 0;
-                       goto out;
-               } else if (unlikely(rc < 0))
-                       goto out;
+       rc = load_xattr_datum(c, xd);
+       if (unlikely(rc)) {
+               rc = (rc > 0) ? 0 : rc;
+               goto out;
        }
+       old_ofs = ref_offset(xd->node);
+       totlen = PAD(sizeof(struct jffs2_raw_xattr)
+                       + xd->name_len + 1 + xd->value_len);
        rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE);
-       if (rc || length < totlen) {
-               JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, totlen);
+       if (rc) {
+               JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen);
                rc = rc ? rc : -EBADFD;
                goto out;
        }
@@ -1182,27 +1224,32 @@ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xatt
                dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n",
                          xd->xid, xd->version, old_ofs, ref_offset(xd->node));
  out:
+       if (!rc)
+               jffs2_mark_node_obsolete(c, raw);
        up_write(&c->xattr_sem);
        return rc;
 }
 
-
-int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref,
+                                   struct jffs2_raw_node_ref *raw)
 {
        uint32_t totlen, length, old_ofs;
-       int rc = -EINVAL;
+       int rc = 0;
 
        down_write(&c->xattr_sem);
        BUG_ON(!ref->node);
 
+       if (ref->node != raw)
+               goto out;
+       if (is_xattr_ref_dead(ref) && (raw->next_in_ino == (void *)ref))
+               goto out;
+
        old_ofs = ref_offset(ref->node);
        totlen = ref_totlen(c, c->gcblock, ref->node);
-       if (totlen != sizeof(struct jffs2_raw_xref))
-               goto out;
 
        rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XREF_SIZE);
-       if (rc || length < totlen) {
-               JFFS2_WARNING("%s: jffs2_reserve_space() = %d, request = %u\n",
+       if (rc) {
+               JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n",
                              __FUNCTION__, rc, totlen);
                rc = rc ? rc : -EBADFD;
                goto out;
@@ -1212,6 +1259,8 @@ int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_
                dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n",
                          ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node));
  out:
+       if (!rc)
+               jffs2_mark_node_obsolete(c, raw);
        up_write(&c->xattr_sem);
        return rc;
 }
@@ -1219,20 +1268,59 @@ int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_
 int jffs2_verify_xattr(struct jffs2_sb_info *c)
 {
        struct jffs2_xattr_datum *xd, *_xd;
+       struct jffs2_eraseblock *jeb;
+       struct jffs2_raw_node_ref *raw;
+       uint32_t totlen;
        int rc;
 
        down_write(&c->xattr_sem);
        list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
                rc = do_verify_xattr_datum(c, xd);
-               if (rc == 0) {
-                       list_del_init(&xd->xindex);
-                       break;
-               } else if (rc > 0) {
-                       list_del_init(&xd->xindex);
-                       delete_xattr_datum_node(c, xd);
+               if (rc < 0)
+                       continue;
+               list_del_init(&xd->xindex);
+               spin_lock(&c->erase_completion_lock);
+               for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+                       if (ref_flags(raw) != REF_UNCHECKED)
+                               continue;
+                       jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+                       totlen = PAD(ref_totlen(c, jeb, raw));
+                       c->unchecked_size -= totlen; c->used_size += totlen;
+                       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+                       raw->flash_offset = ref_offset(raw)
+                               | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL);
                }
+               if (xd->flags & JFFS2_XFLAGS_DEAD)
+                       list_add(&xd->xindex, &c->xattr_dead_list);
+               spin_unlock(&c->erase_completion_lock);
        }
        up_write(&c->xattr_sem);
-
        return list_empty(&c->xattr_unchecked) ? 1 : 0;
 }
+
+void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+       /* must be called under spin_lock(&c->erase_completion_lock) */
+       if (atomic_read(&xd->refcnt) || xd->node != (void *)xd)
+               return;
+
+       list_del(&xd->xindex);
+       jffs2_free_xattr_datum(xd);
+}
+
+void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+       /* must be called under spin_lock(&c->erase_completion_lock) */
+       struct jffs2_xattr_ref *tmp, **ptmp;
+
+       if (ref->node != (void *)ref)
+               return;
+
+       for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) {
+               if (ref == tmp) {
+                       *ptmp = tmp->next;
+                       break;
+               }
+       }
+       jffs2_free_xattr_ref(ref);
+}
index 2c199856c58256b4726649b80d56a5bf975ae54e..06a5c69dcf8b1052d3dd8177d19a90198b9e284c 100644 (file)
@@ -16,6 +16,8 @@
 
 #define JFFS2_XFLAGS_HOT       (0x01)  /* This datum is HOT */
 #define JFFS2_XFLAGS_BIND      (0x02)  /* This datum is not reclaimed */
+#define JFFS2_XFLAGS_DEAD      (0x40)  /* This datum is already dead */
+#define JFFS2_XFLAGS_INVALID   (0x80)  /* This datum contains crc error */
 
 struct jffs2_xattr_datum
 {
@@ -23,10 +25,10 @@ struct jffs2_xattr_datum
        struct jffs2_raw_node_ref *node;
        uint8_t class;
        uint8_t flags;
-       uint16_t xprefix;                       /* see JFFS2_XATTR_PREFIX_* */
+       uint16_t xprefix;               /* see JFFS2_XATTR_PREFIX_* */
 
        struct list_head xindex;        /* chained from c->xattrindex[n] */
-       uint32_t refcnt;                /* # of xattr_ref refers this */
+       atomic_t refcnt;                /* # of xattr_ref refers this */
        uint32_t xid;
        uint32_t version;
 
@@ -47,6 +49,7 @@ struct jffs2_xattr_ref
        uint8_t flags;          /* Currently unused */
        u16 unused;
 
+       uint32_t xseqno;
        union {
                struct jffs2_inode_cache *ic;   /* reference to jffs2_inode_cache */
                uint32_t ino;                   /* only used in scanning/building  */
@@ -58,6 +61,12 @@ struct jffs2_xattr_ref
        struct jffs2_xattr_ref *next;           /* chained from ic->xref_list */
 };
 
+#define XREF_DELETE_MARKER     (0x00000001)
+static inline int is_xattr_ref_dead(struct jffs2_xattr_ref *ref)
+{
+       return ((ref->xseqno & XREF_DELETE_MARKER) != 0);
+}
+
 #ifdef CONFIG_JFFS2_FS_XATTR
 
 extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c);
@@ -70,9 +79,13 @@ extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c
 extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 
-extern int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd);
-extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref);
+extern int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd,
+                                            struct jffs2_raw_node_ref *raw);
+extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref,
+                                          struct jffs2_raw_node_ref *raw);
 extern int jffs2_verify_xattr(struct jffs2_sb_info *c);
+extern void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd);
+extern void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref);
 
 extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
                             char *buffer, size_t size);
index 04eb78f1252e6b70f0383d63dbb2369dd5ca70f6..43e3f566aad65fb26a4dcf92845675d561746601 100644 (file)
@@ -305,7 +305,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
                                offset, nr_segs, jfs_get_block, NULL);
 }
 
-struct address_space_operations jfs_aops = {
+const struct address_space_operations jfs_aops = {
        .readpage       = jfs_readpage,
        .readpages      = jfs_readpages,
        .writepage      = jfs_writepage,
index c300726744641869b6e4f87794b2ece81d9b8280..b5c7da6190dc0ac2364536650923941b8fa43ac8 100644 (file)
@@ -33,7 +33,7 @@ extern void jfs_free_zero_link(struct inode *);
 extern struct dentry *jfs_get_parent(struct dentry *dentry);
 extern void jfs_set_inode_flags(struct inode *);
 
-extern struct address_space_operations jfs_aops;
+extern const struct address_space_operations jfs_aops;
 extern struct inode_operations jfs_dir_inode_operations;
 extern const struct file_operations jfs_dir_operations;
 extern struct inode_operations jfs_file_inode_operations;
index 7f6e88039700c085b09188b8ad350aaecc5b6733..e1e0a6e6ebdfb8d0e1c591a124a249e908fb2174 100644 (file)
@@ -577,7 +577,7 @@ static void metapage_invalidatepage(struct page *page, unsigned long offset)
        metapage_releasepage(page, 0);
 }
 
-struct address_space_operations jfs_metapage_aops = {
+const struct address_space_operations jfs_metapage_aops = {
        .readpage       = metapage_readpage,
        .writepage      = metapage_writepage,
        .sync_page      = block_sync_page,
index f0b7d3282b07397f49d61d65448d1778caf4173b..d17a3290f5aab901253c0f2d43b136a237dc893d 100644 (file)
@@ -139,7 +139,7 @@ static inline void metapage_homeok(struct metapage *mp)
        put_metapage(mp);
 }
 
-extern struct address_space_operations jfs_metapage_aops;
+extern const struct address_space_operations jfs_metapage_aops;
 
 /*
  * This routines invalidate all pages for an extent.
index a6fb509b7341153e729112c8d28fadca1fae2dfd..9ea91c5eeb7b27af1cd054c1887d514dc63db1f2 100644 (file)
@@ -335,7 +335,7 @@ static sector_t minix_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,minix_get_block);
 }
-static struct address_space_operations minix_aops = {
+static const struct address_space_operations minix_aops = {
        .readpage = minix_readpage,
        .writepage = minix_writepage,
        .sync_page = block_sync_page,
index 90d2ea28f333dfef1695c1a4a228934455383618..6c51c1198464efff9de569e5c98228b93206cf94 100644 (file)
@@ -105,7 +105,7 @@ static struct super_operations ncp_sops =
 
 extern struct dentry_operations ncp_root_dentry_operations;
 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
-extern struct address_space_operations ncp_symlink_aops;
+extern const struct address_space_operations ncp_symlink_aops;
 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
 #endif
 
index e935f1b34bc2935e589979ee69c32a2fada36863..f76b1392a012cbc291de7284437d862dc0c7a253 100644 (file)
@@ -99,7 +99,7 @@ fail:
 /*
  * symlinks can't do much...
  */
-struct address_space_operations ncp_symlink_aops = {
+const struct address_space_operations ncp_symlink_aops = {
        .readpage       = ncp_symlink_readpage,
 };
        
index add289138836d9cab60a7687f79ac40f09af19f6..cc2b874ad5a4c38f4c63c0fe4b24028bbec6b030 100644 (file)
@@ -315,7 +315,7 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
        return !nfs_wb_page(page->mapping->host, page);
 }
 
-struct address_space_operations nfs_file_aops = {
+const struct address_space_operations nfs_file_aops = {
        .readpage = nfs_readpage,
        .readpages = nfs_readpages,
        .set_page_dirty = __set_page_dirty_nobuffers,
index 1630b5670dc2652ff36b9bee862f68a386904933..7c7d01672d35a4dc47bbd5ca5d059adcdc1c6598 100644 (file)
@@ -123,7 +123,7 @@ static void release_stateid(struct nfs4_stateid *stp, int flags);
  */
 
 /* recall_lock protects the del_recall_lru */
-static spinlock_t recall_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(recall_lock);
 static struct list_head del_recall_lru;
 
 static void
index 580412d330cb9187035d037d9259e52222f0f87f..bc579bfdfbd8ff0c09c701a849b8b61c362b0fa0 100644 (file)
@@ -1544,7 +1544,7 @@ err_out:
 /**
  * ntfs_aops - general address space operations for inodes and attributes
  */
-struct address_space_operations ntfs_aops = {
+const struct address_space_operations ntfs_aops = {
        .readpage       = ntfs_readpage,        /* Fill page with data. */
        .sync_page      = block_sync_page,      /* Currently, just unplugs the
                                                   disk request queue. */
@@ -1560,7 +1560,7 @@ struct address_space_operations ntfs_aops = {
  * ntfs_mst_aops - general address space operations for mst protecteed inodes
  *                and attributes
  */
-struct address_space_operations ntfs_mst_aops = {
+const struct address_space_operations ntfs_mst_aops = {
        .readpage       = ntfs_readpage,        /* Fill page with data. */
        .sync_page      = block_sync_page,      /* Currently, just unplugs the
                                                   disk request queue. */
index bf7b3d7c09303a17de113173b80b2b8890d97ecb..ddd3d503097c081e42176abb5fd494864fcf56c4 100644 (file)
@@ -57,8 +57,8 @@ extern struct kmem_cache *ntfs_attr_ctx_cache;
 extern struct kmem_cache *ntfs_index_ctx_cache;
 
 /* The various operations structs defined throughout the driver files. */
-extern struct address_space_operations ntfs_aops;
-extern struct address_space_operations ntfs_mst_aops;
+extern const struct address_space_operations ntfs_aops;
+extern const struct address_space_operations ntfs_mst_aops;
 
 extern const struct  file_operations ntfs_file_ops;
 extern struct inode_operations ntfs_file_inode_ops;
index 47152bf9a7f26cdfb82cd02240e5546ba3e47485..cca71317b6d6144e5bd381bacb9149a6f9fddde5 100644 (file)
@@ -666,7 +666,7 @@ out:
        return ret;
 }
 
-struct address_space_operations ocfs2_aops = {
+const struct address_space_operations ocfs2_aops = {
        .readpage       = ocfs2_readpage,
        .writepage      = ocfs2_writepage,
        .prepare_write  = ocfs2_prepare_write,
index 21f38accd0399dd26f6fa1da70af16209c01469e..1d26cfcd9f8406a531ab8acd61a5c813633658a8 100644 (file)
@@ -54,7 +54,7 @@ static DECLARE_RWSEM(o2hb_callback_sem);
  * multiple hb threads are watching multiple regions.  A node is live
  * whenever any of the threads sees activity from the node in its region.
  */
-static spinlock_t o2hb_live_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(o2hb_live_lock);
 static struct list_head o2hb_live_slots[O2NM_MAX_NODES];
 static unsigned long o2hb_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
 static LIST_HEAD(o2hb_node_events);
index 0f60cc0d3985d9e80596e3f63b7059cb594d7d97..1591eb37a72366dc2e4ecbac76128e2d5b7e0d26 100644 (file)
            ##args);                                                    \
 } while (0)
 
-static rwlock_t o2net_handler_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(o2net_handler_lock);
 static struct rb_root o2net_handler_tree = RB_ROOT;
 
 static struct o2net_node o2net_nodes[O2NM_MAX_NODES];
index ba27c5c5e95939192f0bacfe5bfeb7c2776d67a3..b8c23f7ba67e1caf791af2e8f4f28e8f0c6e6413 100644 (file)
@@ -88,7 +88,7 @@ out_free:
  *
  */
 
-spinlock_t dlm_domain_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(dlm_domain_lock);
 LIST_HEAD(dlm_domains);
 static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events);
 
index d6f89577e25f1b0ac55f5ac8e931013ff2b460ee..5ca57ec650c77657c76e82e66f83dea2180da01a 100644 (file)
@@ -53,7 +53,7 @@
 #define MLOG_MASK_PREFIX ML_DLM
 #include "cluster/masklog.h"
 
-static spinlock_t dlm_cookie_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(dlm_cookie_lock);
 static u64 dlm_next_cookie = 1;
 
 static enum dlm_status dlm_send_remote_lock_request(struct dlm_ctxt *dlm,
index da399013516ffe5947ac111f09b963e8c5a9c99b..29b2845f370d85b1a4b642af386553cd6178f708 100644 (file)
@@ -98,8 +98,8 @@ static void dlm_mig_lockres_worker(struct dlm_work_item *item, void *data);
 
 static u64 dlm_get_next_mig_cookie(void);
 
-static spinlock_t dlm_reco_state_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t dlm_mig_cookie_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(dlm_reco_state_lock);
+static DEFINE_SPINLOCK(dlm_mig_cookie_lock);
 static u64 dlm_mig_cookie = 1;
 
 static u64 dlm_get_next_mig_cookie(void)
index 64cd52860c876943d3a51a373f8a74df9f7067f5..4acd37286bdd7cb4b0807da5b338a9f6753ffb99 100644 (file)
@@ -242,7 +242,7 @@ static void ocfs2_build_lock_name(enum ocfs2_lock_type type,
        mlog_exit_void();
 }
 
-static spinlock_t ocfs2_dlm_tracking_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ocfs2_dlm_tracking_lock);
 
 static void ocfs2_add_lockres_tracking(struct ocfs2_lock_res *res,
                                       struct ocfs2_dlm_debug *dlm_debug)
index 84c5079612870bae7ba80aa5e8831a63564687d9..35140f6cf840eedbfde59f23515e8342f9c9ab7a 100644 (file)
@@ -114,7 +114,7 @@ static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode)
 
 extern kmem_cache_t *ocfs2_inode_cache;
 
-extern struct address_space_operations ocfs2_aops;
+extern const struct address_space_operations ocfs2_aops;
 
 struct buffer_head *ocfs2_bread(struct inode *inode, int block,
                                int *err, int reada);
index 3fe8781c22cb68fedf6c5d8189c9aab3f88fa0d1..910a601b2e9820cf4986e3e620faa534277cf072 100644 (file)
@@ -49,7 +49,7 @@
 
 #include "buffer_head_io.h"
 
-spinlock_t trans_inc_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(trans_inc_lock);
 
 static int ocfs2_force_read_journal(struct inode *inode);
 static int ocfs2_recover_node(struct ocfs2_super *osb,
index ee42765a8553e9c5ed51e47805f9bd1440679399..cf70fe2075b8f58e1a4109e7872da1cc7c246c21 100644 (file)
@@ -988,9 +988,7 @@ int ocfs2_request_mount_vote(struct ocfs2_super *osb)
        }
 
 bail:
-       if (request)
-               kfree(request);
-
+       kfree(request);
        return status;
 }
 
@@ -1021,9 +1019,7 @@ int ocfs2_request_umount_vote(struct ocfs2_super *osb)
        }
 
 bail:
-       if (request)
-               kfree(request);
-
+       kfree(request);
        return status;
 }
 
index 0137ec4c1368888d906d6eb543a238e5dca18236..0a163a4f7764059f7401c8b43cae42ca9c2bef43 100644 (file)
@@ -122,6 +122,11 @@ struct mem_size_stats
        unsigned long private_dirty;
 };
 
+__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma)
+{
+       return NULL;
+}
+
 static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
 {
        struct proc_maps_private *priv = m->private;
@@ -158,22 +163,23 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
                pad_len_spaces(m, len);
                seq_path(m, file->f_vfsmnt, file->f_dentry, "\n");
        } else {
-               if (mm) {
-                       if (vma->vm_start <= mm->start_brk &&
+               const char *name = arch_vma_name(vma);
+               if (!name) {
+                       if (mm) {
+                               if (vma->vm_start <= mm->start_brk &&
                                                vma->vm_end >= mm->brk) {
-                               pad_len_spaces(m, len);
-                               seq_puts(m, "[heap]");
-                       } else {
-                               if (vma->vm_start <= mm->start_stack &&
-                                       vma->vm_end >= mm->start_stack) {
-
-                                       pad_len_spaces(m, len);
-                                       seq_puts(m, "[stack]");
+                                       name = "[heap]";
+                               } else if (vma->vm_start <= mm->start_stack &&
+                                          vma->vm_end >= mm->start_stack) {
+                                       name = "[stack]";
                                }
+                       } else {
+                               name = "[vdso]";
                        }
-               } else {
+               }
+               if (name) {
                        pad_len_spaces(m, len);
-                       seq_puts(m, "[vdso]");
+                       seq_puts(m, name);
                }
        }
        seq_putc(m, '\n');
index 2f24c46f72a1bdc19b21062c78cfb07838a67151..8bc182a88748a91abbdc7b46032d81ac5c9ad9fa 100644 (file)
@@ -450,7 +450,7 @@ static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,qnx4_get_block);
 }
-static struct address_space_operations qnx4_aops = {
+static const struct address_space_operations qnx4_aops = {
        .readpage       = qnx4_readpage,
        .writepage      = qnx4_writepage,
        .sync_page      = block_sync_page,
index 00a933eb820c27127cc330adbca12e6518deb4d8..86f14cacf64120569f2fd0ad8e6ee573de98eb4e 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <linux/fs.h>
 
-struct address_space_operations ramfs_aops = {
+const struct address_space_operations ramfs_aops = {
        .readpage       = simple_readpage,
        .prepare_write  = simple_prepare_write,
        .commit_write   = simple_commit_write
index f443a84b98a5a300b21fbf298f7aa2587e6e83eb..99fffc9e1bfd6ebf4959ac6415d8e80e19deff56 100644 (file)
@@ -27,7 +27,7 @@
 
 static int ramfs_nommu_setattr(struct dentry *, struct iattr *);
 
-struct address_space_operations ramfs_aops = {
+const struct address_space_operations ramfs_aops = {
        .readpage               = simple_readpage,
        .prepare_write          = simple_prepare_write,
        .commit_write           = simple_commit_write
index 313237631b49dda2c66145fcc0bab146cc5472aa..c2bb58e74653351797d75c654b855b1fa72b4ed5 100644 (file)
@@ -10,6 +10,6 @@
  */
 
 
-extern struct address_space_operations ramfs_aops;
+extern const struct address_space_operations ramfs_aops;
 extern const struct file_operations ramfs_file_operations;
 extern struct inode_operations ramfs_file_inode_operations;
index 9857e50f85e723c00637ce6e26604cf8f07b6e7b..a24858a632fab85ef57f3ebf291a8a2235f2f182 100644 (file)
@@ -2996,7 +2996,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
        return error;
 }
 
-struct address_space_operations reiserfs_address_space_operations = {
+const struct address_space_operations reiserfs_address_space_operations = {
        .writepage = reiserfs_writepage,
        .readpage = reiserfs_readpage,
        .readpages = reiserfs_readpages,
index 283fbc6b8eea3776a685135d899ffc7daddaac3e..22eed61ebf693dd70c51c1bebe1938d2ffb0f528 100644 (file)
@@ -459,7 +459,7 @@ err_out:
 
 /* Mapping from our types to the kernel */
 
-static struct address_space_operations romfs_aops = {
+static const struct address_space_operations romfs_aops = {
        .readpage = romfs_readpage
 };
 
index ed9a24d19d7d312ed5336c7d0873a059e3c804fb..dae67048baba345fcbd6358e4a84fd890f834633 100644 (file)
@@ -306,7 +306,7 @@ static int smb_commit_write(struct file *file, struct page *page,
        return status;
 }
 
-struct address_space_operations smb_file_aops = {
+const struct address_space_operations smb_file_aops = {
        .readpage = smb_readpage,
        .writepage = smb_writepage,
        .prepare_write = smb_prepare_write,
index 972ed7dad388c3bc9c1075e36a61bced30ded427..34fb462b23795c63581648ab69149faaf7bedfd4 100644 (file)
@@ -63,7 +63,7 @@ extern int smb_revalidate_inode(struct dentry *dentry);
 extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
 extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
 /* file.c */
-extern struct address_space_operations smb_file_aops;
+extern const struct address_space_operations smb_file_aops;
 extern const struct file_operations smb_file_operations;
 extern struct inode_operations smb_file_inode_operations;
 /* ioctl.c */
index f0b347bd12ca52d6636b2cadae31a7f45f2067a7..5e0e31cc46f5e269ebb8ed5c2fddec10f240e512 100644 (file)
@@ -16,7 +16,7 @@
 
 extern struct super_block * sysfs_sb;
 
-static struct address_space_operations sysfs_aops = {
+static const struct address_space_operations sysfs_aops = {
        .readpage       = simple_readpage,
        .prepare_write  = simple_prepare_write,
        .commit_write   = simple_commit_write
index 86f5f8d43d0f6debbfcd26ba292140cfe4fed0d9..f2bcccd1d6fcf42fb9ac5db739eaf33d2ad43fc4 100644 (file)
@@ -465,7 +465,7 @@ static sector_t sysv_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,get_block);
 }
-struct address_space_operations sysv_aops = {
+const struct address_space_operations sysv_aops = {
        .readpage = sysv_readpage,
        .writepage = sysv_writepage,
        .sync_page = block_sync_page,
index 393a480e4deb0860190a1bda62d37178d2846d85..9dcc82120935baba74960a691fc0ef15d2b1009b 100644 (file)
@@ -161,7 +161,7 @@ extern struct inode_operations sysv_dir_inode_operations;
 extern struct inode_operations sysv_fast_symlink_inode_operations;
 extern const struct file_operations sysv_file_operations;
 extern const struct file_operations sysv_dir_operations;
-extern struct address_space_operations sysv_aops;
+extern const struct address_space_operations sysv_aops;
 extern struct super_operations sysv_sops;
 extern struct dentry_operations sysv_dentry_operations;
 
index e34b00e303f13ae9cdd75d35a3649b6346b5c027..a59e5f33daf6f7ed5225d8f85c349acbf29f05ab 100644 (file)
@@ -95,7 +95,7 @@ static int udf_adinicb_commit_write(struct file *file, struct page *page, unsign
        return 0;
 }
 
-struct address_space_operations udf_adinicb_aops = {
+const struct address_space_operations udf_adinicb_aops = {
        .readpage               = udf_adinicb_readpage,
        .writepage              = udf_adinicb_writepage,
        .sync_page              = block_sync_page,
index 2983afd5e7fd4932ca77cd24e95041f94b719062..605f5111b6d86a100430897877f170c2b59248e7 100644 (file)
@@ -132,7 +132,7 @@ static sector_t udf_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping,block,udf_get_block);
 }
 
-struct address_space_operations udf_aops = {
+const struct address_space_operations udf_aops = {
        .readpage               = udf_readpage,
        .writepage              = udf_writepage,
        .sync_page              = block_sync_page,
index 674bb40edc839475cb4bdf5f1fd3b789808ee144..ba068a7865630bb07a8f968a91d20c13245c143f 100644 (file)
@@ -113,6 +113,6 @@ out:
 /*
  * symlinks can't do much...
  */
-struct address_space_operations udf_symlink_aops = {
+const struct address_space_operations udf_symlink_aops = {
        .readpage               = udf_symlink_filler,
 };
index 023e19ba5a2ee8be3d2f4df434564aa70a5f1dc8..2f992387cc9ed0a9cba2bd64c704d2e175f78fe2 100644 (file)
@@ -47,9 +47,9 @@ extern struct inode_operations udf_dir_inode_operations;
 extern const struct file_operations udf_dir_operations;
 extern struct inode_operations udf_file_inode_operations;
 extern const struct file_operations udf_file_operations;
-extern struct address_space_operations udf_aops;
-extern struct address_space_operations udf_adinicb_aops;
-extern struct address_space_operations udf_symlink_aops;
+extern const struct address_space_operations udf_aops;
+extern const struct address_space_operations udf_adinicb_aops;
+extern const struct address_space_operations udf_symlink_aops;
 
 struct udf_fileident_bh
 {
index f2dbdf5a8769765d4ca175250e19e0659bb5f7c8..488b5ff48afb1330ca5f40360af42e25231637d3 100644 (file)
@@ -98,7 +98,9 @@ static u64 ufs_frag_map(struct inode *inode, sector_t frag)
        u64 temp = 0L;
 
        UFSD(": frag = %llu  depth = %d\n", (unsigned long long)frag, depth);
-       UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask);
+       UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",
+               uspi->s_fpbshift, uspi->s_apbmask,
+               (unsigned long long)mask);
 
        if (depth == 0)
                return 0;
@@ -429,7 +431,7 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head
        
        if (!create) {
                phys64 = ufs_frag_map(inode, fragment);
-               UFSD("phys64 = %llu \n",phys64);
+               UFSD("phys64 = %llu\n", (unsigned long long)phys64);
                if (phys64)
                        map_bh(bh_result, sb, phys64);
                return 0;
@@ -574,7 +576,7 @@ static sector_t ufs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,ufs_getfrag_block);
 }
-struct address_space_operations ufs_aops = {
+const struct address_space_operations ufs_aops = {
        .readpage = ufs_readpage,
        .writepage = ufs_writepage,
        .sync_page = block_sync_page,
@@ -605,39 +607,12 @@ static void ufs_set_inode_ops(struct inode *inode)
                                   ufs_get_inode_dev(inode->i_sb, UFS_I(inode)));
 }
 
-void ufs_read_inode (struct inode * inode)
+static void ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode)
 {
        struct ufs_inode_info *ufsi = UFS_I(inode);
-       struct super_block * sb;
-       struct ufs_sb_private_info * uspi;
-       struct ufs_inode * ufs_inode;   
-       struct ufs2_inode *ufs2_inode;
-       struct buffer_head * bh;
+       struct super_block *sb = inode->i_sb;
        mode_t mode;
        unsigned i;
-       unsigned flags;
-       
-       UFSD("ENTER, ino %lu\n", inode->i_ino);
-       
-       sb = inode->i_sb;
-       uspi = UFS_SB(sb)->s_uspi;
-       flags = UFS_SB(sb)->s_flags;
-
-       if (inode->i_ino < UFS_ROOTINO || 
-           inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
-               ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino);
-               goto bad_inode;
-       }
-       
-       bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
-       if (!bh) {
-               ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
-               goto bad_inode;
-       }
-       if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
-               goto ufs2_inode;
-
-       ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino));
 
        /*
         * Copy data to the in-core inode.
@@ -661,14 +636,11 @@ void ufs_read_inode (struct inode * inode)
        inode->i_atime.tv_nsec = 0;
        inode->i_ctime.tv_nsec = 0;
        inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks);
-       inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat) */
-       inode->i_version++;
        ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
        ufsi->i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen);
        ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
        ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
-       ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
-       ufsi->i_dir_start_lookup = 0;
+
        
        if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
@@ -677,24 +649,16 @@ void ufs_read_inode (struct inode * inode)
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
                        ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
        }
-       ufsi->i_osync = 0;
-
-       ufs_set_inode_ops(inode);
-
-       brelse (bh);
-
-       UFSD("EXIT\n");
-       return;
+}
 
-bad_inode:
-       make_bad_inode(inode);
-       return;
+static void ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
+{
+       struct ufs_inode_info *ufsi = UFS_I(inode);
+       struct super_block *sb = inode->i_sb;
+       mode_t mode;
+       unsigned i;
 
-ufs2_inode :
        UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino);
-
-       ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino));
-
        /*
         * Copy data to the in-core inode.
         */
@@ -717,26 +681,64 @@ ufs2_inode :
        inode->i_atime.tv_nsec = 0;
        inode->i_ctime.tv_nsec = 0;
        inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks);
-       inode->i_blksize = PAGE_SIZE; /*This is the optimal IO size(for stat)*/
-
-       inode->i_version++;
        ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags);
        ufsi->i_gen = fs32_to_cpu(sb, ufs2_inode->ui_gen);
        /*
        ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
        ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
        */
-       ufsi->i_lastfrag= (inode->i_size + uspi->s_fsize- 1) >> uspi->s_fshift;
 
        if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
                        ufsi->i_u1.u2_i_data[i] =
                                ufs2_inode->ui_u2.ui_addr.ui_db[i];
-       }
-       else {
+       } else {
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
                        ufsi->i_u1.i_symlink[i] = ufs2_inode->ui_u2.ui_symlink[i];
        }
+}
+
+void ufs_read_inode(struct inode * inode)
+{
+       struct ufs_inode_info *ufsi = UFS_I(inode);
+       struct super_block * sb;
+       struct ufs_sb_private_info * uspi;
+       struct buffer_head * bh;
+
+       UFSD("ENTER, ino %lu\n", inode->i_ino);
+
+       sb = inode->i_sb;
+       uspi = UFS_SB(sb)->s_uspi;
+
+       if (inode->i_ino < UFS_ROOTINO ||
+           inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
+               ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n",
+                           inode->i_ino);
+               goto bad_inode;
+       }
+
+       bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
+       if (!bh) {
+               ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n",
+                           inode->i_ino);
+               goto bad_inode;
+       }
+       if ((UFS_SB(sb)->s_flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+               struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data;
+
+               ufs2_read_inode(inode,
+                               ufs2_inode + ufs_inotofsbo(inode->i_ino));
+       } else {
+               struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data;
+
+               ufs1_read_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino));
+       }
+
+       inode->i_blksize = PAGE_SIZE;/*This is the optimal IO size (for stat)*/
+       inode->i_version++;
+       ufsi->i_lastfrag =
+               (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
+       ufsi->i_dir_start_lookup = 0;
        ufsi->i_osync = 0;
 
        ufs_set_inode_ops(inode);
@@ -745,6 +747,9 @@ ufs2_inode :
 
        UFSD("EXIT\n");
        return;
+
+bad_inode:
+       make_bad_inode(inode);
 }
 
 static int ufs_update_inode(struct inode * inode, int do_sync)
index 3e807b828e221464131d088367496f86f54bb033..c40f81ba9b130426125228e5bfac38d7059bfd1e 100644 (file)
@@ -1454,7 +1454,7 @@ xfs_vm_invalidatepage(
        block_invalidatepage(page, offset);
 }
 
-struct address_space_operations xfs_address_space_operations = {
+const struct address_space_operations xfs_address_space_operations = {
        .readpage               = xfs_vm_readpage,
        .readpages              = xfs_vm_readpages,
        .writepage              = xfs_vm_writepage,
index 706d8c781b8a54b474f7a3d5ecb23a42bf8e8352..2244e516b66a339600830928682a7155df931639 100644 (file)
@@ -40,7 +40,7 @@ typedef struct xfs_ioend {
        struct work_struct      io_work;        /* xfsdatad work queue */
 } xfs_ioend_t;
 
-extern struct address_space_operations xfs_address_space_operations;
+extern const struct address_space_operations xfs_address_space_operations;
 extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
 
 #endif /* __XFS_AOPS_H__ */
index 26fed0756f0100b5c2e2aec31eb5e1f5853c9ed4..2af528dcfb0428ca93f2a5dced879e400682b876 100644 (file)
@@ -1520,7 +1520,7 @@ xfs_mapping_buftarg(
        struct backing_dev_info *bdi;
        struct inode            *inode;
        struct address_space    *mapping;
-       static struct address_space_operations mapping_aops = {
+       static const struct address_space_operations mapping_aops = {
                .sync_page = block_sync_page,
                .migratepage = fail_migrate_page,
        };
index 12810baeb5d4ad7e4c54c7690b08d2fa3fe9de1c..d9180020de6328fa8dbbeb17f68027805d368fae 100644 (file)
@@ -419,16 +419,15 @@ xfs_vn_link(
        int             error;
 
        ip = old_dentry->d_inode;       /* inode being linked to */
-       if (S_ISDIR(ip->i_mode))
-               return -EPERM;
-
        tdvp = vn_from_inode(dir);
        vp = vn_from_inode(ip);
 
+       VN_HOLD(vp);
        error = bhv_vop_link(tdvp, vp, dentry, NULL);
-       if (likely(!error)) {
+       if (unlikely(error)) {
+               VN_RELE(vp);
+       } else {
                VMODIFY(tdvp);
-               VN_HOLD(vp);
                xfs_validate_fields(ip, &vattr);
                d_instantiate(dentry, ip);
        }
index aa26ab906c88cda071d9a2ca54cc79ee2cea6317..028eb17ec2edd8b17e35b333e1b0692ba63414c7 100644 (file)
@@ -140,9 +140,7 @@ BUFFER_FNS(PrivateStart, unwritten);
 #define current_pid()          (current->pid)
 #define current_fsuid(cred)    (current->fsuid)
 #define current_fsgid(cred)    (current->fsgid)
-#define current_set_flags(f)   (current->flags |= (f))
 #define current_test_flags(f)  (current->flags & (f))
-#define current_clear_flags(f) (current->flags & ~(f))
 #define current_set_flags_nested(sp, f)                \
                (*(sp) = current->flags, current->flags |= (f))
 #define current_clear_flags_nested(sp, f)      \
index 35c6a01963a77c9c52af0ba70453926aab316f04..c42b3221b20cb95a0a1303b2d6c51a4aff071148 100644 (file)
@@ -93,7 +93,7 @@ typedef enum {
  */
 static inline struct bhv_vnode *vn_from_inode(struct inode *inode)
 {
-       return (bhv_vnode_t *)list_entry(inode, bhv_vnode_t, v_inode);
+       return container_of(inode, bhv_vnode_t, v_inode);
 }
 static inline struct inode *vn_to_inode(struct bhv_vnode *vnode)
 {
index 1d8ff103201c3bf78646ed2e9baeddac3c1b3019..6e6e56fb352d2fc56585f923f693c9231795c912 100644 (file)
  *
  */
 
-struct bhv_head_lock;
-
 /*
  * Behavior head.  Head of the chain of behaviors.
  * Contained within each virtualized object data structure.
  */
 typedef struct bhv_head {
        struct bhv_desc *bh_first;      /* first behavior in chain */
-       struct bhv_head_lock *bh_lockp; /* pointer to lock info struct */
 } bhv_head_t;
 
 /*
index 5fa0adb7e1737ad0ca4451409f412d73e1b5ce2f..86c1bf0bba9ea19bc0f38cdb98adfd76769ef053 100644 (file)
@@ -1961,9 +1961,9 @@ xfs_iunlink_remove(
        xfs_agino_t     agino;
        xfs_agino_t     next_agino;
        xfs_buf_t       *last_ibp;
-       xfs_dinode_t    *last_dip;
+       xfs_dinode_t    *last_dip = NULL;
        short           bucket_index;
-       int             offset, last_offset;
+       int             offset, last_offset = 0;
        int             error;
        int             agi_ok;
 
index d8f5d4cbe8b7b7819bb403e225389c54c22fd8b5..e730328636c31283c46cd2ce1fac1ccd18c4bf72 100644 (file)
@@ -1740,10 +1740,10 @@ xlog_write(xfs_mount_t *        mp,
           xlog_in_core_t       **commit_iclog,
           uint                 flags)
 {
-    xlog_t          *log    = mp->m_log;
+    xlog_t          *log = mp->m_log;
     xlog_ticket_t    *ticket = (xlog_ticket_t *)tic;
+    xlog_in_core_t   *iclog = NULL;  /* ptr to current in-core log */
     xlog_op_header_t *logop_head;    /* ptr to log operation header */
-    xlog_in_core_t   *iclog;        /* ptr to current in-core log */
     __psint_t       ptr;            /* copy address into data region */
     int                     len;            /* # xlog_write() bytes 2 still copy */
     int                     index;          /* region index currently copying */
index 55b4237c2153975e00ded0b662dcf36edd861ca2..3cb678e3a132997804998f7dbfea787b4a75a15a 100644 (file)
@@ -990,6 +990,8 @@ xlog_find_zeroed(
        xfs_daddr_t     num_scan_bblks;
        int             error, log_bbnum = log->l_logBBsize;
 
+       *blk_no = 0;
+
        /* check totally zeroed log */
        bp = xlog_get_bp(log, 1);
        if (!bp)
index 10dbf203c62f6f929ee709d6624121f744de231a..4be5c0b2d296b20a1feda5c4f1b47c38685f757b 100644 (file)
@@ -1721,15 +1721,14 @@ xfs_mount_log_sbunit(
  * is present to prevent thrashing).
  */
 
+#ifdef CONFIG_HOTPLUG_CPU
 /*
  * hot-plug CPU notifier support.
  *
- * We cannot use the hotcpu_register() function because it does
- * not allow notifier instances. We need a notifier per filesystem
- * as we need to be able to identify the filesystem to balance
- * the counters out. This is achieved by having a notifier block
- * embedded in the xfs_mount_t and doing pointer magic to get the
- * mount pointer from the notifier block address.
+ * We need a notifier per filesystem as we need to be able to identify
+ * the filesystem to balance the counters out. This is achieved by
+ * having a notifier block embedded in the xfs_mount_t and doing pointer
+ * magic to get the mount pointer from the notifier block address.
  */
 STATIC int
 xfs_icsb_cpu_notify(
@@ -1779,6 +1778,7 @@ xfs_icsb_cpu_notify(
 
        return NOTIFY_OK;
 }
+#endif /* CONFIG_HOTPLUG_CPU */
 
 int
 xfs_icsb_init_counters(
@@ -1791,9 +1791,11 @@ xfs_icsb_init_counters(
        if (mp->m_sb_cnts == NULL)
                return -ENOMEM;
 
+#ifdef CONFIG_HOTPLUG_CPU
        mp->m_icsb_notifier.notifier_call = xfs_icsb_cpu_notify;
        mp->m_icsb_notifier.priority = 0;
-       register_cpu_notifier(&mp->m_icsb_notifier);
+       register_hotcpu_notifier(&mp->m_icsb_notifier);
+#endif /* CONFIG_HOTPLUG_CPU */
 
        for_each_online_cpu(i) {
                cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
@@ -1812,7 +1814,7 @@ xfs_icsb_destroy_counters(
        xfs_mount_t     *mp)
 {
        if (mp->m_sb_cnts) {
-               unregister_cpu_notifier(&mp->m_icsb_notifier);
+               unregister_hotcpu_notifier(&mp->m_icsb_notifier);
                free_percpu(mp->m_sb_cnts);
        }
 }
@@ -2026,7 +2028,7 @@ xfs_icsb_balance_counter(
        xfs_sb_field_t  field,
        int             flags)
 {
-       uint64_t        count, resid = 0;
+       uint64_t        count, resid;
        int             weight = num_online_cpus();
        int             s;
 
@@ -2058,6 +2060,7 @@ xfs_icsb_balance_counter(
                break;
        default:
                BUG();
+               count = resid = 0;      /* quiet, gcc */
                break;
        }
 
index 0c1e42b037efe63058819f275e20b0fd7cf9186b..5a0b678956e0e3ca616efb76ffb9d827f6d159fa 100644 (file)
@@ -1929,7 +1929,7 @@ xfs_growfs_rt(
        /*
         * Initial error checking.
         */
-       if (mp->m_rtdev_targp || mp->m_rbmip == NULL ||
+       if (mp->m_rtdev_targp == NULL || mp->m_rbmip == NULL ||
            (nrblocks = in->newblocks) <= sbp->sb_rblocks ||
            (sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))
                return XFS_ERROR(EINVAL);
index cb65c3a603f56a776cfef5a7a0def8c6f2d77108..9dc88b380608e6f29a6bef4c7ee5c21945367f0f 100644 (file)
@@ -338,8 +338,6 @@ typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *);
 typedef struct xfs_trans {
        unsigned int            t_magic;        /* magic number */
        xfs_log_callback_t      t_logcb;        /* log callback struct */
-       struct xfs_trans        *t_forw;        /* async list pointers */
-       struct xfs_trans        *t_back;        /* async list pointers */
        unsigned int            t_type;         /* transaction type */
        unsigned int            t_log_res;      /* amt of log space resvd */
        unsigned int            t_log_count;    /* count for perm log res */
@@ -364,9 +362,11 @@ typedef struct xfs_trans {
        long                    t_res_fdblocks_delta; /* on-disk only chg */
        long                    t_frextents_delta;/* superblock freextents chg*/
        long                    t_res_frextents_delta; /* on-disk only chg */
+#ifdef DEBUG
        long                    t_ag_freeblks_delta; /* debugging counter */
        long                    t_ag_flist_delta; /* debugging counter */
        long                    t_ag_btree_delta; /* debugging counter */
+#endif
        long                    t_dblocks_delta;/* superblock dblocks change */
        long                    t_agcount_delta;/* superblock agcount change */
        long                    t_imaxpct_delta;/* superblock imaxpct change */
index 00a6b7dc24a0a6ed047999b85f4eeca4f1494d1f..23cfa58377283b073f09503734581ea4df80edf0 100644 (file)
@@ -2603,8 +2603,7 @@ xfs_link(
        vn_trace_entry(src_vp, __FUNCTION__, (inst_t *)__return_address);
 
        target_namelen = VNAMELEN(dentry);
-       if (VN_ISDIR(src_vp))
-               return XFS_ERROR(EPERM);
+       ASSERT(!VN_ISDIR(src_vp));
 
        sip = xfs_vtoi(src_vp);
        tdp = XFS_BHVTOI(target_dir_bdp);
@@ -2699,9 +2698,8 @@ xfs_link(
        xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
 
        error = xfs_bumplink(tp, sip);
-       if (error) {
+       if (error)
                goto abort_return;
-       }
 
        /*
         * If this is a synchronous mount, make sure that the
@@ -2719,9 +2717,8 @@ xfs_link(
        }
 
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
-       if (error) {
+       if (error)
                goto std_return;
-       }
 
        /* Fall through to std_return with error = 0. */
 std_return:
@@ -2742,6 +2739,8 @@ std_return:
        xfs_trans_cancel(tp, cancel_flags);
        goto std_return;
 }
+
+
 /*
  * xfs_mkdir
  *
index dba70c62a16c0d3a56df6ffebd917983d0367f3b..457c34b6eb09337bc87421aeb0edfe0b35edd2e7 100644 (file)
@@ -435,7 +435,7 @@ static inline void t2_outl(u32 b, unsigned long addr)
        set_hae(msb); \
 }
 
-static spinlock_t t2_hae_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(t2_hae_lock);
 
 __EXTERN_INLINE u8 t2_readb(const volatile void __iomem *xaddr)
 {
index ca9d43b6350276b1bf07e675907033b52690a9e8..a37db0f95092f495a02819a7382631c34b686c37 100644 (file)
@@ -2,8 +2,6 @@
 #define _ALPHA_HW_IRQ_H
 
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
-
 extern volatile unsigned long irq_err_count;
 
 #ifdef CONFIG_ALPHA_GENERIC
index 3c327c4043734078a6f726c71fab015a82787a2a..f985069e6d011dd41784e83e65f6e6729fe49fff 100644 (file)
@@ -33,9 +33,7 @@
  * bus_to_virt: Used to convert an address for DMA operations
  *              to an address that the kernel can use.
  */
-#define __virt_to_bus__is_a_macro
 #define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x) __phys_to_virt(x)
 
 #endif
index 4a1bfd78a0fe11cbcb56d5c65e261bab7c265b13..53e923dba76e658b4d4613e8099ae424c2ce2854 100644 (file)
@@ -23,9 +23,7 @@
  * There is something to do here later !, Mar 2000, Jungjun Kim
  */
 
-#define __virt_to_bus__is_a_macro
 #define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x)       __phys_to_virt(x)
 
 #endif
index d09ae32cd2f4c011e03e34761294f45c9b888040..5ad90127915f63cfc69f2629ebb0772ff4280f55 100644 (file)
@@ -30,9 +30,7 @@
  * bus_to_virt: Used to convert an address for DMA operations
  *              to an address that the kernel can use.
  */
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)       (x - PAGE_OFFSET +  PHYS_OFFSET)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)       (x -  PHYS_OFFSET + PAGE_OFFSET)
+#define __virt_to_bus(x)       (x - PAGE_OFFSET + PHYS_OFFSET)
+#define __bus_to_virt(x)       (x - PHYS_OFFSET + PAGE_OFFSET)
 
 #endif
index d0a72201ee96a344163a849a9998f41f8274c9e9..3927b1d61b17dd593ebfd45a6814469c2e820377 100644 (file)
 #define IXP23XX_PCI_CPP_ADDR_BITS      IXP23XX_PCI_CSR(0x0160)
 
 
-#ifndef __ASSEMBLY__
-/*
- * Is system memory on the XSI or CPP bus?
- */
-static inline unsigned ixp23xx_cpp_boot(void)
-{
-       return (*IXP23XX_EXP_CFG0 & IXP23XX_EXP_CFG0_XSI_NOT_PRES);
-}
-#endif
-
-
 #endif
index 19a73b39c8640491dc034bdbf5629edad8cd69c1..56e16d66645a090fe1913ffeaafeb8e2a7d8dfa2 100644 (file)
@@ -43,5 +43,15 @@ extern struct sys_timer ixp23xx_timer;
 
 #define IXP23XX_UART_XTAL              14745600
 
+#ifndef __ASSEMBLY__
+/*
+ * Is system memory on the XSI or CPP bus?
+ */
+static inline unsigned ixp23xx_cpp_boot(void)
+{
+       return (*IXP23XX_EXP_CFG0 & IXP23XX_EXP_CFG0_XSI_NOT_PRES);
+}
+#endif
+
 
 #endif
index 013575e6a9a1bd5b3d262cc81fc825c173aa3a60..16c1110f2304c1a08d72adcca3cedc90e054f1c5 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H
 
-#include <asm/hardware.h>
+#include <asm/arch/ixp23xx.h>
 #include <linux/serial_reg.h>
 
 #define UART_BASE      ((volatile u32 *)IXP23XX_UART1_PHYS)
index 84aca61cbaa3d70c2edc629dc257be5593c753b9..a0a1248751646053c9f969cf1f0d181b1911de68 100644 (file)
@@ -7,25 +7,23 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * S3C2440 Signal Drive Strength Control
- *
- *  Changelog:
- *    11-Aug-2004     BJD     Created file
- *    25-Aug-2004     BJD     Added the _SELECT_* defs for using with functions
+ * S3C2440/S3C2412 Signal Drive Strength Control
 */
 
 
 #ifndef __ASM_ARCH_REGS_DSC_H
 #define __ASM_ARCH_REGS_DSC_H "2440-dsc"
 
-#ifdef CONFIG_CPU_S3C2440
+#if defined(CONFIG_CPU_S3C2412)
+#define S3C2412_DSC0      S3C2410_GPIOREG(0xdc)
+#define S3C2412_DSC1      S3C2410_GPIOREG(0xe0)
+#endif
+
+#if defined(CONFIG_CPU_S3C2440)
 
 #define S3C2440_DSC0      S3C2410_GPIOREG(0xc4)
 #define S3C2440_DSC1      S3C2410_GPIOREG(0xc8)
 
-#define S3C2412_DSC0      S3C2410_GPIOREG(0xdc)
-#define S3C2412_DSC1      S3C2410_GPIOREG(0xe0)
-
 #define S3C2440_SELECT_DSC0 (0)
 #define S3C2440_SELECT_DSC1 (1<<31)
 
index 7cff235e667aeea2ef79c9d002bebc85b2d95abb..c1470c695c33556ea6a85f9d4efc4287fc08dea8 100644 (file)
 #define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
 #define S3C2440_NFMECC0  S3C2410_NFREG(0x2C)
 #define S3C2440_NFMECC1  S3C2410_NFREG(0x30)
-#define S3C2440_NFSECC   S3C2410_NFREG(0x34)
+#define S3C2440_NFSECC   S3C24E10_NFREG(0x34)
 #define S3C2440_NFSBLK   S3C2410_NFREG(0x38)
 #define S3C2440_NFEBLK   S3C2410_NFREG(0x3C)
 
+#define S3C2412_NFSBLK         S3C2410_NFREG(0x20)
+#define S3C2412_NFEBLK         S3C2410_NFREG(0x24)
+#define S3C2412_NFSTAT         S3C2410_NFREG(0x28)
+#define S3C2412_NFMECC_ERR0    S3C2410_NFREG(0x2C)
+#define S3C2412_NFMECC_ERR1    S3C2410_NFREG(0x30)
+#define S3C2412_NFMECC0                S3C2410_NFREG(0x34)
+#define S3C2412_NFMECC1                S3C2410_NFREG(0x38)
+#define S3C2412_NFSECC         S3C2410_NFREG(0x3C)
+
 #define S3C2410_NFCONF_EN          (1<<15)
 #define S3C2410_NFCONF_512BYTE     (1<<14)
 #define S3C2410_NFCONF_4STEP       (1<<13)
 #define S3C2440_NFSTAT_RnB_CHANGE      (1<<2)
 #define S3C2440_NFSTAT_ILLEGAL_ACCESS  (1<<3)
 
+#define S3C2412_NFCONF_NANDBOOT                (1<<31)
+#define S3C2412_NFCONF_ECCCLKCON       (1<<30)
+#define S3C2412_NFCONF_ECC_MLC         (1<<24)
+#define S3C2412_NFCONF_TACLS_MASK      (7<<12) /* 1 extra bit of Tacls */
+
+#define S3C2412_NFCONT_ECC4_DIRWR      (1<<18)
+#define S3C2412_NFCONT_LOCKTIGHT       (1<<17)
+#define S3C2412_NFCONT_SOFTLOCK                (1<<16)
+#define S3C2412_NFCONT_ECC4_ENCINT     (1<<13)
+#define S3C2412_NFCONT_ECC4_DECINT     (1<<12)
+#define S3C2412_NFCONT_MAIN_ECC_LOCK   (1<<7)
+#define S3C2412_NFCONT_INIT_MAIN_ECC   (1<<5)
+#define S3C2412_NFCONT_nFCE1           (1<<2)
+#define S3C2412_NFCONT_nFCE0           (1<<1)
+
+#define S3C2412_NFSTAT_ECC_ENCDONE     (1<<7)
+#define S3C2412_NFSTAT_ECC_DECDONE     (1<<6)
+#define S3C2412_NFSTAT_ILLEGAL_ACCESS  (1<<5)
+#define S3C2412_NFSTAT_RnB_CHANGE      (1<<4)
+#define S3C2412_NFSTAT_nFCE1           (1<<3)
+#define S3C2412_NFSTAT_nFCE0           (1<<2)
+#define S3C2412_NFSTAT_Res1            (1<<1)
+#define S3C2412_NFSTAT_READY           (1<<0)
+
+#define S3C2412_NFECCERR_SERRDATA(x)   (((x) >> 21) & 0xf)
+#define S3C2412_NFECCERR_SERRBIT(x)    (((x) >> 18) & 0x7)
+#define S3C2412_NFECCERR_MERRDATA(x)   (((x) >> 7) & 0x3ff)
+#define S3C2412_NFECCERR_MERRBIT(x)    (((x) >> 4) & 0x7)
+#define S3C2412_NFECCERR_SPARE_ERR(x)  (((x) >> 2) & 0x3)
+#define S3C2412_NFECCERR_MAIN_ERR(x)   (((x) >> 2) & 0x3)
+#define S3C2412_NFECCERR_NONE          (0)
+#define S3C2412_NFECCERR_1BIT          (1)
+#define S3C2412_NFECCERR_MULTIBIT      (2)
+#define S3C2412_NFECCERR_ECCAREA       (3)
+
+
+
 #endif /* __ASM_ARM_REGS_NAND */
 
index 4c80ec519d45d8760fc18f73ece1e439adf012de..ca54eb0f12d75cc15ea35281d5cb72f3050171cb 100644 (file)
 #ifndef __ASM_BUGS_H
 #define __ASM_BUGS_H
 
+#ifdef CONFIG_MMU
 extern void check_writebuffer_bugs(void);
 
 #define check_bugs() check_writebuffer_bugs()
+#else
+#define check_bugs() do { } while (0)
+#endif
 
 #endif
index f8ea2de4848ea7ae075836718342952a86cda1d0..4c2885abbe6c950f04d06c6345bb6358f591421b 100644 (file)
@@ -50,6 +50,8 @@
 #define domain_val(dom,type)   ((type) << (2*(dom)))
 
 #ifndef __ASSEMBLY__
+
+#ifdef CONFIG_MMU
 #define set_domain(x)                                  \
        do {                                            \
        __asm__ __volatile__(                           \
        set_domain(thread->cpu_domain);                         \
        } while (0)
 
+#else
+#define set_domain(x)          do { } while (0)
+#define modify_domain(dom,type)        do { } while (0)
+#endif
+
 #endif
 #endif /* !__ASSEMBLY__ */
index 132c3c5628b2a4b4d5be60bee7f1a41f04e627d0..6af4e6bd1290c261dcba28096949fe6262145c8a 100644 (file)
@@ -72,6 +72,14 @@ union fp_state {
 
 #define FP_SIZE (sizeof(union fp_state) / sizeof(int))
 
+struct crunch_state {
+       unsigned int    mvdx[16][2];
+       unsigned int    mvax[4][3];
+       unsigned int    dspsc[2];
+};
+
+#define CRUNCH_SIZE    sizeof(struct crunch_state)
+
 #endif
 
 #endif
index e8ea67c97c73d3526b3c7025dbc9a468e1ef6331..cef5364ed5feb0531cc39b3bee6ccdf01426562d 100644 (file)
@@ -16,8 +16,6 @@ struct map_desc {
        unsigned int type;
 };
 
-struct meminfo;
-
 #define MT_DEVICE              0
 #define MT_CACHECLEAN          1
 #define MT_MINICLEAN           2
@@ -28,7 +26,8 @@ struct meminfo;
 #define MT_IXP2000_DEVICE      7
 #define MT_NONSHARED_DEVICE    8
 
-extern void create_memmap_holes(struct meminfo *);
-extern void memtable_init(struct meminfo *);
+#ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
-extern void setup_io_desc(void);
+#else
+#define iotable_init(map,num)  do { } while (0)
+#endif
index 25d540ed0079bf2063921dddbe83b9fdadf67949..923e0ca66200c1f0a592ff470528d4c524a15583 100644 (file)
@@ -28,7 +28,7 @@ struct hw_pci {
 struct pci_sys_data {
        struct list_head node;
        int             busnr;          /* primary bus number                   */
-       unsigned long   mem_offset;     /* bus->cpu memory mapping offset       */
+       u64             mem_offset;     /* bus->cpu memory mapping offset       */
        unsigned long   io_offset;      /* bus->cpu IO mapping offset           */
        struct pci_bus  *bus;           /* PCI bus                              */
        struct resource *resource[3];   /* Primary PCI bus resources            */
index 731e321a57d1722779b93babdfae17742aca8440..94f973b704f1578f1f88e42dec61a8ac2670007d 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/include/asm-arm/memory.h
  *
  *  Copyright (C) 2000-2002 Russell King
+ *  modification for nommu, Hyok S. Choi, 2004
  *
  * 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
@@ -26,6 +27,8 @@
 #include <asm/arch/memory.h>
 #include <asm/sizes.h>
 
+#ifdef CONFIG_MMU
+
 #ifndef TASK_SIZE
 /*
  * TASK_SIZE - the maximum size of a user space task.
 #define PAGE_OFFSET            UL(0xc0000000)
 #endif
 
+/*
+ * The module space lives between the addresses given by TASK_SIZE
+ * and PAGE_OFFSET - it must be within 32MB of the kernel text.
+ */
+#define MODULE_END             (PAGE_OFFSET)
+#define MODULE_START           (MODULE_END - 16*1048576)
+
+#if TASK_SIZE > MODULE_START
+#error Top of user space clashes with start of module space
+#endif
+
+/*
+ * The XIP kernel gets mapped at the bottom of the module vm area.
+ * Since we use sections to map it, this macro replaces the physical address
+ * with its virtual address while keeping offset from the base section.
+ */
+#define XIP_VIRT_ADDR(physaddr)  (MODULE_START + ((physaddr) & 0x000fffff))
+
+#else /* CONFIG_MMU */
+
+/*
+ * The limitation of user task size can grow up to the end of free ram region.
+ * It is difficult to define and perhaps will never meet the original meaning
+ * of this define that was meant to.
+ * Fortunately, there is no reference for this in noMMU mode, for now.
+ */
+#ifndef TASK_SIZE
+#define TASK_SIZE              (CONFIG_DRAM_SIZE)
+#endif
+
+#ifndef TASK_UNMAPPED_BASE
+#define TASK_UNMAPPED_BASE     UL(0x00000000)
+#endif
+
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET            (CONFIG_DRAM_BASE)
+#endif
+
+#ifndef END_MEM
+#define END_MEM                (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE)
+#endif
+
+#ifndef PAGE_OFFSET
+#define PAGE_OFFSET            (PHYS_OFFSET)
+#endif
+
+/*
+ * The module can be at any place in ram in nommu mode.
+ */
+#define MODULE_END             (END_MEM)
+#define MODULE_START           (PHYS_OFFSET)
+
+#endif /* !CONFIG_MMU */
+
 /*
  * Size of DMA-consistent memory region.  Must be multiple of 2M,
  * between 2MB and 14MB inclusive.
 #define        __phys_to_pfn(paddr)    ((paddr) >> PAGE_SHIFT)
 #define        __pfn_to_phys(pfn)      ((pfn) << PAGE_SHIFT)
 
-/*
- * The module space lives between the addresses given by TASK_SIZE
- * and PAGE_OFFSET - it must be within 32MB of the kernel text.
- */
-#define MODULE_END     (PAGE_OFFSET)
-#define MODULE_START   (MODULE_END - 16*1048576)
-
-#if TASK_SIZE > MODULE_START
-#error Top of user space clashes with start of module space
-#endif
-
-/*
- * The XIP kernel gets mapped at the bottom of the module vm area.
- * Since we use sections to map it, this macro replaces the physical address
- * with its virtual address while keeping offset from the base section.
- */
-#define XIP_VIRT_ADDR(physaddr)  (MODULE_START + ((physaddr) & 0x000fffff))
-
 #ifndef __ASSEMBLY__
 
 /*
index a457cb71984f58cdd8ba6de24a8f33a93b9bdd95..23dde52e0945f31c24ddd9fc4ddc1b8e66a74163 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ARM_MMU_H
 #define __ARM_MMU_H
 
+#ifdef CONFIG_MMU
+
 typedef struct {
 #if __LINUX_ARM_ARCH__ >= 6
        unsigned int id;
@@ -13,4 +15,18 @@ typedef struct {
 #define ASID(mm)       (0)
 #endif
 
+#else
+
+/*
+ * From nommu.h:
+ *  Copyright (C) 2002, David McCullough <davidm@snapgear.com>
+ *  modified for 2.6 by Hyok S. Choi <hyok.choi@samsung.com>
+ */
+typedef struct {
+       struct vm_list_struct   *vmlist;
+       unsigned long           end_brk;
+} mm_context_t;
+
+#endif
+
 #endif
index 81c59facea3bead1184df5cf0359058eb9a2d366..9fadb01e030d15a4fd67dda4ac143ff52406be46 100644 (file)
@@ -82,6 +82,7 @@ static inline void
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
          struct task_struct *tsk)
 {
+#ifdef CONFIG_MMU
        unsigned int cpu = smp_processor_id();
 
        if (prev != next) {
@@ -91,6 +92,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
                if (cache_is_vivt())
                        cpu_clear(cpu, prev->cpu_vm_mask);
        }
+#endif
 }
 
 #define deactivate_mm(tsk,mm)  do { } while (0)
diff --git a/include/asm-arm/page-nommu.h b/include/asm-arm/page-nommu.h
new file mode 100644 (file)
index 0000000..a1bcad0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  linux/include/asm-arm/page-nommu.h
+ *
+ *  Copyright (C) 2004 Hyok S. Choi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASMARM_PAGE_NOMMU_H
+#define _ASMARM_PAGE_NOMMU_H
+
+#if !defined(CONFIG_SMALL_TASKS) && PAGE_SHIFT < 13
+#define KTHREAD_SIZE (8192)
+#else
+#define KTHREAD_SIZE PAGE_SIZE
+#endif
+#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
+#define free_user_page(page, addr)     free_page(addr)
+
+#define clear_page(page)       memset((page), 0, PAGE_SIZE)
+#define copy_page(to,from)     memcpy((to), (from), PAGE_SIZE)
+
+#define clear_user_page(page, vaddr, pg)       clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef unsigned long pte_t;
+typedef unsigned long pmd_t;
+typedef unsigned long pgd_t[2];
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)      (x)
+#define pmd_val(x)      (x)
+#define pgd_val(x)     ((x)[0])
+#define pgprot_val(x)   (x)
+
+#define __pte(x)        (x)
+#define __pmd(x)        (x)
+#define __pgprot(x)     (x)
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
+#endif
index 66cfeb5290ea5c0e077f67db6bd154c5768ab9b1..63d12f0244c50d09ab60c89d56159196440fb024 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#ifndef CONFIG_MMU
+
+#include "page-nommu.h"
+
+#else
+
 #include <asm/glue.h>
 
 /*
@@ -171,6 +177,8 @@ typedef unsigned long pgprot_t;
 /* the upper-most page table pointer */
 extern pmd_t *top_pmd;
 
+#endif /* CONFIG_MMU */
+
 #include <asm/memory.h>
 
 #endif /* !__ASSEMBLY__ */
index c4ac2e67768dcdbf6077e3fc385e2a192ab569d1..4d43945529118a8ea7e92241771a6f3253a1e93a 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
+#define check_pgt_cache()              do { } while (0)
+
+#ifdef CONFIG_MMU
+
 #define _PAGE_USER_TABLE       (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
 #define _PAGE_KERNEL_TABLE     (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
 
@@ -32,8 +36,6 @@ extern void free_pgd_slow(pgd_t *pgd);
 #define pgd_alloc(mm)                  get_pgd_slow(mm)
 #define pgd_free(pgd)                  free_pgd_slow(pgd)
 
-#define check_pgt_cache()              do { } while (0)
-
 /*
  * Allocate one PTE table.
  *
@@ -126,4 +128,6 @@ pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep)
        __pmd_populate(pmdp, page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE);
 }
 
+#endif /* CONFIG_MMU */
+
 #endif
diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
new file mode 100644 (file)
index 0000000..b13322d
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  linux/include/asm-arm/pgtable-nommu.h
+ *
+ *  Copyright (C) 1995-2002 Russell King
+ *  Copyright (C) 2004  Hyok S. Choi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASMARM_PGTABLE_NOMMU_H
+#define _ASMARM_PGTABLE_NOMMU_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+/*
+ * Trivial page table functions.
+ */
+#define pgd_present(pgd)       (1)
+#define pgd_none(pgd)          (0)
+#define pgd_bad(pgd)           (0)
+#define pgd_clear(pgdp)
+#define kern_addr_valid(addr)  (1)
+#define        pmd_offset(a, b)        ((void *)0)
+/* FIXME */
+/*
+ * PMD_SHIFT determines the size of the area a second-level page table can map
+ * PGDIR_SHIFT determines what a third-level page table entry can map
+ */
+#define PGDIR_SHIFT            21
+
+#define PGDIR_SIZE             (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK             (~(PGDIR_SIZE-1))
+/* FIXME */
+
+#define PAGE_NONE      __pgprot(0)
+#define PAGE_SHARED    __pgprot(0)
+#define PAGE_COPY      __pgprot(0)
+#define PAGE_READONLY  __pgprot(0)
+#define PAGE_KERNEL    __pgprot(0)
+
+//extern void paging_init(struct meminfo *, struct machine_desc *);
+#define swapper_pg_dir ((pgd_t *) 0)
+
+#define __swp_type(x)          (0)
+#define __swp_offset(x)                (0)
+#define __swp_entry(typ,off)   ((swp_entry_t) { ((typ) | ((off) << 7)) })
+#define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
+
+
+typedef pte_t *pte_addr_t;
+
+static inline int pte_file(pte_t pte) { return 0; }
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+#define ZERO_PAGE(vaddr)       (virt_to_page(0))
+
+/*
+ * Mark the prot value as uncacheable and unbufferable.
+ */
+#define pgprot_noncached(prot) __pgprot(0)
+#define pgprot_writecombine(prot) __pgprot(0)
+
+
+/*
+ * These would be in other places but having them here reduces the diffs.
+ */
+extern unsigned int kobjsize(const void *objp);
+extern int is_in_rom(unsigned long);
+
+/*
+ * No page table caches to initialise.
+ */
+#define pgtable_cache_init()   do { } while (0)
+#define io_remap_page_range    remap_page_range
+#define io_remap_pfn_range     remap_pfn_range
+
+#define MK_IOSPACE_PFN(space, pfn)     (pfn)
+#define GET_IOSPACE(pfn)               0
+#define GET_PFN(pfn)                   (pfn)
+
+
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define        VMALLOC_START   0
+#define        VMALLOC_END     0xffffffff
+
+#define FIRST_USER_ADDRESS      (0)
+
+#else 
+
+/*
+ * dummy tlb and user structures.
+ */
+#define v3_tlb_fns     (0)
+#define v4_tlb_fns     (0)
+#define v4wb_tlb_fns   (0)
+#define v4wbi_tlb_fns  (0)
+#define v6_tlb_fns     (0)
+
+#define v3_user_fns    (0)
+#define v4_user_fns    (0)
+#define v4_mc_user_fns (0)
+#define v4wb_user_fns  (0)
+#define v4wt_user_fns  (0)
+#define v6_user_fns    (0)
+#define xscale_mc_user_fns (0)
+
+#endif /*__ASSEMBLY__*/
+
+#endif /* _ASMARM_PGTABLE_H */
index e85c08d78ddadf5e85f14818fc858c94692e40d2..8d3919c6458c6c9326ef35a35ee7c848d34ac467 100644 (file)
 #define _ASMARM_PGTABLE_H
 
 #include <asm-generic/4level-fixup.h>
+#include <asm/proc-fns.h>
+
+#ifndef CONFIG_MMU
+
+#include "pgtable-nommu.h"
+
+#else
 
 #include <asm/memory.h>
-#include <asm/proc-fns.h>
 #include <asm/arch/vmalloc.h>
 
 /*
@@ -378,4 +384,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 #endif /* !__ASSEMBLY__ */
 
+#endif /* CONFIG_MMU */
+
 #endif /* _ASMARM_PGTABLE_H */
index e9310895e79dae741c6104ba85f63a5afc660cb2..1bde92cdaebd01739c3db199a438f47a7ffd0493 100644 (file)
 
 #include <asm/memory.h>
 
+#ifdef CONFIG_MMU
+
 #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
 
 #define cpu_get_pgd()  \
                (pgd_t *)phys_to_virt(pg);              \
        })
 
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* __ASM_PROCFNS_H */
index 2bebe3dc0a30c5a8be30081d11f2e14fa798f4da..5a8ef787dbf81c0c3ec5caf79471fe69a3033f07 100644 (file)
 
 #define PTRACE_SET_SYSCALL     23
 
+/* PTRACE_SYSCALL is 24 */
+
+#define PTRACE_GETCRUNCHREGS   25
+#define PTRACE_SETCRUNCHREGS   26
+
 /*
  * PSR bits
  */
index cfbccb63c67b4df54523fa3942b2ba6b096bd09b..c46b5c84275f3f2f5b2ac91d8a60002963fdc9f5 100644 (file)
@@ -59,6 +59,7 @@ struct thread_info {
        struct cpu_context_save cpu_context;    /* cpu context */
        __u8                    used_cp[16];    /* thread used copro */
        unsigned long           tp_value;
+       struct crunch_state     crunchstate;
        union fp_state          fpstate __attribute__((aligned(8)));
        union vfp_state         vfpstate;
        struct restart_block    restart_block;
@@ -101,6 +102,11 @@ extern void free_thread_info(struct thread_info *);
 #define thread_saved_fp(tsk)   \
        ((unsigned long)(task_thread_info(tsk)->cpu_context.fp))
 
+extern void crunch_task_disable(struct thread_info *);
+extern void crunch_task_copy(struct thread_info *, void *);
+extern void crunch_task_restore(struct thread_info *, void *);
+extern void crunch_task_release(struct thread_info *);
+
 extern void iwmmxt_task_disable(struct thread_info *);
 extern void iwmmxt_task_copy(struct thread_info *, void *);
 extern void iwmmxt_task_restore(struct thread_info *, void *);
index 064f0f5e8e2b9e3361082dbc420b2e6248263c40..87aba57a66c40d5b0f10fe199c3159fa5710a9e3 100644 (file)
@@ -40,16 +40,25 @@ struct exception_table_entry
 
 extern int fixup_exception(struct pt_regs *regs);
 
+/*
+ * These two are intentionally not defined anywhere - if the kernel
+ * code generates any references to them, that's a bug.
+ */
+extern int __get_user_bad(void);
+extern int __put_user_bad(void);
+
 /*
  * Note that this is actually 0x1,0000,0000
  */
 #define KERNEL_DS      0x00000000
-#define USER_DS                TASK_SIZE
-
 #define get_ds()       (KERNEL_DS)
+
+#ifdef CONFIG_MMU
+
+#define USER_DS                TASK_SIZE
 #define get_fs()       (current_thread_info()->addr_limit)
 
-static inline void set_fs (mm_segment_t fs)
+static inline void set_fs(mm_segment_t fs)
 {
        current_thread_info()->addr_limit = fs;
        modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
@@ -75,8 +84,6 @@ static inline void set_fs (mm_segment_t fs)
                : "cc"); \
        flag; })
 
-#define access_ok(type,addr,size)      (__range_ok(addr,size) == 0)
-
 /*
  * Single-value transfer routines.  They automatically use the right
  * size if we just have the right pointer type.  Note that the functions
@@ -87,20 +94,10 @@ static inline void set_fs (mm_segment_t fs)
  * fixup code, but there are a few places where it intrudes on the
  * main code path.  When we only write to user space, there is no
  * problem.
- *
- * The "__xxx" versions of the user access functions do not verify the
- * address space - it must have been done previously with a separate
- * "access_ok()" call.
- *
- * The "xxx_error" versions set the third argument to EFAULT if an
- * error occurs, and leave it unchanged on success.  Note that these
- * versions are void (ie, don't return a value as such).
  */
-
 extern int __get_user_1(void *);
 extern int __get_user_2(void *);
 extern int __get_user_4(void *);
-extern int __get_user_bad(void);
 
 #define __get_user_x(__r2,__p,__e,__s,__i...)                          \
           __asm__ __volatile__ (                                       \
@@ -131,6 +128,74 @@ extern int __get_user_bad(void);
                __e;                                                    \
        })
 
+extern int __put_user_1(void *, unsigned int);
+extern int __put_user_2(void *, unsigned int);
+extern int __put_user_4(void *, unsigned int);
+extern int __put_user_8(void *, unsigned long long);
+
+#define __put_user_x(__r2,__p,__e,__s)                                 \
+          __asm__ __volatile__ (                                       \
+               __asmeq("%0", "r0") __asmeq("%2", "r2")                 \
+               "bl     __put_user_" #__s                               \
+               : "=&r" (__e)                                           \
+               : "0" (__p), "r" (__r2)                                 \
+               : "ip", "lr", "cc")
+
+#define put_user(x,p)                                                  \
+       ({                                                              \
+               const register typeof(*(p)) __r2 asm("r2") = (x);       \
+               const register typeof(*(p)) __user *__p asm("r0") = (p);\
+               register int __e asm("r0");                             \
+               switch (sizeof(*(__p))) {                               \
+               case 1:                                                 \
+                       __put_user_x(__r2, __p, __e, 1);                \
+                       break;                                          \
+               case 2:                                                 \
+                       __put_user_x(__r2, __p, __e, 2);                \
+                       break;                                          \
+               case 4:                                                 \
+                       __put_user_x(__r2, __p, __e, 4);                \
+                       break;                                          \
+               case 8:                                                 \
+                       __put_user_x(__r2, __p, __e, 8);                \
+                       break;                                          \
+               default: __e = __put_user_bad(); break;                 \
+               }                                                       \
+               __e;                                                    \
+       })
+
+#else /* CONFIG_MMU */
+
+/*
+ * uClinux has only one addr space, so has simplified address limits.
+ */
+#define USER_DS                        KERNEL_DS
+
+#define segment_eq(a,b)                (1)
+#define __addr_ok(addr)                (1)
+#define __range_ok(addr,size)  (0)
+#define get_fs()               (KERNEL_DS)
+
+static inline void set_fs(mm_segment_t fs)
+{
+}
+
+#define get_user(x,p)  __get_user(x,p)
+#define put_user(x,p)  __put_user(x,p)
+
+#endif /* CONFIG_MMU */
+
+#define access_ok(type,addr,size)      (__range_ok(addr,size) == 0)
+
+/*
+ * The "__xxx" versions of the user access functions do not verify the
+ * address space - it must have been done previously with a separate
+ * "access_ok()" call.
+ *
+ * The "xxx_error" versions set the third argument to EFAULT if an
+ * error occurs, and leave it unchanged on success.  Note that these
+ * versions are void (ie, don't return a value as such).
+ */
 #define __get_user(x,ptr)                                              \
 ({                                                                     \
        long __gu_err = 0;                                              \
@@ -212,43 +277,6 @@ do {                                                                       \
        : "r" (addr), "i" (-EFAULT)                             \
        : "cc")
 
-extern int __put_user_1(void *, unsigned int);
-extern int __put_user_2(void *, unsigned int);
-extern int __put_user_4(void *, unsigned int);
-extern int __put_user_8(void *, unsigned long long);
-extern int __put_user_bad(void);
-
-#define __put_user_x(__r2,__p,__e,__s)                                 \
-          __asm__ __volatile__ (                                       \
-               __asmeq("%0", "r0") __asmeq("%2", "r2")                 \
-               "bl     __put_user_" #__s                               \
-               : "=&r" (__e)                                           \
-               : "0" (__p), "r" (__r2)                                 \
-               : "ip", "lr", "cc")
-
-#define put_user(x,p)                                                  \
-       ({                                                              \
-               const register typeof(*(p)) __r2 asm("r2") = (x);       \
-               const register typeof(*(p)) __user *__p asm("r0") = (p);\
-               register int __e asm("r0");                             \
-               switch (sizeof(*(__p))) {                               \
-               case 1:                                                 \
-                       __put_user_x(__r2, __p, __e, 1);                \
-                       break;                                          \
-               case 2:                                                 \
-                       __put_user_x(__r2, __p, __e, 2);                \
-                       break;                                          \
-               case 4:                                                 \
-                       __put_user_x(__r2, __p, __e, 4);                \
-                       break;                                          \
-               case 8:                                                 \
-                       __put_user_x(__r2, __p, __e, 8);                \
-                       break;                                          \
-               default: __e = __put_user_bad(); break;                 \
-               }                                                       \
-               __e;                                                    \
-       })
-
 #define __put_user(x,ptr)                                              \
 ({                                                                     \
        long __pu_err = 0;                                              \
@@ -353,66 +381,54 @@ do {                                                                      \
        : "r" (x), "i" (-EFAULT)                                \
        : "cc")
 
-extern unsigned long __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
-extern unsigned long __arch_copy_to_user(void __user *to, const void *from, unsigned long n);
-extern unsigned long __arch_clear_user(void __user *addr, unsigned long n);
-extern unsigned long __arch_strncpy_from_user(char *to, const char __user *from, unsigned long count);
-extern unsigned long __arch_strnlen_user(const char __user *s, long n);
+
+#ifdef CONFIG_MMU
+extern unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n);
+extern unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n);
+extern unsigned long __clear_user(void __user *addr, unsigned long n);
+#else
+#define __copy_from_user(to,from,n)    (memcpy(to, (void __force *)from, n), 0)
+#define __copy_to_user(to,from,n)      (memcpy((void __force *)to, from, n), 0)
+#define __clear_user(addr,n)           (memset((void __force *)addr, 0, n), 0)
+#endif
+
+extern unsigned long __strncpy_from_user(char *to, const char __user *from, unsigned long count);
+extern unsigned long __strnlen_user(const char __user *s, long n);
 
 static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        if (access_ok(VERIFY_READ, from, n))
-               n = __arch_copy_from_user(to, from, n);
+               n = __copy_from_user(to, from, n);
        else /* security hole - plug it */
                memzero(to, n);
        return n;
 }
 
-static inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-       return __arch_copy_from_user(to, from, n);
-}
-
 static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
 {
        if (access_ok(VERIFY_WRITE, to, n))
-               n = __arch_copy_to_user(to, from, n);
+               n = __copy_to_user(to, from, n);
        return n;
 }
 
-static inline unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-       return __arch_copy_to_user(to, from, n);
-}
-
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
 
-static inline unsigned long clear_user (void __user *to, unsigned long n)
+static inline unsigned long clear_user(void __user *to, unsigned long n)
 {
        if (access_ok(VERIFY_WRITE, to, n))
-               n = __arch_clear_user(to, n);
+               n = __clear_user(to, n);
        return n;
 }
 
-static inline unsigned long __clear_user (void __user *to, unsigned long n)
-{
-       return __arch_clear_user(to, n);
-}
-
-static inline long strncpy_from_user (char *dst, const char __user *src, long count)
+static inline long strncpy_from_user(char *dst, const char __user *src, long count)
 {
        long res = -EFAULT;
        if (access_ok(VERIFY_READ, src, 1))
-               res = __arch_strncpy_from_user(dst, src, count);
+               res = __strncpy_from_user(dst, src, count);
        return res;
 }
 
-static inline long __strncpy_from_user (char *dst, const char __user *src, long count)
-{
-       return __arch_strncpy_from_user(dst, src, count);
-}
-
 #define strlen_user(s) strnlen_user(s, ~0UL >> 1)
 
 static inline long strnlen_user(const char __user *s, long n)
@@ -420,7 +436,7 @@ static inline long strnlen_user(const char __user *s, long n)
        unsigned long res = 0;
 
        if (__addr_ok(s))
-               res = __arch_strnlen_user(s, n);
+               res = __strnlen_user(s, n);
 
        return res;
 }
index 9e6f7ca9f5ae3623f9eed2bb11e6e236dc561fb5..bf65e9f4525d04f78dacff51b229ee7f767b0432 100644 (file)
@@ -35,6 +35,17 @@ struct ucontext {
  * bytes, to prevent unpredictable padding in the signal frame.
  */
 
+#ifdef CONFIG_CRUNCH
+#define CRUNCH_MAGIC           0x5065cf03
+#define CRUNCH_STORAGE_SIZE    (CRUNCH_SIZE + 8)
+
+struct crunch_sigframe {
+       unsigned long   magic;
+       unsigned long   size;
+       struct crunch_state     storage;
+} __attribute__((__aligned__(8)));
+#endif
+
 #ifdef CONFIG_IWMMXT
 /* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
 #define IWMMXT_MAGIC           0x12ef842a
@@ -74,6 +85,9 @@ struct vfp_sigframe
  * one of these.
  */
 struct aux_sigframe {
+#ifdef CONFIG_CRUNCH
+       struct crunch_sigframe  crunch;
+#endif
 #ifdef CONFIG_IWMMXT
        struct iwmmxt_sigframe  iwmmxt;
 #endif
index 341536a234e9ccd4e62cd4de8174821c450f4b5c..298066020af212a98a26c15b82b65401832ac151 100644 (file)
@@ -1,7 +1,5 @@
 #ifndef _ASM_HW_IRQ_H
 #define _ASM_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
-
 #endif
 
index 4b338792218b045ce9593af9f5bac2329f686986..998cce9f3200308dd6c87c5f23276e13709ae724 100644 (file)
@@ -1,11 +1,6 @@
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
-/*
- * IRQ line status macro IRQ_PER_CPU is used
- */
-#define ARCH_HAS_IRQ_PER_CPU
-
 #include <asm/arch/irq.h>
 
 static inline int irq_canonicalize(int irq)
index 845cb67ad8ea5d40bcb707462d30879255247b81..8ceab7bcd8b4f229f45536f8208e5394c99e9695 100644 (file)
        __ret;                                          \
 })
 
+#ifdef CONFIG_SMP
+# define WARN_ON_SMP(x)                        WARN_ON(x)
+#else
+# define WARN_ON_SMP(x)                        do { } while (0)
+#endif
+
 #endif
index 9d11550b481810e6f459598dcac969187c1f6a4b..db5a3732f1065a79dde1660e8149d70e2a18091b 100644 (file)
                VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;               \
        }                                                               \
                                                                        \
+       /* Kernel symbol table: Normal unused symbols */                \
+       __ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {  \
+               VMLINUX_SYMBOL(__start___ksymtab_unused) = .;           \
+               *(__ksymtab_unused)                                     \
+               VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;            \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-only unused symbols */              \
+       __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
+               VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;       \
+               *(__ksymtab_unused_gpl)                                 \
+               VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;        \
+       }                                                               \
+                                                                       \
        /* Kernel symbol table: GPL-future-only symbols */              \
        __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;       \
                VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;               \
        }                                                               \
                                                                        \
+       /* Kernel symbol table: Normal unused symbols */                \
+       __kcrctab_unused  : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) {  \
+               VMLINUX_SYMBOL(__start___kcrctab_unused) = .;           \
+               *(__kcrctab_unused)                                     \
+               VMLINUX_SYMBOL(__stop___kcrctab_unused) = .;            \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-only unused symbols */              \
+       __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
+               VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .;       \
+               *(__kcrctab_unused_gpl)                                 \
+               VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .;        \
+       }                                                               \
+                                                                       \
        /* Kernel symbol table: GPL-future-only symbols */              \
        __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;       \
index e7252c216ca81cc8d6543f51b51fa1f8a216d194..b1bc7b1b64b0e304d13f907e4d5cd607417bdfee 100644 (file)
@@ -7,8 +7,6 @@
 #include <linux/nodemask.h>
 #include <linux/percpu.h>
 
-#include <asm/node.h>
-
 struct i386_cpu {
        struct cpu cpu;
 };
index 4153d80e4d2b86535a6e55a6e72a30ba7b5b5699..1eac92cb5b161744c463eec3ccd7d84395cc02f0 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/processor.h>
 #include <asm/system.h>                /* for savesegment */
 #include <asm/auxvec.h>
+#include <asm/desc.h>
 
 #include <linux/utsname.h>
 
@@ -129,15 +130,41 @@ extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct
 #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
 #define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
 
-#define VSYSCALL_BASE  (__fix_to_virt(FIX_VSYSCALL))
-#define VSYSCALL_EHDR  ((const struct elfhdr *) VSYSCALL_BASE)
-#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall)
+#define VDSO_HIGH_BASE         (__fix_to_virt(FIX_VDSO))
+#define VDSO_BASE              ((unsigned long)current->mm->context.vdso)
+
+#ifdef CONFIG_COMPAT_VDSO
+# define VDSO_COMPAT_BASE      VDSO_HIGH_BASE
+# define VDSO_PRELINK          VDSO_HIGH_BASE
+#else
+# define VDSO_COMPAT_BASE      VDSO_BASE
+# define VDSO_PRELINK          0
+#endif
+
+#define VDSO_COMPAT_SYM(x) \
+               (VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK)
+
+#define VDSO_SYM(x) \
+               (VDSO_BASE + (unsigned long)(x) - VDSO_PRELINK)
+
+#define VDSO_HIGH_EHDR         ((const struct elfhdr *) VDSO_HIGH_BASE)
+#define VDSO_EHDR              ((const struct elfhdr *) VDSO_COMPAT_BASE)
+
 extern void __kernel_vsyscall;
 
+#define VDSO_ENTRY             VDSO_SYM(&__kernel_vsyscall)
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+                                       int executable_stack);
+
+extern unsigned int vdso_enabled;
+
 #define ARCH_DLINFO                                            \
-do {                                                           \
-               NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY);        \
-               NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE);    \
+do if (vdso_enabled) {                                         \
+               NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY);            \
+               NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \
 } while (0)
 
 /*
@@ -148,15 +175,15 @@ do {                                                              \
  * Dumping its extra ELF program headers includes all the other information
  * a debugger needs to easily find how the vsyscall DSO was being used.
  */
-#define ELF_CORE_EXTRA_PHDRS           (VSYSCALL_EHDR->e_phnum)
+#define ELF_CORE_EXTRA_PHDRS           (VDSO_HIGH_EHDR->e_phnum)
 #define ELF_CORE_WRITE_EXTRA_PHDRS                                           \
 do {                                                                         \
        const struct elf_phdr *const vsyscall_phdrs =                         \
-               (const struct elf_phdr *) (VSYSCALL_BASE                      \
-                                          + VSYSCALL_EHDR->e_phoff);         \
+               (const struct elf_phdr *) (VDSO_HIGH_BASE                     \
+                                          + VDSO_HIGH_EHDR->e_phoff);    \
        int i;                                                                \
        Elf32_Off ofs = 0;                                                    \
-       for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
+       for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) {               \
                struct elf_phdr phdr = vsyscall_phdrs[i];                     \
                if (phdr.p_type == PT_LOAD) {                                 \
                        BUG_ON(ofs != 0);                                     \
@@ -174,10 +201,10 @@ do {                                                                            \
 #define ELF_CORE_WRITE_EXTRA_DATA                                            \
 do {                                                                         \
        const struct elf_phdr *const vsyscall_phdrs =                         \
-               (const struct elf_phdr *) (VSYSCALL_BASE                      \
-                                          + VSYSCALL_EHDR->e_phoff);         \
+               (const struct elf_phdr *) (VDSO_HIGH_BASE                     \
+                                          + VDSO_HIGH_EHDR->e_phoff);    \
        int i;                                                                \
-       for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
+       for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) {               \
                if (vsyscall_phdrs[i].p_type == PT_LOAD)                      \
                        DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr,        \
                                   PAGE_ALIGN(vsyscall_phdrs[i].p_memsz));    \
index f7e068f4d2f98d7cdb8c5198cd26c1796bb3d9dc..a48cc3f7ccc688a725595e46bb21c6e2fe7fb0ad 100644 (file)
@@ -51,7 +51,7 @@
  */
 enum fixed_addresses {
        FIX_HOLE,
-       FIX_VSYSCALL,
+       FIX_VDSO,
 #ifdef CONFIG_X86_LOCAL_APIC
        FIX_APIC_BASE,  /* local (CPU) APIC) -- required for SMP or not */
 #endif
@@ -115,14 +115,6 @@ extern void __set_fixmap (enum fixed_addresses idx,
 #define __fix_to_virt(x)       (FIXADDR_TOP - ((x) << PAGE_SHIFT))
 #define __virt_to_fix(x)       ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
 
-/*
- * This is the range that is readable by user mode, and things
- * acting like user mode such as get_user_pages.
- */
-#define FIXADDR_USER_START     (__fix_to_virt(FIX_VSYSCALL))
-#define FIXADDR_USER_END       (FIXADDR_USER_START + PAGE_SIZE)
-
-
 extern void __this_fixmap_does_not_exist(void);
 
 /*
index a4c0a5a9ffd84cd4a5c18eab814dc89f08cb69f8..87e5a351d8812b369bf1fc88187214d947d87fa9 100644 (file)
@@ -69,14 +69,4 @@ extern atomic_t irq_mis_count;
 
 #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
 
-#if defined(CONFIG_X86_IO_APIC)
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-       if (IO_APIC_IRQ(i))
-               send_IPI_self(IO_APIC_VECTOR(i));
-}
-#else
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
-#endif
-
 #endif /* _ASM_HW_IRQ_H */
index b92d6d9a4d3ced6b7785a9f4d9bdbdf0d124e427..33f700ef68316048cdb049f436d187d57854295a 100644 (file)
@@ -1,5 +1,8 @@
 /* Hook to call BIOS initialisation function */
 
+extern unsigned long sgivwfb_mem_phys;
+extern unsigned long sgivwfb_mem_size;
+
 /* no action for visws */
 
 #define ARCH_SETUP
index f431a0b86d4c46669e49b0fe4811a64017a27385..8358dd3df7aa22c1eb5bd4637f68b47b5509cd76 100644 (file)
@@ -12,6 +12,7 @@ typedef struct {
        int size;
        struct semaphore sem;
        void *ldt;
+       void *vdso;
 } mm_context_t;
 
 #endif
diff --git a/include/asm-i386/node.h b/include/asm-i386/node.h
deleted file mode 100644 (file)
index e13c6ff..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _ASM_I386_NODE_H_
-#define _ASM_I386_NODE_H_
-
-#include <linux/device.h>
-#include <linux/mmzone.h>
-#include <linux/node.h>
-#include <linux/topology.h>
-#include <linux/nodemask.h>
-
-struct i386_node {
-       struct node node;
-};
-extern struct i386_node node_devices[MAX_NUMNODES];
-
-static inline int arch_register_node(int num){
-       int p_node;
-       struct node *parent = NULL;
-
-       if (!node_online(num))
-               return 0;
-       p_node = parent_node(num);
-
-       if (p_node != num)
-               parent = &node_devices[p_node].node;
-
-       return register_node(&node_devices[num].node, num, parent);
-}
-
-#endif /* _ASM_I386_NODE_H_ */
index e3a552fa5538744bd578d6351c8c23756774c782..f5bf544c729a373aa4ec1832aa9fa3cd55a13800 100644 (file)
@@ -96,6 +96,8 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 #ifndef __ASSEMBLY__
 
+struct vm_area_struct;
+
 /*
  * This much address space is reserved for vmalloc() and iomap()
  * as well as fixmap mappings.
@@ -139,6 +141,7 @@ extern int page_is_ram(unsigned long pagenr);
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
+#define __HAVE_ARCH_GATE_AREA 1
 #endif /* __KERNEL__ */
 
 #endif /* _I386_PAGE_H */
index 55ea992da32954c2bdd1aca5c5c902f7b4c3b02a..b32346d62e1039d956c919b190836f2ab0217ef1 100644 (file)
@@ -71,8 +71,12 @@ struct cpuinfo_x86 {
        cpumask_t llc_shared_map;       /* cpus sharing the last level cache */
 #endif
        unsigned char x86_max_cores;    /* cpuid returned max cores value */
-       unsigned char booted_cores;     /* number of cores as seen by OS */
        unsigned char apicid;
+#ifdef CONFIG_SMP
+       unsigned char booted_cores;     /* number of cores as seen by OS */
+       __u8 phys_proc_id;              /* Physical processor id. */
+       __u8 cpu_core_id;               /* Core id */
+#endif
 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
 
 #define X86_VENDOR_INTEL 0
@@ -104,8 +108,6 @@ extern struct cpuinfo_x86 cpu_data[];
 #define current_cpu_data boot_cpu_data
 #endif
 
-extern int phys_proc_id[NR_CPUS];
-extern int cpu_core_id[NR_CPUS];
 extern int cpu_llc_id[NR_CPUS];
 extern char ignore_fpu_irq;
 
index fdbc7f422ea5501ec586eabed02b349072e0184b..2833fa2c0dd0e6d5a54b5b6539123533f9c04855 100644 (file)
@@ -37,6 +37,7 @@ struct thread_info {
                                                   0-0xBFFFFFFF for user-thead
                                                   0-0xFFFFFFFF for kernel-thread
                                                */
+       void                    *sysenter_return;
        struct restart_block    restart_block;
 
        unsigned long           previous_esp;   /* ESP of the previous stack in case
@@ -83,17 +84,15 @@ struct thread_info {
 #define init_stack             (init_thread_union.stack)
 
 
+/* how to get the current stack pointer from C */
+register unsigned long current_stack_pointer asm("esp") __attribute_used__;
+
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
-       struct thread_info *ti;
-       __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));
-       return ti;
+       return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE - 1));
 }
 
-/* how to get the current stack pointer from C */
-register unsigned long current_stack_pointer asm("esp") __attribute_used__;
-
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
 #define alloc_thread_info(tsk)                                 \
index b94e5eeef917ea92d9f7339593e1bda8dcc3bafd..6adbd9b1ae881121e9f377a121ec0c4e9355361c 100644 (file)
 #define _ASM_I386_TOPOLOGY_H
 
 #ifdef CONFIG_X86_HT
-#define topology_physical_package_id(cpu)                              \
-       (phys_proc_id[cpu] == BAD_APICID ? -1 : phys_proc_id[cpu])
-#define topology_core_id(cpu)                                          \
-       (cpu_core_id[cpu] == BAD_APICID ? 0 : cpu_core_id[cpu])
+#define topology_physical_package_id(cpu)      (cpu_data[cpu].phys_proc_id)
+#define topology_core_id(cpu)                  (cpu_data[cpu].cpu_core_id)
 #define topology_core_siblings(cpu)            (cpu_core_map[cpu])
 #define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
 #endif
@@ -114,4 +112,9 @@ extern unsigned long node_remap_size[];
 
 extern cpumask_t cpu_coregroup_map(int cpu);
 
+#ifdef CONFIG_SMP
+#define mc_capable()   (boot_cpu_data.x86_max_cores > 1)
+#define smt_capable()  (smp_num_siblings > 1)
+#endif
+
 #endif /* _ASM_I386_TOPOLOGY_H */
index d480f2e38215d69df898f89e11519f3c00b9dc85..69f0f1df67220edd0bc7bfe0b2148c6038b86e05 100644 (file)
@@ -78,8 +78,8 @@ static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
        return user_mode_vm(&info->regs);
 #else
        return info->regs.eip < PAGE_OFFSET
-              || (info->regs.eip >= __fix_to_virt(FIX_VSYSCALL)
-                   && info->regs.eip < __fix_to_virt(FIX_VSYSCALL) + PAGE_SIZE)
+              || (info->regs.eip >= __fix_to_virt(FIX_VDSO)
+                   && info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE)
               || info->regs.esp < PAGE_OFFSET;
 #endif
 }
index ea8b8c407ab4a210f50b055c2030cb34222fdca0..27f9df6b914539401c26421ce0bb38d970ef0081 100644 (file)
@@ -97,8 +97,7 @@ extern int reserve_irq_vector (int vector);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
 
-static inline void
-hw_resend_irq (struct hw_interrupt_type *h, unsigned int vector)
+static inline void ia64_resend_irq(unsigned int vector)
 {
        platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0);
 }
index dbe86c0bbce5f896f25e4934228ac2c36228227a..79479e2c6966b0cb468db6f348538e8b0e19d32f 100644 (file)
 #define NR_IRQS                256
 #define NR_IRQ_VECTORS NR_IRQS
 
-/*
- * IRQ line status macro IRQ_PER_CPU is used
- */
-#define ARCH_HAS_IRQ_PER_CPU
-
 static __inline__ int
 irq_canonicalize (int irq)
 {
index a140310bf84dcb4120980b883965a9ea9260a847..2fb337b0e9b786486508a6611c3e6e098ea58781 100644 (file)
@@ -46,6 +46,18 @@ struct ia64_node_data {
  */
 #define NODE_DATA(nid)         (local_node_data->pg_data_ptrs[nid])
 
+/*
+ * LOCAL_DATA_ADDR - This is to calculate the address of other node's
+ *                  "local_node_data" at hot-plug phase. The local_node_data
+ *                  is pointed by per_cpu_page. Kernel usually use it for
+ *                  just executing cpu. However, when new node is hot-added,
+ *                  the addresses of local data for other nodes are necessary
+ *                  to update all of them.
+ */
+#define LOCAL_DATA_ADDR(pgdat)                         \
+       ((struct ia64_node_data *)((u64)(pgdat) +       \
+                                  L1_CACHE_ALIGN(sizeof(struct pglist_data))))
+
 #endif /* CONFIG_NUMA */
 
 #endif /* _ASM_IA64_NODEDATA_H */
index cd490b20d59268cc9723b7b23dd036d1c215d078..bd4452bda357b8e58837daf43093be52d147bade 100644 (file)
@@ -85,6 +85,7 @@
 #define  SN_SAL_GET_PROM_FEATURE_SET              0x02000065
 #define  SN_SAL_SET_OS_FEATURE_SET                0x02000066
 #define  SN_SAL_INJECT_ERROR                      0x02000067
+#define  SN_SAL_SET_CPU_NUMBER                    0x02000068
 
 /*
  * Service-specific constants
@@ -1150,4 +1151,13 @@ sn_inject_error(u64 paddr, u64 *data, u64 *ecc)
        local_irq_restore(irq_flags);
        return ret_stuff.status;
 }
+
+static inline int
+ia64_sn_set_cpu_number(int cpu)
+{
+       struct ia64_sal_retval rv;
+
+       SAL_CALL_NOLOCK(rv, SN_SAL_SET_CPU_NUMBER, cpu, 0, 0, 0, 0, 0, 0);
+       return rv.status;
+}
 #endif /* _ASM_IA64_SN_SN_SAL_H */
index 616b5ed2aa7277e12885e6e35805d4fcacf748d9..937c212575239f3ec9ee9526e2c989289669f967 100644 (file)
@@ -112,6 +112,7 @@ void build_cpu_to_node_map(void);
 #define topology_core_id(cpu)                  (cpu_data(cpu)->core_id)
 #define topology_core_siblings(cpu)            (cpu_core_map[cpu])
 #define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
+#define smt_capable()                          (smp_num_siblings > 1)
 #endif
 
 #include <asm-generic/topology.h>
index 8d7e9d0e09e876329089bc7401c662430dc78ae2..7138537cda03017c2bce4cb15f1a7a7380a82a2a 100644 (file)
@@ -1,9 +1,4 @@
 #ifndef _ASM_M32R_HW_IRQ_H
 #define _ASM_M32R_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-       /* Nothing to do */
-}
-
 #endif /* _ASM_M32R_HW_IRQ_H */
index 3fdc79f06d501a44cfe60045588f7c072968cf4f..bdc1a4ac4fe956ebdfdfe12746c3a0932a844214 100644 (file)
@@ -52,7 +52,7 @@ type name(void) \
    __asm__ __volatile__ ("trap #2" \
                          : "=g" (__res) \
                          : "0" (__res) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -64,7 +64,7 @@ type name(atype a) \
    __asm__ __volatile__ ("trap #2" \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -77,7 +77,7 @@ type name(atype a, btype b) \
    __asm__ __volatile__ ("trap #2" \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a), "d" (__b) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -92,7 +92,7 @@ type name(atype a, btype b, ctype c) \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a), "d" (__b), \
                            "d" (__c) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -108,7 +108,7 @@ type name(atype a, btype b, ctype c, dtype d) \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a), "d" (__b), \
                            "d" (__c), "d" (__d) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -125,7 +125,7 @@ type name(atype a, btype b, ctype c, dtype d, etype e) \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a), "d" (__b), \
                            "d" (__c), "d" (__d), "d" (__e) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
index 1e19c457de7de9750f15ae842887aad8f4faf96a..47258e86e8c4a69e996504d52e34abfcea3524a4 100644 (file)
@@ -46,11 +46,9 @@ struct pt_regs {
 #else
   unsigned short sr;
   unsigned long  pc;
-#ifndef NO_FORMAT_VEC
   unsigned format :  4; /* frame format specifier */
   unsigned vector : 12; /* vector offset */
 #endif
-#endif
 };
 
 /*
index c854d017c0e5b2090af5b3bdadc56751b839a504..458d9fdc76bf2eed4372a0993dd0ebb0f1b08baa 100644 (file)
@@ -19,9 +19,9 @@ extern void init_8259A(int aeoi);
 
 extern atomic_t irq_err_count;
 
-/* This may not be apropriate for all machines, we'll see ...  */
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-}
+/*
+ * interrupt-retrigger: NOP for now. This may not be apropriate for all
+ * machines, we'll see ...
+ */
 
 #endif /* __ASM_HW_IRQ_H */
index 083d9c512a04914c6520f54603c310af932a5213..e994b0c012279a316693e403b4f94d80ea522c4d 100644 (file)
@@ -4,10 +4,4 @@
 
 #define NR_IRQS        256
 
-#ifdef CONFIG_SMP
-
-#define ARCH_HAS_IRQ_PER_CPU
-
-#endif
-
 #endif /* __ASM_MACH_MIPS_IRQ_H */
index 3ce3440d1b0ca89fd19c3871abac0f21c646ff1f..1a7bfe699e0ccc5a33b5ab1a3c65e9b0822b780f 100644 (file)
@@ -48,6 +48,7 @@
 #define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE)
 
 #ifdef CONFIG_PA20
+#define LDCW           ldcw,co
 #define BL             b,l
 # ifdef CONFIG_64BIT
 #  define LEVEL                2.0w
@@ -55,6 +56,7 @@
 #  define LEVEL                2.0
 # endif
 #else
+#define LDCW           ldcw
 #define BL             bl
 #define LEVEL          1.1
 #endif
index 289624d8b2d4681cfaed6a729a5313e07b153930..71b4eeea205a1a85eda581179fd97b46eeee0e83 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/personality.h>
 
 #define COMPAT_USER_HZ 100
 
@@ -149,4 +150,14 @@ static __inline__ void __user *compat_alloc_user_space(long len)
        return (void __user *)regs->gr[30];
 }
 
+static inline int __is_compat_task(struct task_struct *t)
+{
+       return personality(t->personality) == PER_LINUX32;
+}
+
+static inline int is_compat_task(void)
+{
+       return __is_compat_task(current);
+}
+
 #endif /* _ASM_PARISC_COMPAT_H */
index 151426e275213c23a6e1afa124fcb681a672e54e..6707f7df3921f566e044bb39ea0c31b95154f290 100644 (file)
@@ -3,15 +3,6 @@
 
 /*
  *     linux/include/asm/hw_irq.h
- *
- *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
- *
- *     moved some of the old arch/i386/kernel/irq.h to here. VY
- *
- *     IRQ/IPI changes taken from work by Thomas Radke
- *     <tomsoft@informatik.tu-chemnitz.de>
  */
 
-extern void hw_resend_irq(struct hw_interrupt_type *, unsigned int);
-
 #endif
index 377ba90c7d0256841568386405399164191569b4..5cae260615a22a74d14075d529a47419e9d02137 100644 (file)
 
 #define NR_IRQS                (CPU_IRQ_MAX + 1)
 
-/*
- * IRQ line status macro IRQ_PER_CPU is used
- */
-#define ARCH_HAS_IRQ_PER_CPU
-
 static __inline__ int irq_canonicalize(int irq)
 {
        return (irq == 2) ? 9 : irq;
index 08364f957e7a8811e50ed54f27ed5550e38395ff..c9b2e35326eed89eba875cd506262fdd485b21f4 100644 (file)
@@ -278,12 +278,11 @@ typedef struct {
 /* constants for OS (NVM...) */
 #define OS_ID_NONE             0       /* Undefined OS ID      */
 #define OS_ID_HPUX             1       /* HP-UX OS             */
-#define OS_ID_LINUX            OS_ID_HPUX /* just use the same value as hpux */
 #define OS_ID_MPEXL            2       /* MPE XL OS            */
 #define OS_ID_OSF              3       /* OSF OS               */
 #define OS_ID_HPRT             4       /* HP-RT OS             */
 #define OS_ID_NOVEL            5       /* NOVELL OS            */
-#define OS_ID_NT               6       /* NT OS                */
+#define OS_ID_LINUX            6       /* Linux                */
 
 
 /* constants for PDC_CHASSIS */
@@ -352,8 +351,8 @@ struct pdc_cache_cf {               /* for PDC_CACHE  (I/D-caches) */
                cc_wt   : 1,    /* 0 = WT-Dcache, 1 = WB-Dcache */
                cc_sh   : 2,    /* 0 = separate I/D-cache, else shared I/D-cache */
                cc_cst  : 3,    /* 0 = incoherent D-cache, 1=coherent D-cache */
-               cc_pad1 : 5,    /* reserved */
-               cc_assoc: 8;    /* associativity of I/D-cache */
+               cc_pad1 : 10,   /* reserved */
+               cc_hv   : 3;    /* hversion dependent */
 };
 
 struct pdc_tlb_cf {            /* for PDC_CACHE (I/D-TLB's) */
@@ -719,6 +718,7 @@ void setup_pdc(void);               /* in inventory.c */
 int pdc_add_valid(unsigned long address);
 int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
 int pdc_chassis_disp(unsigned long disp);
+int pdc_chassis_warn(unsigned long *warn);
 int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
 int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
                  void *iodc_data, unsigned int iodc_data_size);
@@ -732,6 +732,7 @@ int pdc_model_cpuid(unsigned long *cpu_id);
 int pdc_model_versions(unsigned long *versions, int id);
 int pdc_model_capabilities(unsigned long *capabilities);
 int pdc_cache_info(struct pdc_cache_info *cache);
+int pdc_spaceid_bits(unsigned long *space_bits);
 #ifndef CONFIG_PA20
 int pdc_btlb_info(struct pdc_btlb_info *btlb);
 int pdc_mem_map_hpa(struct pdc_memory_map *r_addr, struct pdc_module_path *mod_path);
@@ -775,6 +776,18 @@ int pdc_sti_call(unsigned long func, unsigned long flags,
 
 extern void pdc_init(void);
 
+static inline char * os_id_to_string(u16 os_id) {
+       switch(os_id) {
+       case OS_ID_NONE:        return "No OS";
+       case OS_ID_HPUX:        return "HP-UX";
+       case OS_ID_MPEXL:       return "MPE-iX";
+       case OS_ID_OSF:         return "OSF";
+       case OS_ID_HPRT:        return "HP-RT";
+       case OS_ID_NOVEL:       return "Novell Netware";
+       case OS_ID_LINUX:       return "Linux";
+       default:        return "Unknown";
+       }
+}
 #endif /* __ASSEMBLY__ */
 
 #endif /* _PARISC_PDC_H */
index b6bcc672ba8064610bf0286f9cf34988774c44e6..5066c54dae0ab422cf2dad44dff9a95007ff8f4f 100644 (file)
@@ -506,13 +506,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 
 /* TLB page size encoding - see table 3-1 in parisc20.pdf */
 #define _PAGE_SIZE_ENCODING_4K         0
-#define _PAGE_SIZE_ENCODING_16K        1
-#define _PAGE_SIZE_ENCODING_64K        2
+#define _PAGE_SIZE_ENCODING_16K                1
+#define _PAGE_SIZE_ENCODING_64K                2
 #define _PAGE_SIZE_ENCODING_256K       3
 #define _PAGE_SIZE_ENCODING_1M         4
 #define _PAGE_SIZE_ENCODING_4M         5
-#define _PAGE_SIZE_ENCODING_16M        6
-#define _PAGE_SIZE_ENCODING_64M        7
+#define _PAGE_SIZE_ENCODING_16M                6
+#define _PAGE_SIZE_ENCODING_64M                7
 
 #if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
 # define _PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_4K
index ca49dc91f4fca86bff592f5336ab4265a80ca497..b73626f040dace5eb8d091636be645ed564864a0 100644 (file)
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
  */
-
-/* We cannot use MFIA as it was added for PA2.0 - prumpf
-
-   At one point there were no "0f/0b" type local symbols in gas for
-   PA-RISC.  This is no longer true, but this still seems like the
-   nicest way to implement this. */
-
-#define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; })
+#ifdef CONFIG_PA20
+#define current_ia(x)  __asm__("mfia %0" : "=r"(x))
+#else /* mfia added in pa2.0 */
+#define current_ia(x)  __asm__("blr 0,%0\n\tnop" : "=r"(x))
+#endif
+#define current_text_addr() ({ void *pc; current_ia(pc); pc; })
 
 #define TASK_SIZE               (current->thread.task_size)
 #define TASK_UNMAPPED_BASE      (current->thread.map_base)
index 863876134b2ca9cce106096cfff6551689403c79..5fe2d2329ab5e7c7dbd8121351b1ea7fcef54dbc 100644 (file)
@@ -155,13 +155,14 @@ static inline void set_eiem(unsigned long val)
    type and dynamically select the 16-byte aligned int from the array
    for the semaphore.  */
 
-#define __PA_LDCW_ALIGNMENT 16
-#define __ldcw_align(a) ({ \
-  unsigned long __ret = (unsigned long) &(a)->lock[0];                 \
-  __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); \
-  (volatile unsigned int *) __ret;                                      \
+#define __PA_LDCW_ALIGNMENT    16
+#define __ldcw_align(a) ({                                     \
+       unsigned long __ret = (unsigned long) &(a)->lock[0];    \
+       __ret = (__ret + __PA_LDCW_ALIGNMENT - 1)               \
+               & ~(__PA_LDCW_ALIGNMENT - 1);                   \
+       (volatile unsigned int *) __ret;                        \
 })
-#define LDCW   "ldcw"
+#define __LDCW "ldcw"
 
 #else /*CONFIG_PA20*/
 /* From: "Jim Hull" <jim.hull of hp.com>
@@ -171,17 +172,18 @@ static inline void set_eiem(unsigned long val)
    they only require "natural" alignment (4-byte for ldcw, 8-byte for
    ldcd). */
 
-#define __PA_LDCW_ALIGNMENT 4
+#define __PA_LDCW_ALIGNMENT    4
 #define __ldcw_align(a) ((volatile unsigned int *)a)
-#define LDCW   "ldcw,co"
+#define __LDCW "ldcw,co"
 
 #endif /*!CONFIG_PA20*/
 
 /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
-#define __ldcw(a) ({ \
-       unsigned __ret; \
-       __asm__ __volatile__(LDCW " 0(%1),%0" : "=r" (__ret) : "r" (a)); \
-       __ret; \
+#define __ldcw(a) ({                                           \
+       unsigned __ret;                                         \
+       __asm__ __volatile__(__LDCW " 0(%1),%0"                 \
+               : "=r" (__ret) : "r" (a));                      \
+       __ret;                                                  \
 })
 
 #ifdef CONFIG_SMP
index f6c417c8c484a8965eee6ac6cfd175d45a82c8d4..d973e8b3466ca805afbdf52a846211434f2e8269 100644 (file)
@@ -172,7 +172,11 @@ struct exception_data {
 /*
  * The "__put_user/kernel_asm()" macros tell gcc they read from memory
  * instead of writing. This is because they do not write to any memory
- * gcc knows about, so there are no aliasing issues.
+ * gcc knows about, so there are no aliasing issues. These macros must
+ * also be aware that "fixup_put_user_skip_[12]" are executed in the
+ * context of the fault, and any registers used there must be listed
+ * as clobbers. In this case only "r1" is used by the current routines.
+ * r8/r9 are already listed as err/val.
  */
 
 #ifdef __LP64__
@@ -183,7 +187,8 @@ struct exception_data {
                "\t.dword\t1b,fixup_put_user_skip_1\n"      \
                "\t.previous"                               \
                : "=r"(__pu_err)                            \
-               : "r"(ptr), "r"(x), "0"(__pu_err))
+               : "r"(ptr), "r"(x), "0"(__pu_err)           \
+               : "r1")
 
 #define __put_user_asm(stx,x,ptr)                           \
        __asm__ __volatile__ (                              \
index 12b867238a4751438fc76b3ac37132fd37f5f938..27bcfad1c3e337cf3642245c3430dba14202ccb4 100644 (file)
 
 #define SYS_ify(syscall_name)   __NR_##syscall_name
 
-/* Assume all syscalls are done from PIC code just to be
- * safe. The worst case scenario is that you lose a register
- * and save/restore r19 across the syscall. */
-#define PIC
-
 #ifndef ASM_LINE_SEP
 # define ASM_LINE_SEP ;
 #endif
index ce0f7db63c1673a1435d93e7906a27bb9cb947cd..d40359204abaa1ff38743c718a72e40ba22d3f96 100644 (file)
@@ -86,27 +86,27 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 #define mask_irq(irq)                                          \
        ({                                                      \
                irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->handler && desc->handler->disable)    \
-                       desc->handler->disable(irq);            \
+               if (desc->chip && desc->chip->disable)  \
+                       desc->chip->disable(irq);               \
        })
 #define unmask_irq(irq)                                                \
        ({                                                      \
                irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->handler && desc->handler->enable)     \
-                       desc->handler->enable(irq);             \
+               if (desc->chip && desc->chip->enable)   \
+                       desc->chip->enable(irq);                \
        })
 #define ack_irq(irq)                                           \
        ({                                                      \
                irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->handler && desc->handler->ack)        \
-                       desc->handler->ack(irq);                \
+               if (desc->chip && desc->chip->ack)      \
+                       desc->chip->ack(irq);           \
        })
 
-/* Should we handle this via lost interrupts and IPIs or should we don't care like
- * we do now ? --BenH.
+/*
+ * interrupt-retrigger: should we handle this via lost interrupts and IPIs
+ * or should we not care like we do now ? --BenH.
  */
 struct hw_interrupt_type;
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HW_IRQ_H */
index a10feec29d4d4dce05685d8e112cecbbf37d8a29..eb5f33e1977a2cce8ff839eb7917f2813b4b7ce1 100644 (file)
 #define IRQ_POLARITY_POSITIVE  0x2     /* high level or low->high edge */
 #define IRQ_POLARITY_NEGATIVE  0x0     /* low level or high->low edge */
 
-/*
- * IRQ line status macro IRQ_PER_CPU is used
- */
-#define ARCH_HAS_IRQ_PER_CPU
-
 #define get_irq_desc(irq) (&irq_desc[(irq)])
 
 /* Define a way to iterate across irqs. */
index 5d2c9e6c4be2ba1483118e2de61b572ccbb2c2b1..46afd29b904e47694c1f2127b07738bf091cd075 100644 (file)
@@ -242,7 +242,7 @@ extern pgprot_t     pci_phys_mem_access_prot(struct file *file,
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
 extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
                                 const struct resource *rsrc,
-                                u64 *start, u64 *end);
+                                resource_size_t *start, resource_size_t *end);
 #endif /* CONFIG_PPC_MULTIPLATFORM || CONFIG_PPC32 */
 
 #endif /* __KERNEL__ */
index 92f3e5507d224cfc1cbf80e10d7d6bc09647a804..bbc3844b086fcadd9f529c69f5b12b6556530667 100644 (file)
@@ -93,5 +93,10 @@ static inline void sysfs_remove_device_from_node(struct sys_device *dev,
 
 #endif /* CONFIG_NUMA */
 
+#ifdef CONFIG_SMP
+#include <asm/cputable.h>
+#define smt_capable()          (cpu_has_feature(CPU_FTR_SMT))
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_TOPOLOGY_H */
index 61434edbad7b7fd8489ca0a11743f0e604b565da..11ffaaa5da165abe9adec4d586eba35864fa71dc 100644 (file)
@@ -133,7 +133,7 @@ extern pgprot_t     pci_phys_mem_access_prot(struct file *file,
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
 extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
                                 const struct resource *rsrc,
-                                u64 *start, u64 *end);
+                                resource_size_t *start, resource_size_t *end);
 
 
 #endif /* __KERNEL__ */
index 4d2b126ba15961a6b7f7ee8b83d0e751d02b9a8c..0ddcdba79e4a91b6b04b140810994f31bd5636a8 100644 (file)
@@ -12,6 +12,9 @@
  *    Copyright (C) 1992, Linus Torvalds
  *
  */
+
+#ifdef __KERNEL__
+
 #include <linux/compiler.h>
 
 /*
  * with operation of the form "set_bit(bitnr, flags)".
  */
 
-/* set ALIGN_CS to 1 if the SMP safe bit operations should
- * align the address to 4 byte boundary. It seems to work
- * without the alignment. 
- */
-#ifdef __KERNEL__
-#define ALIGN_CS 0
-#else
-#define ALIGN_CS 1
-#ifndef CONFIG_SMP
-#error "bitops won't work without CONFIG_SMP"
-#endif
-#endif
-
 /* bitmap tables from arch/S390/kernel/bitmap.S */
 extern const char _oi_bitmap[];
 extern const char _ni_bitmap[];
@@ -121,10 +111,6 @@ static inline void set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make OR mask */
@@ -141,10 +127,6 @@ static inline void clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make AND mask */
@@ -161,10 +143,6 @@ static inline void change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make XOR mask */
@@ -182,10 +160,6 @@ test_and_set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make OR/test mask */
@@ -205,10 +179,6 @@ test_and_clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make AND/test mask */
@@ -228,10 +198,6 @@ test_and_change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;  /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;       /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make XOR/test mask */
@@ -834,8 +800,6 @@ static inline int sched_find_first_bit(unsigned long *b)
 
 #include <asm-generic/bitops/hweight.h>
 
-#ifdef __KERNEL__
-
 /*
  * ATTENTION: intel byte ordering convention for ext2 and minix !!
  * bit 0 is the LSB of addr; bit 31 is the MSB of addr;
index 089cf567c317b48f09501a377e73b320a59192d0..2b16193063513003e49e7327e8e5add0690f48a9 100644 (file)
@@ -276,6 +276,8 @@ extern void wait_cons_dev(void);
 
 extern void clear_all_subchannels(void);
 
+extern void css_schedule_reprobe(void);
+
 #endif
 
 #endif
index 2d09950a9c11207d43daaa593860256bc52438b1..241756f80df35260a06641d523f42a519170f513 100644 (file)
@@ -44,10 +44,6 @@ struct cmbdata {
 #define BIODASDCMFENABLE       _IO(DASD_IOCTL_LETTER,32)
 /* enable channel measurement */
 #define BIODASDCMFDISABLE      _IO(DASD_IOCTL_LETTER,33)
-/* reset channel measurement block */
-#define BIODASDRESETCMB                _IO(DASD_IOCTL_LETTER,34)
-/* read channel measurement data */
-#define BIODASDREADCMB         _IOWR(DASD_IOCTL_LETTER,32,__u64)
 /* read channel measurement data */
 #define BIODASDREADALLCMB      _IOWR(DASD_IOCTL_LETTER,33,struct cmbdata)
 
index 1630c26e8f45a5c27eef949454fb4702747fc7f0..c042f9578081a4ece5e06afb1b996bd558ed3416 100644 (file)
@@ -68,10 +68,12 @@ typedef struct dasd_information2_t {
  * 0x00: default features
  * 0x01: readonly (ro)
  * 0x02: use diag discipline (diag)
+ * 0x04: set the device initially online (internal use only)
  */
-#define DASD_FEATURE_DEFAULT  0
-#define DASD_FEATURE_READONLY 1
-#define DASD_FEATURE_USEDIAG  2
+#define DASD_FEATURE_DEFAULT        0x00
+#define DASD_FEATURE_READONLY       0x01
+#define DASD_FEATURE_USEDIAG        0x02
+#define DASD_FEATURE_INITIAL_ONLINE  0x04
 
 #define DASD_PARTN_BITS 2
 
index 8e0c7ed73d0312a811c5a3f887527747a6c669c3..0a518915bf90f1087466444caf0809a8b9b3a02b 100644 (file)
@@ -63,6 +63,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
+       .preempt_count  = 1,                    \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index e21443d3ea1df4532562d613571f611c1b464a63..aa7a243862e1b714afbc0803de501b1ab2b13e69 100644 (file)
 
 #ifdef __KERNEL__
 
-/* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
-
 #define __syscall_return(type, res)                         \
 do {                                                        \
-       if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+       if ((unsigned long)(res) >= (unsigned long)(-4095)) {\
                errno = -(res);                              \
                res = -1;                                    \
        }                                                    \
index 1d934fb2c581c69ac6b6fe7906af5adc010a2f01..fed26616967a03979d0d6ea6e7c14d1d6a446f97 100644 (file)
@@ -1,9 +1,4 @@
 #ifndef __ASM_SH_HW_IRQ_H
 #define __ASM_SH_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-       /* Nothing to do */
-}
-
 #endif /* __ASM_SH_HW_IRQ_H */
index ae718d1f2d6cc90d416284453c5c01cdbfb652dd..ebb39089b0acf3be7f39841243447e3b94427a07 100644 (file)
@@ -11,6 +11,5 @@
  * Copyright (C) 2000, 2001  Paolo Alberelli
  *
  */
-static __inline__ void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { /* Nothing to do */ }
 
 #endif /* __ASM_SH64_HW_IRQ_H */
index 0e234e201bd6b587375e17cdb450daae6c47b22c..98a6c613589dcbe29205d0705ebf871b6f577b22 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef _ASM_SPARC64_TOPOLOGY_H
 #define _ASM_SPARC64_TOPOLOGY_H
 
+#include <asm/spitfire.h>
+#define smt_capable()  (tlb_type == hypervisor)
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_SPARC64_TOPOLOGY_H */
index 4ee38c0b6a64c0378c110cf7beb9d2aeeebfeae6..1cf84cf5f21af301596b5439289e1183071e2661 100644 (file)
@@ -4,7 +4,4 @@
 #include "asm/irq.h"
 #include "asm/archparam.h"
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{}
-
 #endif
index a8aab4342712a77a7e1f2ac49ae8b536fb270d40..043e94bb6bd8e51f0c94dd6473c92d00e4f86a99 100644 (file)
@@ -1,8 +1,4 @@
 #ifndef __V850_HW_IRQ_H__
 #define __V850_HW_IRQ_H__
 
-static inline void hw_resend_irq (struct hw_interrupt_type *h, unsigned int i)
-{
-}
-
 #endif /* __V850_HW_IRQ_H__ */
index 1b2ac55d3204e9ed6bbf3816fd82c50fa774f461..48a4a5364e85ddfc651c6716e0cf54deeac21df2 100644 (file)
@@ -124,18 +124,9 @@ asmlinkage void IRQ_NAME(nr); \
 __asm__( \
 "\n.p2align\n" \
 "IRQ" #nr "_interrupt:\n\t" \
-       "push $" #nr "-256 ; " \
+       "push $~(" #nr ") ; " \
        "jmp common_interrupt");
 
-#if defined(CONFIG_X86_IO_APIC)
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
-       if (IO_APIC_IRQ(i))
-               send_IPI_self(IO_APIC_VECTOR(i));
-}
-#else
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
-#endif
-
 #define platform_legacy_irq(irq)       ((irq) < 16)
 
 #endif
index c4e46e7fa7ba781f9c086bf2ace317d105d9ba56..6e7a2e976b04fc8bc8a98213522fabf5c623af02 100644 (file)
@@ -59,6 +59,8 @@ extern int __node_distance(int, int);
 #define topology_core_id(cpu)                  (cpu_data[cpu].cpu_core_id)
 #define topology_core_siblings(cpu)            (cpu_core_map[cpu])
 #define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
+#define mc_capable()                   (boot_cpu_data.x86_max_cores > 1)
+#define smt_capable()                  (smp_num_siblings > 1)
 #endif
 
 #include <asm-generic/topology.h>
index ccf436249eaaa90f66c6d746701bcce74f1f01ad..3ddbea759b2bc32be0839976e1d582b23f90fdfe 100644 (file)
@@ -11,8 +11,4 @@
 #ifndef _XTENSA_HW_IRQ_H
 #define _XTENSA_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-}
-
 #endif
index c35833824e118d8f9012542647f4f96ba95fb3d7..2ed2fd855133cba6d445a4babdb213e4eb4b2f75 100644 (file)
@@ -259,7 +259,7 @@ struct ac97_codec {
        int type;
        u32 model;
 
-       int modem:1;
+       unsigned int modem:1;
 
        struct ac97_ops *codec_ops;
 
index 90d6df1551ed06964d6f326866790531e7c04780..88b5dfd8ee125be2c3a025c7ea1e03183eaccbe4 100644 (file)
@@ -528,12 +528,18 @@ static inline void acpi_set_cstate_limit(unsigned int new_limit) { return; }
 
 #ifdef CONFIG_ACPI_NUMA
 int acpi_get_pxm(acpi_handle handle);
+int acpi_get_node(acpi_handle *handle);
 #else
 static inline int acpi_get_pxm(acpi_handle handle)
 {
        return 0;
 }
+static inline int acpi_get_node(acpi_handle *handle)
+{
+       return 0;
+}
 #endif
+extern int acpi_paddr_to_node(u64 start_addr, u64 size);
 
 extern int pnpacpi_disabled;
 
index fb7e9b7ccbe312bf29ecada865da27dc152fb51d..737e407d0cd11e7479e6d38d3cf48562eec4f596 100644 (file)
@@ -149,7 +149,6 @@ void create_empty_buffers(struct page *, unsigned long,
                        unsigned long b_state);
 void end_buffer_read_sync(struct buffer_head *bh, int uptodate);
 void end_buffer_write_sync(struct buffer_head *bh, int uptodate);
-void end_buffer_async_write(struct buffer_head *bh, int uptodate);
 
 /* Things to do with buffers at mapping->private_list */
 void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode);
@@ -214,6 +213,7 @@ int nobh_truncate_page(struct address_space *, loff_t);
 int nobh_writepage(struct page *page, get_block_t *get_block,
                         struct writeback_control *wbc);
 
+void buffer_init(void);
 
 /*
  * inline definitions
index 7b5c5df5cb69213ab7c2b5e45f1939c2b2ddc8b5..be512cc98791a31b85c0317e6f2b19e1e90c3631 100644 (file)
@@ -27,8 +27,8 @@ extern struct inode_operations coda_dir_inode_operations;
 extern struct inode_operations coda_file_inode_operations;
 extern struct inode_operations coda_ioctl_inode_operations;
 
-extern struct address_space_operations coda_file_aops;
-extern struct address_space_operations coda_symlink_aops;
+extern const struct address_space_operations coda_file_aops;
+extern const struct address_space_operations coda_symlink_aops;
 
 extern const struct file_operations coda_dir_operations;
 extern const struct file_operations coda_file_operations;
index 08d50c53aab401ef79c20e85213027d854e5d199..a3caf6866bae588885c43618d9965a6285f0913c 100644 (file)
@@ -31,17 +31,23 @@ struct cpu {
        struct sys_device sysdev;
 };
 
-extern int register_cpu(struct cpu *, int, struct node *);
+extern int register_cpu(struct cpu *cpu, int num);
 extern struct sys_device *get_cpu_sysdev(unsigned cpu);
 #ifdef CONFIG_HOTPLUG_CPU
-extern void unregister_cpu(struct cpu *, struct node *);
+extern void unregister_cpu(struct cpu *cpu);
 #endif
 struct notifier_block;
 
 #ifdef CONFIG_SMP
 /* Need to know about CPUs going up/down? */
 extern int register_cpu_notifier(struct notifier_block *nb);
+#ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu_notifier(struct notifier_block *nb);
+#else
+static inline void unregister_cpu_notifier(struct notifier_block *nb)
+{
+}
+#endif
 extern int current_in_cpu_hotplug(void);
 
 int cpu_up(unsigned int cpu);
@@ -73,6 +79,8 @@ extern int lock_cpu_hotplug_interruptible(void);
                { .notifier_call = fn, .priority = pri };       \
        register_cpu_notifier(&fn##_nb);                        \
 }
+#define register_hotcpu_notifier(nb)   register_cpu_notifier(nb)
+#define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb)
 int cpu_down(unsigned int cpu);
 #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
 #else
@@ -80,6 +88,8 @@ int cpu_down(unsigned int cpu);
 #define unlock_cpu_hotplug()   do { } while (0)
 #define lock_cpu_hotplug_interruptible() 0
 #define hotcpu_notifier(fn, pri)
+#define register_hotcpu_notifier(nb)
+#define unregister_hotcpu_notifier(nb)
 
 /* CPUs don't go offline once they're online w/o CONFIG_HOTPLUG_CPU */
 static inline int cpu_is_offline(int cpu) { return 0; }
index 78b236ca04f801ec188f1f78306ee44d10e02d95..272010a6078a9181dfb4a49a51f3820d47ee1b01 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef DMAENGINE_H
 #define DMAENGINE_H
-#include <linux/config.h>
+
 #ifdef CONFIG_DMA_ENGINE
 
 #include <linux/device.h>
index fbfa6b52e2fb0007a3ec29b7a003fc3981981d19..278ef4495819509748a2e1b3c53651202bbcf1f9 100644 (file)
@@ -38,7 +38,7 @@ struct statfs;
 
 extern struct inode_operations efs_dir_inode_operations;
 extern const struct file_operations efs_dir_operations;
-extern struct address_space_operations efs_symlink_aops;
+extern const struct address_space_operations efs_symlink_aops;
 
 extern void efs_read_inode(struct inode *);
 extern efs_block_t efs_map_block(struct inode *, efs_block_t);
index 2d8b348c11923ad57d803982040c3563bf612e52..e04a5cfe874f978c91efbaa3bfe5ac71d259aefe 100644 (file)
@@ -392,7 +392,7 @@ struct address_space {
        unsigned int            truncate_count; /* Cover race condition with truncate */
        unsigned long           nrpages;        /* number of total pages */
        pgoff_t                 writeback_index;/* writeback starts here */
-       struct address_space_operations *a_ops; /* methods */
+       const struct address_space_operations *a_ops;   /* methods */
        unsigned long           flags;          /* error bits/gfp mask */
        struct backing_dev_info *backing_dev_info; /* device readahead, etc */
        spinlock_t              private_lock;   /* for use by the address_space */
@@ -1405,7 +1405,7 @@ extern void bd_forget(struct inode *inode);
 extern void bdput(struct block_device *);
 extern struct block_device *open_by_devnum(dev_t, unsigned);
 extern const struct file_operations def_blk_fops;
-extern struct address_space_operations def_blk_aops;
+extern const struct address_space_operations def_blk_aops;
 extern const struct file_operations def_chr_fops;
 extern const struct file_operations bad_sock_fops;
 extern const struct file_operations def_fifo_fops;
index 966a5b3da439b40232c269f44026733db5a76244..34c3a215f2cd9affe3583451063a09887ee0669c 100644 (file)
@@ -12,6 +12,9 @@
 #define FUTEX_REQUEUE          3
 #define FUTEX_CMP_REQUEUE      4
 #define FUTEX_WAKE_OP          5
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
 
 /*
  * Support for robust futexes: the kernel cleans up held futexes at
@@ -90,18 +93,21 @@ struct robust_list_head {
  */
 #define ROBUST_LIST_LIMIT      2048
 
-long do_futex(unsigned long uaddr, int op, int val,
-               unsigned long timeout, unsigned long uaddr2, int val2,
-               int val3);
+long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+             u32 __user *uaddr2, u32 val2, u32 val3);
 
 extern int handle_futex_death(u32 __user *uaddr, struct task_struct *curr);
 
 #ifdef CONFIG_FUTEX
 extern void exit_robust_list(struct task_struct *curr);
+extern void exit_pi_state_list(struct task_struct *curr);
 #else
 static inline void exit_robust_list(struct task_struct *curr)
 {
 }
+static inline void exit_pi_state_list(struct task_struct *curr)
+{
+}
 #endif
 
 #define FUTEX_OP_SET           0       /* *(int *)UADDR2 = OPARG; */
index ef7bef207f48d3ae0b458c063e788eaf69f803d3..0c100168c0cf2e20f5dc53ce83290545b2961876 100644 (file)
@@ -793,6 +793,7 @@ typedef struct hwif_s {
        unsigned        auto_poll  : 1; /* supports nop auto-poll */
        unsigned        sg_mapped  : 1; /* sg_table and sg_nents are ready */
        unsigned        no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */
+       unsigned        err_stops_fifo : 1; /* 1=data FIFO is cleared by an error */
 
        struct device   gendev;
        struct completion gendev_rel_comp; /* To deal with device release() */
index e127ef7e8da834dd3300ab875349c530b8a5e60d..3a256957fb56a7f05453dd3ea60cb075ca086b01 100644 (file)
@@ -87,6 +87,7 @@ extern struct group_info init_groups;
        .lock_depth     = -1,                                           \
        .prio           = MAX_PRIO-20,                                  \
        .static_prio    = MAX_PRIO-20,                                  \
+       .normal_prio    = MAX_PRIO-20,                                  \
        .policy         = SCHED_NORMAL,                                 \
        .cpus_allowed   = CPU_MASK_ALL,                                 \
        .mm             = NULL,                                         \
@@ -122,6 +123,8 @@ extern struct group_info init_groups;
        .journal_info   = NULL,                                         \
        .cpu_timers     = INIT_CPU_TIMERS(tsk.cpu_timers),              \
        .fs_excl        = ATOMIC_INIT(0),                               \
+       .pi_lock        = SPIN_LOCK_UNLOCKED,                           \
+       INIT_RT_MUTEXES(tsk)                                            \
 }
 
 
index 70741e170114e5f9328553fa9b8eadc1a60fc7ab..db2a63a11633cb9ebdfeb21dc9436b1a23bd92ea 100644 (file)
@@ -36,6 +36,20 @@ extern void free_irq(unsigned int, void *);
 extern void disable_irq_nosync(unsigned int irq);
 extern void disable_irq(unsigned int irq);
 extern void enable_irq(unsigned int irq);
+
+/* IRQ wakeup (PM) control: */
+extern int set_irq_wake(unsigned int irq, unsigned int on);
+
+static inline int enable_irq_wake(unsigned int irq)
+{
+       return set_irq_wake(irq, 1);
+}
+
+static inline int disable_irq_wake(unsigned int irq)
+{
+       return set_irq_wake(irq, 0);
+}
+
 #endif
 
 #ifndef __ARCH_SET_SOFTIRQ_PENDING
index cd6bd001ba4edbc68dfc5b52f08ef3bb832c785e..87a9fc039b4789e6d68e65510cb06bafaf18c801 100644 (file)
@@ -9,13 +9,15 @@
 #define _LINUX_IOPORT_H
 
 #include <linux/compiler.h>
+#include <linux/types.h>
 /*
  * Resources are tree-like, allowing
  * nesting etc..
  */
 struct resource {
+       resource_size_t start;
+       resource_size_t end;
        const char *name;
-       unsigned long start, end;
        unsigned long flags;
        struct resource *parent, *sibling, *child;
 };
@@ -96,31 +98,37 @@ extern struct resource * ____request_resource(struct resource *root, struct reso
 extern int release_resource(struct resource *new);
 extern __deprecated_for_modules int insert_resource(struct resource *parent, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
-                            unsigned long size,
-                            unsigned long min, unsigned long max,
-                            unsigned long align,
+                            resource_size_t size, resource_size_t min,
+                            resource_size_t max, resource_size_t align,
                             void (*alignf)(void *, struct resource *,
-                                           unsigned long, unsigned long),
+                                           resource_size_t, resource_size_t),
                             void *alignf_data);
-int adjust_resource(struct resource *res, unsigned long start,
-                   unsigned long size);
+int adjust_resource(struct resource *res, resource_size_t start,
+                   resource_size_t size);
+
+/* get registered SYSTEM_RAM resources in specified area */
+extern int find_next_system_ram(struct resource *res);
 
 /* Convenience shorthand with allocation */
 #define request_region(start,n,name)   __request_region(&ioport_resource, (start), (n), (name))
 #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
 #define rename_region(region, newname) do { (region)->name = (newname); } while (0)
 
-extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name);
+extern struct resource * __request_region(struct resource *,
+                                       resource_size_t start,
+                                       resource_size_t n, const char *name);
 
 /* Compatibility cruft */
 #define release_region(start,n)        __release_region(&ioport_resource, (start), (n))
 #define check_mem_region(start,n)      __check_region(&iomem_resource, (start), (n))
 #define release_mem_region(start,n)    __release_region(&iomem_resource, (start), (n))
 
-extern int __check_region(struct resource *, unsigned long, unsigned long);
-extern void __release_region(struct resource *, unsigned long, unsigned long);
+extern int __check_region(struct resource *, resource_size_t, resource_size_t);
+extern void __release_region(struct resource *, resource_size_t,
+                               resource_size_t);
 
-static inline int __deprecated check_region(unsigned long s, unsigned long n)
+static inline int __deprecated check_region(resource_size_t s,
+                                               resource_size_t n)
 {
        return __check_region(&ioport_resource, s, n);
 }
index 5653b2f23b6a6fdf94f0e1d15ae8cb7436638db0..d09fbeabf1dc976539384f1889299bfc2e69383e 100644 (file)
@@ -210,11 +210,7 @@ struct kernel_ipmi_msg
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/device.h>
-
-#ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
-extern struct proc_dir_entry *proc_ipmi_root;
-#endif /* CONFIG_PROC_FS */
 
 /* Opaque type for a IPMI message user.  One of these is needed to
    send and receive messages. */
index 676e00dfb21a623c6922436646cc4e85be8d7656..0832149cdb180df6e8ba75e1f7a951c438b03546 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __irq_h
-#define __irq_h
+#ifndef _LINUX_IRQ_H
+#define _LINUX_IRQ_H
 
 /*
  * Please do not include this file in generic code.  There is currently
@@ -11,7 +11,7 @@
 
 #include <linux/smp.h>
 
-#if !defined(CONFIG_S390)
+#ifndef CONFIG_S390
 
 #include <linux/linkage.h>
 #include <linux/cache.h>
 #define IRQ_WAITING    32      /* IRQ not yet seen - for autodetection */
 #define IRQ_LEVEL      64      /* IRQ level triggered */
 #define IRQ_MASKED     128     /* IRQ masked - shouldn't be seen again */
-#if defined(ARCH_HAS_IRQ_PER_CPU)
+#ifdef CONFIG_IRQ_PER_CPU
 # define IRQ_PER_CPU   256     /* IRQ is per CPU */
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
 #else
 # define CHECK_IRQ_PER_CPU(var) 0
 #endif
 
+#define IRQ_NOPROBE    512     /* IRQ is not valid for probing */
+#define IRQ_NOREQUEST  1024    /* IRQ cannot be requested */
+#define IRQ_NOAUTOEN   2048    /* IRQ will not be enabled on request irq */
+#define IRQ_DELAYED_DISABLE \
+                       4096    /* IRQ disable (masking) happens delayed. */
+
 /*
- * Interrupt controller descriptor. This is all we need
- * to describe about the low-level hardware. 
+ * IRQ types, see also include/linux/interrupt.h
  */
-struct hw_interrupt_type {
-       const char * typename;
-       unsigned int (*startup)(unsigned int irq);
-       void (*shutdown)(unsigned int irq);
-       void (*enable)(unsigned int irq);
-       void (*disable)(unsigned int irq);
-       void (*ack)(unsigned int irq);
-       void (*end)(unsigned int irq);
-       void (*set_affinity)(unsigned int irq, cpumask_t dest);
+#define IRQ_TYPE_NONE          0x0000          /* Default, unspecified type */
+#define IRQ_TYPE_EDGE_RISING   0x0001          /* Edge rising type */
+#define IRQ_TYPE_EDGE_FALLING  0x0002          /* Edge falling type */
+#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
+#define IRQ_TYPE_LEVEL_HIGH    0x0004          /* Level high type */
+#define IRQ_TYPE_LEVEL_LOW     0x0008          /* Level low type */
+#define IRQ_TYPE_SENSE_MASK    0x000f          /* Mask of the above */
+#define IRQ_TYPE_SIMPLE                0x0010          /* Simple type */
+#define IRQ_TYPE_PERCPU                0x0020          /* Per CPU type */
+#define IRQ_TYPE_PROBE         0x0040          /* Probing in progress */
+
+struct proc_dir_entry;
+
+/**
+ * struct irq_chip - hardware interrupt chip descriptor
+ *
+ * @name:              name for /proc/interrupts
+ * @startup:           start up the interrupt (defaults to ->enable if NULL)
+ * @shutdown:          shut down the interrupt (defaults to ->disable if NULL)
+ * @enable:            enable the interrupt (defaults to chip->unmask if NULL)
+ * @disable:           disable the interrupt (defaults to chip->mask if NULL)
+ * @ack:               start of a new interrupt
+ * @mask:              mask an interrupt source
+ * @mask_ack:          ack and mask an interrupt source
+ * @unmask:            unmask an interrupt source
+ * @eoi:               end of interrupt - chip level
+ * @end:               end of interrupt - flow level
+ * @set_affinity:      set the CPU affinity on SMP machines
+ * @retrigger:         resend an IRQ to the CPU
+ * @set_type:          set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
+ * @set_wake:          enable/disable power-management wake-on of an IRQ
+ *
+ * @release:           release function solely used by UML
+ * @typename:          obsoleted by name, kept as migration helper
+ */
+struct irq_chip {
+       const char      *name;
+       unsigned int    (*startup)(unsigned int irq);
+       void            (*shutdown)(unsigned int irq);
+       void            (*enable)(unsigned int irq);
+       void            (*disable)(unsigned int irq);
+
+       void            (*ack)(unsigned int irq);
+       void            (*mask)(unsigned int irq);
+       void            (*mask_ack)(unsigned int irq);
+       void            (*unmask)(unsigned int irq);
+       void            (*eoi)(unsigned int irq);
+
+       void            (*end)(unsigned int irq);
+       void            (*set_affinity)(unsigned int irq, cpumask_t dest);
+       int             (*retrigger)(unsigned int irq);
+       int             (*set_type)(unsigned int irq, unsigned int flow_type);
+       int             (*set_wake)(unsigned int irq, unsigned int on);
+
        /* Currently used only by UML, might disappear one day.*/
 #ifdef CONFIG_IRQ_RELEASE_METHOD
-       void (*release)(unsigned int irq, void *dev_id);
+       void            (*release)(unsigned int irq, void *dev_id);
 #endif
+       /*
+        * For compatibility, ->typename is copied into ->name.
+        * Will disappear.
+        */
+       const char      *typename;
 };
 
-typedef struct hw_interrupt_type  hw_irq_controller;
-
-/*
- * This is the "IRQ descriptor", which contains various information
- * about the irq, including what kind of hardware handling it has,
- * whether it is disabled etc etc.
+/**
+ * struct irq_desc - interrupt descriptor
+ *
+ * @handle_irq:                highlevel irq-events handler [if NULL, __do_IRQ()]
+ * @chip:              low level interrupt hardware access
+ * @handler_data:      per-IRQ data for the irq_chip methods
+ * @chip_data:         platform-specific per-chip private data for the chip
+ *                     methods, to allow shared chip implementations
+ * @action:            the irq action chain
+ * @status:            status information
+ * @depth:             disable-depth, for nested irq_disable() calls
+ * @irq_count:         stats field to detect stalled irqs
+ * @irqs_unhandled:    stats field for spurious unhandled interrupts
+ * @lock:              locking for SMP
+ * @affinity:          IRQ affinity on SMP
+ * @cpu:               cpu index useful for balancing
+ * @pending_mask:      pending rebalanced interrupts
+ * @move_irq:          need to re-target IRQ destination
+ * @dir:               /proc/irq/ procfs entry
+ * @affinity_entry:    /proc/irq/smp_affinity procfs entry on SMP
  *
  * Pad this out to 32 bytes for cache and indexing reasons.
  */
-typedef struct irq_desc {
-       hw_irq_controller *handler;
-       void *handler_data;
-       struct irqaction *action;       /* IRQ action list */
-       unsigned int status;            /* IRQ status */
-       unsigned int depth;             /* nested irq disables */
-       unsigned int irq_count;         /* For detecting broken interrupts */
-       unsigned int irqs_unhandled;
-       spinlock_t lock;
-#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
-       unsigned int move_irq;          /* Flag need to re-target intr dest*/
+struct irq_desc {
+       void fastcall           (*handle_irq)(unsigned int irq,
+                                             struct irq_desc *desc,
+                                             struct pt_regs *regs);
+       struct irq_chip         *chip;
+       void                    *handler_data;
+       void                    *chip_data;
+       struct irqaction        *action;        /* IRQ action list */
+       unsigned int            status;         /* IRQ status */
+
+       unsigned int            depth;          /* nested irq disables */
+       unsigned int            irq_count;      /* For detecting broken IRQs */
+       unsigned int            irqs_unhandled;
+       spinlock_t              lock;
+#ifdef CONFIG_SMP
+       cpumask_t               affinity;
+       unsigned int            cpu;
+#endif
+#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
+       cpumask_t               pending_mask;
+       unsigned int            move_irq;       /* need to re-target IRQ dest */
 #endif
-} ____cacheline_aligned irq_desc_t;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *dir;
+#endif
+} ____cacheline_aligned;
 
-extern irq_desc_t irq_desc [NR_IRQS];
+extern struct irq_desc irq_desc[NR_IRQS];
 
-/* Return a pointer to the irq descriptor for IRQ.  */
-static inline irq_desc_t *
-irq_descp (int irq)
-{
-       return irq_desc + irq;
-}
+/*
+ * Migration helpers for obsolete names, they will go away:
+ */
+#define hw_interrupt_type      irq_chip
+typedef struct irq_chip                hw_irq_controller;
+#define no_irq_type            no_irq_chip
+typedef struct irq_desc                irq_desc_t;
 
-#include <asm/hw_irq.h> /* the arch dependent stuff */
+/*
+ * Pick up the arch-dependent methods:
+ */
+#include <asm/hw_irq.h>
 
-extern int setup_irq(unsigned int irq, struct irqaction * new);
+extern int setup_irq(unsigned int irq, struct irqaction *new);
 
 #ifdef CONFIG_GENERIC_HARDIRQS
-extern cpumask_t irq_affinity[NR_IRQS];
 
 #ifdef CONFIG_SMP
 static inline void set_native_irq_info(int irq, cpumask_t mask)
 {
-       irq_affinity[irq] = mask;
+       irq_desc[irq].affinity = mask;
 }
 #else
 static inline void set_native_irq_info(int irq, cpumask_t mask)
@@ -111,8 +196,7 @@ static inline void set_native_irq_info(int irq, cpumask_t mask)
 
 #ifdef CONFIG_SMP
 
-#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
-extern cpumask_t pending_irq_cpumask[NR_IRQS];
+#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
 
 void set_pending_irq(unsigned int irq, cpumask_t mask);
 void move_native_irq(int irq);
@@ -133,7 +217,7 @@ static inline void set_irq_info(int irq, cpumask_t mask)
 {
 }
 
-#else // CONFIG_PCI_MSI
+#else /* CONFIG_PCI_MSI */
 
 static inline void move_irq(int irq)
 {
@@ -144,26 +228,36 @@ static inline void set_irq_info(int irq, cpumask_t mask)
 {
        set_native_irq_info(irq, mask);
 }
-#endif // CONFIG_PCI_MSI
 
-#else  // CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE
+#endif /* CONFIG_PCI_MSI */
+
+#else /* CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE */
+
+static inline void move_irq(int irq)
+{
+}
+
+static inline void move_native_irq(int irq)
+{
+}
+
+static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
+{
+}
 
-#define move_irq(x)
-#define move_native_irq(x)
-#define set_pending_irq(x,y)
 static inline void set_irq_info(int irq, cpumask_t mask)
 {
        set_native_irq_info(irq, mask);
 }
 
-#endif // CONFIG_GENERIC_PENDING_IRQ
+#endif /* CONFIG_GENERIC_PENDING_IRQ */
 
-#else // CONFIG_SMP
+#else /* CONFIG_SMP */
 
 #define move_irq(x)
 #define move_native_irq(x)
 
-#endif // CONFIG_SMP
+#endif /* CONFIG_SMP */
 
 #ifdef CONFIG_IRQBALANCE
 extern void set_balance_irq_affinity(unsigned int irq, cpumask_t mask);
@@ -173,32 +267,138 @@ static inline void set_balance_irq_affinity(unsigned int irq, cpumask_t mask)
 }
 #endif
 
+#ifdef CONFIG_AUTO_IRQ_AFFINITY
+extern int select_smp_affinity(unsigned int irq);
+#else
+static inline int select_smp_affinity(unsigned int irq)
+{
+       return 1;
+}
+#endif
+
 extern int no_irq_affinity;
-extern int noirqdebug_setup(char *str);
 
-extern fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
-                                       struct irqaction *action);
+/* Handle irq action chains: */
+extern int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+                           struct irqaction *action);
+
+/*
+ * Built-in IRQ handlers for various IRQ types,
+ * callable via desc->chip->handle_irq()
+ */
+extern void fastcall
+handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+extern void fastcall
+handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
+                        struct pt_regs *regs);
+extern void fastcall
+handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+extern void fastcall
+handle_simple_irq(unsigned int irq, struct irq_desc *desc,
+                 struct pt_regs *regs);
+extern void fastcall
+handle_percpu_irq(unsigned int irq, struct irq_desc *desc,
+                 struct pt_regs *regs);
+extern void fastcall
+handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+
+/*
+ * Get a descriptive string for the highlevel handler, for
+ * /proc/interrupts output:
+ */
+extern const char *
+handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                       struct pt_regs *));
+
+/*
+ * Monolithic do_IRQ implementation.
+ * (is an explicit fastcall, because i386 4KSTACKS calls it from assembly)
+ */
 extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
-extern void note_interrupt(unsigned int irq, irq_desc_t *desc,
-                                       int action_ret, struct pt_regs *regs);
-extern int can_request_irq(unsigned int irq, unsigned long irqflags);
 
+/*
+ * Architectures call this to let the generic IRQ layer
+ * handle an interrupt. If the descriptor is attached to an
+ * irqchip-style controller then we call the ->handle_irq() handler,
+ * and it calls __do_IRQ() if it's attached to an irqtype-style controller.
+ */
+static inline void generic_handle_irq(unsigned int irq, struct pt_regs *regs)
+{
+       struct irq_desc *desc = irq_desc + irq;
+
+       if (likely(desc->handle_irq))
+               desc->handle_irq(irq, desc, regs);
+       else
+               __do_IRQ(irq, regs);
+}
+
+/* Handling of unhandled and spurious interrupts: */
+extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
+                          int action_ret, struct pt_regs *regs);
+
+/* Resending of interrupts :*/
+void check_irq_resend(struct irq_desc *desc, unsigned int irq);
+
+/* Initialize /proc/irq/ */
 extern void init_irq_proc(void);
 
-#ifdef CONFIG_AUTO_IRQ_AFFINITY
-extern int select_smp_affinity(unsigned int irq);
-#else
-static inline int
-select_smp_affinity(unsigned int irq)
+/* Enable/disable irq debugging output: */
+extern int noirqdebug_setup(char *str);
+
+/* Checks whether the interrupt can be requested by request_irq(): */
+extern int can_request_irq(unsigned int irq, unsigned long irqflags);
+
+/* Dummy irq-chip implementation: */
+extern struct irq_chip no_irq_chip;
+
+extern void
+set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
+                        void fastcall (*handle)(unsigned int,
+                                                struct irq_desc *,
+                                                struct pt_regs *));
+extern void
+__set_irq_handler(unsigned int irq,
+                 void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                         struct pt_regs *),
+                 int is_chained);
+
+/*
+ * Set a highlevel flow handler for a given IRQ:
+ */
+static inline void
+set_irq_handler(unsigned int irq,
+               void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                       struct pt_regs *))
 {
-       return 1;
+       __set_irq_handler(irq, handle, 0);
 }
-#endif
 
-#endif
+/*
+ * Set a highlevel chained flow handler for a given IRQ.
+ * (a chained handler is automatically enabled and set to
+ *  IRQ_NOREQUEST and IRQ_NOPROBE)
+ */
+static inline void
+set_irq_chained_handler(unsigned int irq,
+                       void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                               struct pt_regs *))
+{
+       __set_irq_handler(irq, handle, 1);
+}
 
-extern hw_irq_controller no_irq_type;  /* needed in every arch ? */
+/* Set/get chip/data for an IRQ: */
 
-#endif
+extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
+extern int set_irq_data(unsigned int irq, void *data);
+extern int set_irq_chip_data(unsigned int irq, void *data);
+extern int set_irq_type(unsigned int irq, unsigned int type);
+
+#define get_irq_chip(irq)      (irq_desc[irq].chip)
+#define get_irq_chip_data(irq) (irq_desc[irq].chip_data)
+#define get_irq_data(irq)      (irq_desc[irq].handler_data)
+
+#endif /* CONFIG_GENERIC_HARDIRQS */
+
+#endif /* !CONFIG_S390 */
 
-#endif /* __irq_h */
+#endif /* _LINUX_IRQ_H */
diff --git a/include/linux/isdn/tpam.h b/include/linux/isdn/tpam.h
deleted file mode 100644 (file)
index d18dd0d..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* $Id: tpam.h,v 1.1.2.1 2001/06/08 08:23:46 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * 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 _TPAM_H_
-#define _TPAM_H_
-
-#include <linux/types.h>
-
-/* IOCTL commands */
-#define TPAM_CMD_DSPLOAD       0x0001
-#define TPAM_CMD_DSPSAVE       0x0002
-#define TPAM_CMD_DSPRUN                0x0003
-#define TPAM_CMD_LOOPMODEON    0x0004
-#define TPAM_CMD_LOOPMODEOFF   0x0005
-
-/* addresses of debug information zones on board */
-#define TPAM_TRAPAUDIT_REGISTER                0x005493e4
-#define TPAM_NCOAUDIT_REGISTER         0x00500000
-#define TPAM_MSGAUDIT_REGISTER         0x008E30F0
-
-/* length of debug information zones on board */
-#define TPAM_TRAPAUDIT_LENGTH          10000
-#define TPAM_NCOAUDIT_LENGTH           300000
-#define TPAM_NCOAUDIT_COUNT            30
-#define TPAM_MSGAUDIT_LENGTH           60000
-
-/* IOCTL load/save parameter */
-typedef struct tpam_dsp_ioctl {
-       __u32 address;  /* address to load/save data */
-       __u32 data_len; /* size of data to be loaded/saved */
-       __u8 data[0];   /* data */
-} tpam_dsp_ioctl;
-
-#endif /* _TPAM_H_ */
index c6f70660b3716e39736153151cc5ef6c1b82fd70..c9c760700bc3415046d6243a0b7143d1ec173b5c 100644 (file)
@@ -186,6 +186,7 @@ struct jffs2_raw_xref
        jint32_t hdr_crc;
        jint32_t ino;           /* inode number */
        jint32_t xid;           /* XATTR identifier number */
+       jint32_t xseqno;        /* xref sequencial number */
        jint32_t node_crc;
 } __attribute__((packed));
 
index 4eb851ece080d0682f4ada0b9fe24aad22c3cd19..efe0ee4cc80baee508567f08c72b3f7d03277e43 100644 (file)
@@ -155,10 +155,8 @@ static inline void con_schedule_flip(struct tty_struct *t)
 {
        unsigned long flags;
        spin_lock_irqsave(&t->buf.lock, flags);
-       if (t->buf.tail != NULL) {
-               t->buf.tail->active = 0;
+       if (t->buf.tail != NULL)
                t->buf.tail->commit = t->buf.tail->used;
-       }
        spin_unlock_irqrestore(&t->buf.lock, flags);
        schedule_work(&t->buf.work);
 }
index e693e729bc92141b77440c217599e70860a81934..169f05e4863ed140058674a1e5a1fcab5f06f766 100644 (file)
@@ -177,7 +177,8 @@ struct key {
 /*
  * kernel managed key type definition
  */
-typedef int (*request_key_actor_t)(struct key *key, struct key *authkey, const char *op);
+typedef int (*request_key_actor_t)(struct key *key, struct key *authkey,
+                                  const char *op, void *aux);
 
 struct key_type {
        /* name of the type */
@@ -285,6 +286,11 @@ extern struct key *request_key(struct key_type *type,
                               const char *description,
                               const char *callout_info);
 
+extern struct key *request_key_with_auxdata(struct key_type *type,
+                                           const char *description,
+                                           const char *callout_info,
+                                           void *aux);
+
 extern int key_validate(struct key *key);
 
 extern key_ref_t key_create_or_update(key_ref_t keyring,
index 20b1cf527c609a575ff468b91f7a4106a8464a8b..f4284bf897585727ee8b2a6cacafd6e228d28b96 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <asm/scatterlist.h>
 #include <asm/io.h>
 #include <linux/ata.h>
 #include <linux/workqueue.h>
@@ -887,6 +888,9 @@ static inline unsigned int ata_tag_internal(unsigned int tag)
        return tag == ATA_MAX_QUEUE - 1;
 }
 
+/*
+ * device helpers
+ */
 static inline unsigned int ata_class_enabled(unsigned int class)
 {
        return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
@@ -917,6 +921,17 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
        return ata_class_absent(dev->class);
 }
 
+/*
+ * port helpers
+ */
+static inline int ata_port_max_devices(const struct ata_port *ap)
+{
+       if (ap->flags & ATA_FLAG_SLAVE_POSS)
+               return 2;
+       return 1;
+}
+
+
 static inline u8 ata_chk_status(struct ata_port *ap)
 {
        return ap->ops->check_status(ap);
index 37ca31b21bb7a29cda46861f5e3d97a25ed83622..6b74adf5297f644f82531a5fbcbc55b5892d13f7 100644 (file)
@@ -4,17 +4,10 @@
 #ifdef __KERNEL__
 
 #include <linux/stddef.h>
+#include <linux/poison.h>
 #include <linux/prefetch.h>
 #include <asm/system.h>
 
-/*
- * These are non-NULL pointers that will result in page faults
- * under normal circumstances, used to verify that nobody uses
- * non-initialized list entries.
- */
-#define LIST_POISON1  ((void *) 0x00100100)
-#define LIST_POISON2  ((void *) 0x00200200)
-
 /*
  * Simple doubly linked list implementation.
  *
index 911206386171ccedc51397d9e36a7c424de9642c..218501cfaeb9255ed62ca9fbf2a197cbb6993f53 100644 (file)
@@ -63,6 +63,76 @@ extern int online_pages(unsigned long, unsigned long);
 /* reasonably generic interface to expand the physical pages in a zone  */
 extern int __add_pages(struct zone *zone, unsigned long start_pfn,
        unsigned long nr_pages);
+
+#ifdef CONFIG_NUMA
+extern int memory_add_physaddr_to_nid(u64 start);
+#else
+static inline int memory_add_physaddr_to_nid(u64 start)
+{
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_HAVE_ARCH_NODEDATA_EXTENSION
+/*
+ * For supporting node-hotadd, we have to allocate a new pgdat.
+ *
+ * If an arch has generic style NODE_DATA(),
+ * node_data[nid] = kzalloc() works well. But it depends on the architecture.
+ *
+ * In general, generic_alloc_nodedata() is used.
+ * Now, arch_free_nodedata() is just defined for error path of node_hot_add.
+ *
+ */
+extern pg_data_t *arch_alloc_nodedata(int nid);
+extern void arch_free_nodedata(pg_data_t *pgdat);
+extern void arch_refresh_nodedata(int nid, pg_data_t *pgdat);
+
+#else /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */
+
+#define arch_alloc_nodedata(nid)       generic_alloc_nodedata(nid)
+#define arch_free_nodedata(pgdat)      generic_free_nodedata(pgdat)
+
+#ifdef CONFIG_NUMA
+/*
+ * If ARCH_HAS_NODEDATA_EXTENSION=n, this func is used to allocate pgdat.
+ * XXX: kmalloc_node() can't work well to get new node's memory at this time.
+ *     Because, pgdat for the new node is not allocated/initialized yet itself.
+ *     To use new node's memory, more consideration will be necessary.
+ */
+#define generic_alloc_nodedata(nid)                            \
+({                                                             \
+       kzalloc(sizeof(pg_data_t), GFP_KERNEL);                 \
+})
+/*
+ * This definition is just for error path in node hotadd.
+ * For node hotremove, we have to replace this.
+ */
+#define generic_free_nodedata(pgdat)   kfree(pgdat)
+
+extern pg_data_t *node_data[];
+static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
+{
+       node_data[nid] = pgdat;
+}
+
+#else /* !CONFIG_NUMA */
+
+/* never called */
+static inline pg_data_t *generic_alloc_nodedata(int nid)
+{
+       BUG();
+       return NULL;
+}
+static inline void generic_free_nodedata(pg_data_t *pgdat)
+{
+}
+static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
+{
+}
+#endif /* CONFIG_NUMA */
+#endif /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */
+
 #else /* ! CONFIG_MEMORY_HOTPLUG */
 /*
  * Stub functions for when hotplug is off
@@ -99,7 +169,8 @@ static inline int __remove_pages(struct zone *zone, unsigned long start_pfn,
        return -ENOSYS;
 }
 
-extern int add_memory(u64 start, u64 size);
+extern int add_memory(int nid, u64 start, u64 size);
+extern int arch_add_memory(int nid, u64 start, u64 size);
 extern int remove_memory(u64 start, u64 size);
 
 #endif /* __LINUX_MEMORY_HOTPLUG_H */
index a929ea197e4844da5d11fc9f43da506138b276f7..c41a1299b8cf354cc8b9d9677f328aa4bc8b8533 100644 (file)
@@ -1030,13 +1030,20 @@ static inline void vm_stat_account(struct mm_struct *mm,
 }
 #endif /* CONFIG_PROC_FS */
 
+static inline void
+debug_check_no_locks_freed(const void *from, unsigned long len)
+{
+       mutex_debug_check_no_locks_freed(from, len);
+       rt_mutex_debug_check_no_locks_freed(from, len);
+}
+
 #ifndef CONFIG_DEBUG_PAGEALLOC
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable)
 {
        if (!PageHighMem(page) && !enable)
-               mutex_debug_check_no_locks_freed(page_address(page),
-                                                numpages * PAGE_SIZE);
+               debug_check_no_locks_freed(page_address(page),
+                                          numpages * PAGE_SIZE);
 }
 #endif
 
@@ -1065,5 +1072,7 @@ void drop_slab(void);
 extern int randomize_va_space;
 #endif
 
+const char *arch_vma_name(struct vm_area_struct *vma);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
index 9ebbb74b7b729ee8fe17a8ed783c1a3327944fb8..9e9dc7c24d9589e50e84913c76f46ac9ec3b2ae5 100644 (file)
@@ -203,6 +203,15 @@ void *__symbol_get_gpl(const char *symbol);
 #define EXPORT_SYMBOL_GPL_FUTURE(sym)                          \
        __EXPORT_SYMBOL(sym, "_gpl_future")
 
+
+#ifdef CONFIG_UNUSED_SYMBOLS
+#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
+#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
+#else
+#define EXPORT_UNUSED_SYMBOL(sym)
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)
+#endif
+
 #endif
 
 struct module_ref
@@ -261,6 +270,15 @@ struct module
        unsigned int num_gpl_syms;
        const unsigned long *gpl_crcs;
 
+       /* unused exported symbols. */
+       const struct kernel_symbol *unused_syms;
+       unsigned int num_unused_syms;
+       const unsigned long *unused_crcs;
+       /* GPL-only, unused exported symbols. */
+       const struct kernel_symbol *unused_gpl_syms;
+       unsigned int num_unused_gpl_syms;
+       const unsigned long *unused_gpl_crcs;
+
        /* symbols that will be GPL-only in the near future. */
        const struct kernel_symbol *gpl_future_syms;
        unsigned int num_gpl_future_syms;
@@ -456,6 +474,8 @@ void module_remove_driver(struct device_driver *);
 #define EXPORT_SYMBOL(sym)
 #define EXPORT_SYMBOL_GPL(sym)
 #define EXPORT_SYMBOL_GPL_FUTURE(sym)
+#define EXPORT_UNUSED_SYMBOL(sym)
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)
 
 /* Given an address, look for it in the exception tables. */
 static inline const struct exception_table_entry *
index 0a1740b2532ebfe417d9adbdc8703d39d24cca1e..d90b1bb3756305d71303de5e726636fa9f3cdfe1 100644 (file)
@@ -335,7 +335,7 @@ extern struct inode_operations nfs_file_inode_operations;
 extern struct inode_operations nfs3_file_inode_operations;
 #endif /* CONFIG_NFS_V3 */
 extern const struct file_operations nfs_file_operations;
-extern struct address_space_operations nfs_file_aops;
+extern const struct address_space_operations nfs_file_aops;
 
 static inline struct rpc_cred *nfs_file_cred(struct file *file)
 {
index 254dc3de650b81e5cce4821f8101dad72005f996..81dcec84cd8f00290037cb29c7f7e0960b51b895 100644 (file)
@@ -26,8 +26,25 @@ struct node {
        struct sys_device       sysdev;
 };
 
+extern struct node node_devices[];
+
 extern int register_node(struct node *, int, struct node *);
 extern void unregister_node(struct node *node);
+extern int register_one_node(int nid);
+extern void unregister_one_node(int nid);
+#ifdef CONFIG_NUMA
+extern int register_cpu_under_node(unsigned int cpu, unsigned int nid);
+extern int unregister_cpu_under_node(unsigned int cpu, unsigned int nid);
+#else
+static inline int register_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+       return 0;
+}
+static inline int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+       return 0;
+}
+#endif
 
 #define to_node(sys_device) container_of(sys_device, struct node, sysdev)
 
diff --git a/include/linux/nsc_gpio.h b/include/linux/nsc_gpio.h
new file mode 100644 (file)
index 0000000..135742c
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+   nsc_gpio.c
+
+   National Semiconductor GPIO common access methods.
+
+   struct nsc_gpio_ops abstracts the low-level access
+   operations for the GPIO units on 2 NSC chip families; the GEODE
+   integrated CPU, and the PC-8736[03456] integrated PC-peripheral
+   chips.
+
+   The GPIO units on these chips have the same pin architecture, but
+   the access methods differ.  Thus, scx200_gpio and pc8736x_gpio
+   implement their own versions of these routines; and use the common
+   file-operations routines implemented in nsc_gpio module.
+
+   Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com>
+
+   NB: this work was tested on the Geode SC-1100 and PC-87366 chips.
+   NSC sold the GEODE line to AMD, and the PC-8736x line to Winbond.
+*/
+
+struct nsc_gpio_ops {
+       struct module*  owner;
+       u32     (*gpio_config)  (unsigned iminor, u32 mask, u32 bits);
+       void    (*gpio_dump)    (struct nsc_gpio_ops *amp, unsigned iminor);
+       int     (*gpio_get)     (unsigned iminor);
+       void    (*gpio_set)     (unsigned iminor, int state);
+       void    (*gpio_set_high)(unsigned iminor);
+       void    (*gpio_set_low) (unsigned iminor);
+       void    (*gpio_change)  (unsigned iminor);
+       int     (*gpio_current) (unsigned iminor);
+       struct device*  dev;    /* for dev_dbg() support, set in init  */
+};
+
+extern ssize_t nsc_gpio_write(struct file *file, const char __user *data,
+                             size_t len, loff_t *ppos);
+
+extern ssize_t nsc_gpio_read(struct file *file, char __user *buf,
+                            size_t len, loff_t *ppos);
+
+extern void nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index);
+
index 62a8c22f5f604981970a762d780c0f9eff101165..983fca251b25c67bfc23c738d282eb09a411602b 100644 (file)
@@ -404,8 +404,8 @@ int pcibios_enable_device(struct pci_dev *, int mask);
 char *pcibios_setup (char *str);
 
 /* Used only when drivers/pci/setup.c is used */
-void pcibios_align_resource(void *, struct resource *,
-                           unsigned long, unsigned long);
+void pcibios_align_resource(void *, struct resource *, resource_size_t,
+                               resource_size_t);
 void pcibios_update_irq(struct pci_dev *, int irq);
 
 /* Generic PCI functions used internally */
@@ -532,10 +532,10 @@ void pci_release_region(struct pci_dev *, int);
 
 /* drivers/pci/bus.c */
 int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
-                          unsigned long size, unsigned long align,
-                          unsigned long min, unsigned int type_mask,
+                          resource_size_t size, resource_size_t align,
+                          resource_size_t min, unsigned int type_mask,
                           void (*alignf)(void *, struct resource *,
-                                         unsigned long, unsigned long),
+                                         resource_size_t, resource_size_t),
                           void *alignf_data);
 void pci_enable_bridges(struct pci_bus *bus);
 
@@ -730,7 +730,8 @@ static inline char *pci_name(struct pci_dev *pdev)
  */
 #ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER
 static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                const struct resource *rsrc, u64 *start, u64 *end)
+                const struct resource *rsrc, resource_size_t *start,
+               resource_size_t *end)
 {
        *start = rsrc->start;
        *end = rsrc->end;
index c2fd2d19938b94931303ed9e538b235a69494687..9ae6b1a753668e74155316473c7b5adcbe5da209 100644 (file)
 #define PCI_DEVICE_ID_NVIDIA_NVENET_19              0x03EF
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2     0x03F6
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3     0x03F7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE      0x0448
 #define PCI_DEVICE_ID_NVIDIA_NVENET_20              0x0450
 #define PCI_DEVICE_ID_NVIDIA_NVENET_21              0x0451
 #define PCI_DEVICE_ID_NVIDIA_NVENET_22              0x0452
 #define PCI_DEVICE_ID_INTEL_ICH8_4     0x2815
 #define PCI_DEVICE_ID_INTEL_ICH8_5     0x283e
 #define PCI_DEVICE_ID_INTEL_ICH8_6     0x2850
-#define PCI_DEVICE_ID_INTEL_GD31244    0x3200
 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
 #define PCI_DEVICE_ID_INTEL_82830_HB   0x3575
 #define PCI_DEVICE_ID_INTEL_82830_CGC  0x3577
diff --git a/include/linux/plist.h b/include/linux/plist.h
new file mode 100644 (file)
index 0000000..b95818a
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Descending-priority-sorted double-linked list
+ *
+ * (C) 2002-2003 Intel Corp
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
+ *
+ * 2001-2005 (c) MontaVista Software, Inc.
+ * Daniel Walker <dwalker@mvista.com>
+ *
+ * (C) 2005 Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Simplifications of the original code by
+ * Oleg Nesterov <oleg@tv-sign.ru>
+ *
+ * Licensed under the FSF's GNU Public License v2 or later.
+ *
+ * Based on simple lists (include/linux/list.h).
+ *
+ * This is a priority-sorted list of nodes; each node has a
+ * priority from INT_MIN (highest) to INT_MAX (lowest).
+ *
+ * Addition is O(K), removal is O(1), change of priority of a node is
+ * O(K) and K is the number of RT priority levels used in the system.
+ * (1 <= K <= 99)
+ *
+ * This list is really a list of lists:
+ *
+ *  - The tier 1 list is the prio_list, different priority nodes.
+ *
+ *  - The tier 2 list is the node_list, serialized nodes.
+ *
+ * Simple ASCII art explanation:
+ *
+ * |HEAD          |
+ * |              |
+ * |prio_list.prev|<------------------------------------|
+ * |prio_list.next|<->|pl|<->|pl|<--------------->|pl|<-|
+ * |10            |   |10|   |21|   |21|   |21|   |40|   (prio)
+ * |              |   |  |   |  |   |  |   |  |   |  |
+ * |              |   |  |   |  |   |  |   |  |   |  |
+ * |node_list.next|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
+ * |node_list.prev|<------------------------------------|
+ *
+ * The nodes on the prio_list list are sorted by priority to simplify
+ * the insertion of new nodes. There are no nodes with duplicate
+ * priorites on the list.
+ *
+ * The nodes on the node_list is ordered by priority and can contain
+ * entries which have the same priority. Those entries are ordered
+ * FIFO
+ *
+ * Addition means: look for the prio_list node in the prio_list
+ * for the priority of the node and insert it before the node_list
+ * entry of the next prio_list node. If it is the first node of
+ * that priority, add it to the prio_list in the right position and
+ * insert it into the serialized node_list list
+ *
+ * Removal means remove it from the node_list and remove it from
+ * the prio_list if the node_list list_head is non empty. In case
+ * of removal from the prio_list it must be checked whether other
+ * entries of the same priority are on the list or not. If there
+ * is another entry of the same priority then this entry has to
+ * replace the removed entry on the prio_list. If the entry which
+ * is removed is the only entry of this priority then a simple
+ * remove from both list is sufficient.
+ *
+ * INT_MIN is the highest priority, 0 is the medium highest, INT_MAX
+ * is lowest priority.
+ *
+ * No locking is done, up to the caller.
+ *
+ */
+#ifndef _LINUX_PLIST_H_
+#define _LINUX_PLIST_H_
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock_types.h>
+
+struct plist_head {
+       struct list_head prio_list;
+       struct list_head node_list;
+#ifdef CONFIG_DEBUG_PI_LIST
+       spinlock_t *lock;
+#endif
+};
+
+struct plist_node {
+       int                     prio;
+       struct plist_head       plist;
+};
+
+#ifdef CONFIG_DEBUG_PI_LIST
+# define PLIST_HEAD_LOCK_INIT(_lock)   .lock = _lock
+#else
+# define PLIST_HEAD_LOCK_INIT(_lock)
+#endif
+
+/**
+ * #PLIST_HEAD_INIT - static struct plist_head initializer
+ *
+ * @head:      struct plist_head variable name
+ */
+#define PLIST_HEAD_INIT(head, _lock)                   \
+{                                                      \
+       .prio_list = LIST_HEAD_INIT((head).prio_list),  \
+       .node_list = LIST_HEAD_INIT((head).node_list),  \
+       PLIST_HEAD_LOCK_INIT(&(_lock))                  \
+}
+
+/**
+ * #PLIST_NODE_INIT - static struct plist_node initializer
+ *
+ * @node:      struct plist_node variable name
+ * @__prio:    initial node priority
+ */
+#define PLIST_NODE_INIT(node, __prio)                  \
+{                                                      \
+       .prio  = (__prio),                              \
+       .plist = PLIST_HEAD_INIT((node).plist, NULL),   \
+}
+
+/**
+ * plist_head_init - dynamic struct plist_head initializer
+ *
+ * @head:      &struct plist_head pointer
+ */
+static inline void
+plist_head_init(struct plist_head *head, spinlock_t *lock)
+{
+       INIT_LIST_HEAD(&head->prio_list);
+       INIT_LIST_HEAD(&head->node_list);
+#ifdef CONFIG_DEBUG_PI_LIST
+       head->lock = lock;
+#endif
+}
+
+/**
+ * plist_node_init - Dynamic struct plist_node initializer
+ *
+ * @node:      &struct plist_node pointer
+ * @prio:      initial node priority
+ */
+static inline void plist_node_init(struct plist_node *node, int prio)
+{
+       node->prio = prio;
+       plist_head_init(&node->plist, NULL);
+}
+
+extern void plist_add(struct plist_node *node, struct plist_head *head);
+extern void plist_del(struct plist_node *node, struct plist_head *head);
+
+/**
+ * plist_for_each - iterate over the plist
+ *
+ * @pos1:      the type * to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define plist_for_each(pos, head)      \
+        list_for_each_entry(pos, &(head)->node_list, plist.node_list)
+
+/**
+ * plist_for_each_entry_safe - iterate over a plist of given type safe
+ * against removal of list entry
+ *
+ * @pos1:      the type * to use as a loop counter.
+ * @n1:        another type * to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define plist_for_each_safe(pos, n, head)      \
+        list_for_each_entry_safe(pos, n, &(head)->node_list, plist.node_list)
+
+/**
+ * plist_for_each_entry        - iterate over list of given type
+ *
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define plist_for_each_entry(pos, head, mem)   \
+        list_for_each_entry(pos, &(head)->node_list, mem.plist.node_list)
+
+/**
+ * plist_for_each_entry_safe - iterate over list of given type safe against
+ * removal of list entry
+ *
+ * @pos:       the type * to use as a loop counter.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @m:         the name of the list_struct within the struct.
+ */
+#define plist_for_each_entry_safe(pos, n, head, m)     \
+       list_for_each_entry_safe(pos, n, &(head)->node_list, m.plist.node_list)
+
+/**
+ * plist_head_empty - return !0 if a plist_head is empty
+ *
+ * @head:      &struct plist_head pointer
+ */
+static inline int plist_head_empty(const struct plist_head *head)
+{
+       return list_empty(&head->node_list);
+}
+
+/**
+ * plist_node_empty - return !0 if plist_node is not on a list
+ *
+ * @node:      &struct plist_node pointer
+ */
+static inline int plist_node_empty(const struct plist_node *node)
+{
+       return plist_head_empty(&node->plist);
+}
+
+/* All functions below assume the plist_head is not empty. */
+
+/**
+ * plist_first_entry - get the struct for the first entry
+ *
+ * @ptr:       the &struct plist_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#ifdef CONFIG_DEBUG_PI_LIST
+# define plist_first_entry(head, type, member) \
+({ \
+       WARN_ON(plist_head_empty(head)); \
+       container_of(plist_first(head), type, member); \
+})
+#else
+# define plist_first_entry(head, type, member) \
+       container_of(plist_first(head), type, member)
+#endif
+
+/**
+ * plist_first - return the first node (and thus, highest priority)
+ *
+ * @head:      the &struct plist_head pointer
+ *
+ * Assumes the plist is _not_ empty.
+ */
+static inline struct plist_node* plist_first(const struct plist_head *head)
+{
+       return list_entry(head->node_list.next,
+                         struct plist_node, plist.node_list);
+}
+
+#endif
index 93b0959eb40f466ba0e1834da22c558b090a937e..ab8a8dd8d64c5f55c88bd28c05d7439875239b72 100644 (file)
@@ -389,7 +389,8 @@ int pnp_start_dev(struct pnp_dev *dev);
 int pnp_stop_dev(struct pnp_dev *dev);
 int pnp_activate_dev(struct pnp_dev *dev);
 int pnp_disable_dev(struct pnp_dev *dev);
-void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size);
+void pnp_resource_change(struct resource *resource, resource_size_t start,
+                               resource_size_t size);
 
 /* protocol helpers */
 int pnp_is_active(struct pnp_dev * dev);
@@ -434,7 +435,9 @@ static inline int pnp_start_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
-static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { }
+static inline void pnp_resource_change(struct resource *resource,
+                                       resource_size_t start,
+                                       resource_size_t size) { }
 
 /* protocol helpers */
 static inline int pnp_is_active(struct pnp_dev * dev) { return 0; }
diff --git a/include/linux/poison.h b/include/linux/poison.h
new file mode 100644 (file)
index 0000000..a5347c0
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _LINUX_POISON_H
+#define _LINUX_POISON_H
+
+/********** include/linux/list.h **********/
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+/********** mm/slab.c **********/
+/*
+ * Magic nums for obj red zoning.
+ * Placed in the first word before and the first word after an obj.
+ */
+#define        RED_INACTIVE    0x5A2CF071UL    /* when obj is inactive */
+#define        RED_ACTIVE      0x170FC2A5UL    /* when obj is active */
+
+/* ...and for poisoning */
+#define        POISON_INUSE    0x5a    /* for use-uninitialised poisoning */
+#define POISON_FREE    0x6b    /* for use-after-free poisoning */
+#define        POISON_END      0xa5    /* end-byte of poisoning */
+
+/********** arch/$ARCH/mm/init.c **********/
+#define POISON_FREE_INITMEM    0xcc
+
+/********** arch/x86_64/mm/init.c **********/
+#define        POISON_FREE_INITDATA    0xba
+
+/********** arch/ia64/hp/common/sba_iommu.c **********/
+/*
+ * arch/ia64/hp/common/sba_iommu.c uses a 16-byte poison string with a
+ * value of "SBAIOMMU POISON\0" for spill-over poisoning.
+ */
+
+/********** fs/jbd/journal.c **********/
+#define JBD_POISON_FREE        0x5b
+
+/********** drivers/base/dmapool.c **********/
+#define        POOL_POISON_FREED       0xa7    /* !inuse */
+#define        POOL_POISON_ALLOCATED   0xa9    /* !initted */
+
+/********** drivers/atm/ **********/
+#define ATM_POISON_FREE                0x12
+
+/********** kernel/mutexes **********/
+#define MUTEX_DEBUG_INIT       0x11
+#define MUTEX_DEBUG_FREE       0x22
+
+/********** security/ **********/
+#define KEY_DESTROY            0xbd
+
+/********** sound/oss/ **********/
+#define OSS_POISON_FREE                0xAB
+
+#endif
index 6312758393b61a3e3e741825f78d49956024ea26..48dfe00070c70bbcd27574870b19288f7655364c 100644 (file)
@@ -258,6 +258,7 @@ extern void rcu_init(void);
 extern void rcu_check_callbacks(int cpu, int user);
 extern void rcu_restart_cpu(int cpu);
 extern long rcu_batches_completed(void);
+extern long rcu_batches_completed_bh(void);
 
 /* Exported interfaces */
 extern void FASTCALL(call_rcu(struct rcu_head *head, 
index 5676c4210e2c186d23548072abaf39d5885d4874..daa2d83cefe832a541f6e3ec1f5bd62f01b34c56 100644 (file)
@@ -1973,7 +1973,7 @@ void reiserfs_unmap_buffer(struct buffer_head *);
 /* file.c */
 extern struct inode_operations reiserfs_file_inode_operations;
 extern const struct file_operations reiserfs_file_operations;
-extern struct address_space_operations reiserfs_address_space_operations;
+extern const struct address_space_operations reiserfs_address_space_operations;
 
 /* fix_nodes.c */
 
diff --git a/include/linux/rtmutex.h b/include/linux/rtmutex.h
new file mode 100644 (file)
index 0000000..fa4a3b8
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * RT Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This file contains the public data structure and API definitions.
+ */
+
+#ifndef __LINUX_RT_MUTEX_H
+#define __LINUX_RT_MUTEX_H
+
+#include <linux/linkage.h>
+#include <linux/plist.h>
+#include <linux/spinlock_types.h>
+
+/*
+ * The rt_mutex structure
+ *
+ * @wait_lock: spinlock to protect the structure
+ * @wait_list: pilist head to enqueue waiters in priority order
+ * @owner:     the mutex owner
+ */
+struct rt_mutex {
+       spinlock_t              wait_lock;
+       struct plist_head       wait_list;
+       struct task_struct      *owner;
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+       int                     save_state;
+       struct list_head        held_list_entry;
+       unsigned long           acquire_ip;
+       const char              *name, *file;
+       int                     line;
+       void                    *magic;
+#endif
+};
+
+struct rt_mutex_waiter;
+struct hrtimer_sleeper;
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+ extern int rt_mutex_debug_check_no_locks_freed(const void *from,
+                                               unsigned long len);
+ extern void rt_mutex_debug_check_no_locks_held(struct task_struct *task);
+#else
+ static inline int rt_mutex_debug_check_no_locks_freed(const void *from,
+                                                      unsigned long len)
+ {
+       return 0;
+ }
+# define rt_mutex_debug_check_no_locks_held(task)      do { } while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) \
+       , .name = #mutexname, .file = __FILE__, .line = __LINE__
+# define rt_mutex_init(mutex)                  __rt_mutex_init(mutex, __FUNCTION__)
+ extern void rt_mutex_debug_task_free(struct task_struct *tsk);
+#else
+# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname)
+# define rt_mutex_init(mutex)                  __rt_mutex_init(mutex, NULL)
+# define rt_mutex_debug_task_free(t)                   do { } while (0)
+#endif
+
+#define __RT_MUTEX_INITIALIZER(mutexname) \
+       { .wait_lock = SPIN_LOCK_UNLOCKED \
+       , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list, mutexname.wait_lock) \
+       , .owner = NULL \
+       __DEBUG_RT_MUTEX_INITIALIZER(mutexname)}
+
+#define DEFINE_RT_MUTEX(mutexname) \
+       struct rt_mutex mutexname = __RT_MUTEX_INITIALIZER(mutexname)
+
+/***
+ * rt_mutex_is_locked - is the mutex locked
+ * @lock: the mutex to be queried
+ *
+ * Returns 1 if the mutex is locked, 0 if unlocked.
+ */
+static inline int rt_mutex_is_locked(struct rt_mutex *lock)
+{
+       return lock->owner != NULL;
+}
+
+extern void __rt_mutex_init(struct rt_mutex *lock, const char *name);
+extern void rt_mutex_destroy(struct rt_mutex *lock);
+
+extern void rt_mutex_lock(struct rt_mutex *lock);
+extern int rt_mutex_lock_interruptible(struct rt_mutex *lock,
+                                               int detect_deadlock);
+extern int rt_mutex_timed_lock(struct rt_mutex *lock,
+                                       struct hrtimer_sleeper *timeout,
+                                       int detect_deadlock);
+
+extern int rt_mutex_trylock(struct rt_mutex *lock);
+
+extern void rt_mutex_unlock(struct rt_mutex *lock);
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# define INIT_RT_MUTEX_DEBUG(tsk)                                      \
+       .held_list_head = LIST_HEAD_INIT(tsk.held_list_head),           \
+       .held_list_lock = SPIN_LOCK_UNLOCKED
+#else
+# define INIT_RT_MUTEX_DEBUG(tsk)
+#endif
+
+#ifdef CONFIG_RT_MUTEXES
+# define INIT_RT_MUTEXES(tsk)                                          \
+       .pi_waiters     = PLIST_HEAD_INIT(tsk.pi_waiters, tsk.pi_lock), \
+       INIT_RT_MUTEX_DEBUG(tsk)
+#else
+# define INIT_RT_MUTEXES(tsk)
+#endif
+
+#endif
index 122a25c1b997e46641b636db8a740ca9af9e3788..821f0481ebe190c0b5e171a4e6ab887802b3015c 100644 (file)
@@ -73,6 +73,7 @@ struct sched_param {
 #include <linux/seccomp.h>
 #include <linux/rcupdate.h>
 #include <linux/futex.h>
+#include <linux/rtmutex.h>
 
 #include <linux/time.h>
 #include <linux/param.h>
@@ -83,6 +84,7 @@ struct sched_param {
 #include <asm/processor.h>
 
 struct exec_domain;
+struct futex_pi_state;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -123,6 +125,7 @@ extern unsigned long nr_running(void);
 extern unsigned long nr_uninterruptible(void);
 extern unsigned long nr_active(void);
 extern unsigned long nr_iowait(void);
+extern unsigned long weighted_cpuload(const int cpu);
 
 
 /*
@@ -494,8 +497,11 @@ struct signal_struct {
 
 #define MAX_PRIO               (MAX_RT_PRIO + 40)
 
-#define rt_task(p)             (unlikely((p)->prio < MAX_RT_PRIO))
+#define rt_prio(prio)          unlikely((prio) < MAX_RT_PRIO)
+#define rt_task(p)             rt_prio((p)->prio)
 #define batch_task(p)          (unlikely((p)->policy == SCHED_BATCH))
+#define has_rt_policy(p) \
+       unlikely((p)->policy != SCHED_NORMAL && (p)->policy != SCHED_BATCH)
 
 /*
  * Some day this will be a full-fledged user tracking system..
@@ -558,9 +564,9 @@ enum idle_type
 /*
  * sched-domains (multiprocessor balancing) declarations:
  */
-#ifdef CONFIG_SMP
 #define SCHED_LOAD_SCALE       128UL   /* increase resolution of load */
 
+#ifdef CONFIG_SMP
 #define SD_LOAD_BALANCE                1       /* Do load balancing on this domain. */
 #define SD_BALANCE_NEWIDLE     2       /* Balance when about to become idle */
 #define SD_BALANCE_EXEC                4       /* Balance on exec */
@@ -569,6 +575,11 @@ enum idle_type
 #define SD_WAKE_AFFINE         32      /* Wake task to waking CPU */
 #define SD_WAKE_BALANCE                64      /* Perform balancing at task wakeup */
 #define SD_SHARE_CPUPOWER      128     /* Domain members share cpu power */
+#define SD_POWERSAVINGS_BALANCE        256     /* Balance for power savings */
+
+#define BALANCE_FOR_POWER      ((sched_mc_power_savings || sched_smt_power_savings) \
+                                ? SD_POWERSAVINGS_BALANCE : 0)
+
 
 struct sched_group {
        struct sched_group *next;       /* Must be a circular list */
@@ -638,7 +649,7 @@ struct sched_domain {
 #endif
 };
 
-extern void partition_sched_domains(cpumask_t *partition1,
+extern int partition_sched_domains(cpumask_t *partition1,
                                    cpumask_t *partition2);
 
 /*
@@ -713,10 +724,13 @@ struct task_struct {
 
        int lock_depth;         /* BKL lock depth */
 
-#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
+#ifdef CONFIG_SMP
+#ifdef __ARCH_WANT_UNLOCKED_CTXSW
        int oncpu;
 #endif
-       int prio, static_prio;
+#endif
+       int load_weight;        /* for niceness load balancing purposes */
+       int prio, static_prio, normal_prio;
        struct list_head run_list;
        prio_array_t *array;
 
@@ -843,6 +857,20 @@ struct task_struct {
 /* Protection of (de-)allocation: mm, files, fs, tty, keyrings */
        spinlock_t alloc_lock;
 
+       /* Protection of the PI data structures: */
+       spinlock_t pi_lock;
+
+#ifdef CONFIG_RT_MUTEXES
+       /* PI waiters blocked on a rt_mutex held by this task */
+       struct plist_head pi_waiters;
+       /* Deadlock detection and priority inheritance handling */
+       struct rt_mutex_waiter *pi_blocked_on;
+# ifdef CONFIG_DEBUG_RT_MUTEXES
+       spinlock_t held_list_lock;
+       struct list_head held_list_head;
+# endif
+#endif
+
 #ifdef CONFIG_DEBUG_MUTEXES
        /* mutex deadlock detection */
        struct mutex_waiter *blocked_on;
@@ -888,6 +916,8 @@ struct task_struct {
 #ifdef CONFIG_COMPAT
        struct compat_robust_list_head __user *compat_robust_list;
 #endif
+       struct list_head pi_state_list;
+       struct futex_pi_state *pi_state_cache;
 
        atomic_t fs_excl;       /* holding fs exclusive resources */
        struct rcu_head rcu;
@@ -955,6 +985,7 @@ static inline void put_task_struct(struct task_struct *t)
 #define PF_SPREAD_PAGE 0x01000000      /* Spread page cache over cpuset */
 #define PF_SPREAD_SLAB 0x02000000      /* Spread some slab caches over cpuset */
 #define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
+#define PF_MUTEX_TESTER        0x20000000      /* Thread belongs to the rt mutex tester */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
@@ -1009,6 +1040,19 @@ static inline void idle_task_exit(void) {}
 #endif
 
 extern void sched_idle_next(void);
+
+#ifdef CONFIG_RT_MUTEXES
+extern int rt_mutex_getprio(task_t *p);
+extern void rt_mutex_setprio(task_t *p, int prio);
+extern void rt_mutex_adjust_pi(task_t *p);
+#else
+static inline int rt_mutex_getprio(task_t *p)
+{
+       return p->normal_prio;
+}
+# define rt_mutex_adjust_pi(p)         do { } while (0)
+#endif
+
 extern void set_user_nice(task_t *p, long nice);
 extern int task_prio(const task_t *p);
 extern int task_nice(const task_t *p);
@@ -1408,6 +1452,11 @@ static inline void arch_pick_mmap_layout(struct mm_struct *mm)
 extern long sched_setaffinity(pid_t pid, cpumask_t new_mask);
 extern long sched_getaffinity(pid_t pid, cpumask_t *mask);
 
+#include <linux/sysdev.h>
+extern int sched_mc_power_savings, sched_smt_power_savings;
+extern struct sysdev_attribute attr_sched_mc_power_savings, attr_sched_smt_power_savings;
+extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls);
+
 extern void normalize_rt_tasks(void);
 
 #ifdef CONFIG_PM
index a22f9e173ad2d3b953dc3b90fb9df231b70557b2..693c0557e70bdf6b13baa898a4dca5c82b8ae919 100644 (file)
@@ -49,10 +49,3 @@ extern unsigned scx200_cb_base;
 #define SCx200_REV 0x3d                /* Revision Register */
 #define SCx200_CBA 0x3e                /* Configuration Base Address Register */
 #define SCx200_CBA_SCRATCH 0x64        /* Configuration Base Address Scratchpad */
-
-/*
-    Local variables:
-        compile-command: "make -C ../.. bzImage modules"
-        c-basic-offset: 8
-    End:
-*/
index 30cdd648ba79355d5dfed28fcbbb64ccf6be4de2..90dd069cc145c4b26a6fefe020aacee17d28aa65 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/spinlock.h>
 
-u32 scx200_gpio_configure(int index, u32 set, u32 clear);
+u32 scx200_gpio_configure(unsigned index, u32 set, u32 clear);
 
 extern unsigned scx200_gpio_base;
 extern long scx200_gpio_shadow[2];
@@ -17,7 +17,7 @@ extern long scx200_gpio_shadow[2];
 
 /* returns the value of the GPIO pin */
 
-static inline int scx200_gpio_get(int index) {
+static inline int scx200_gpio_get(unsigned index) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR + 0x04;
        __SCx200_GPIO_INDEX;
@@ -29,7 +29,7 @@ static inline int scx200_gpio_get(int index) {
    driven if the GPIO is configured as an output, it might not be the
    state of the GPIO right now if the GPIO is configured as an input) */
 
-static inline int scx200_gpio_current(int index) {
+static inline int scx200_gpio_current(unsigned index) {
         __SCx200_GPIO_BANK;
        __SCx200_GPIO_INDEX;
                
@@ -38,7 +38,7 @@ static inline int scx200_gpio_current(int index) {
 
 /* drive the GPIO signal high */
 
-static inline void scx200_gpio_set_high(int index) {
+static inline void scx200_gpio_set_high(unsigned index) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
@@ -49,7 +49,7 @@ static inline void scx200_gpio_set_high(int index) {
 
 /* drive the GPIO signal low */
 
-static inline void scx200_gpio_set_low(int index) {
+static inline void scx200_gpio_set_low(unsigned index) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
@@ -60,7 +60,7 @@ static inline void scx200_gpio_set_low(int index) {
 
 /* drive the GPIO signal to state */
 
-static inline void scx200_gpio_set(int index, int state) {
+static inline void scx200_gpio_set(unsigned index, int state) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
@@ -73,7 +73,7 @@ static inline void scx200_gpio_set(int index, int state) {
 }
 
 /* toggle the GPIO signal */
-static inline void scx200_gpio_change(int index) {
+static inline void scx200_gpio_change(unsigned index) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
@@ -87,10 +87,3 @@ static inline void scx200_gpio_change(int index) {
 #undef __SCx200_GPIO_SHADOW
 #undef __SCx200_GPIO_INDEX
 #undef __SCx200_GPIO_OUT
-
-/*
-    Local variables:
-        compile-command: "make -C ../.. bzImage modules"
-        c-basic-offset: 8
-    End:
-*/
index e928c0dcc29755d31c2ba5b7f1d96b1f3ac50b1e..c8bb68099eb9e35bf5ae2edba0c43244ca95ff5b 100644 (file)
@@ -642,10 +642,14 @@ struct spi_board_info {
        u16             bus_num;
        u16             chip_select;
 
+       /* mode becomes spi_device.mode, and is essential for chips
+        * where the default of SPI_CS_HIGH = 0 is wrong.
+        */
+       u8              mode;
+
        /* ... may need additional spi_device chip config data here.
         * avoid stuff protocol drivers can set; but include stuff
         * needed to behave without being bound to a driver:
-        *  - chipselect polarity
         *  - quirks like clock rate mattering when not selected
         */
 };
index dc3f3aa0c83e89ec345caac3d4af9fdb1eae35b1..c41e2d6d1acc3dfb4ca036a6a78047e02181d5c0 100644 (file)
@@ -199,6 +199,8 @@ static inline int zone_reclaim(struct zone *z, gfp_t mask, unsigned int order)
 }
 #endif
 
+extern int kswapd_run(int nid);
+
 #ifdef CONFIG_MMU
 /* linux/mm/shmem.c */
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
index 33785b79d548a802e346022714d5032cacdbd097..008f04c5673715b33a52536e2bd4375bc064ff92 100644 (file)
@@ -174,9 +174,9 @@ asmlinkage long sys_waitid(int which, pid_t pid,
                           int options, struct rusage __user *ru);
 asmlinkage long sys_waitpid(pid_t pid, int __user *stat_addr, int options);
 asmlinkage long sys_set_tid_address(int __user *tidptr);
-asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
+asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
                        struct timespec __user *utime, u32 __user *uaddr2,
-                       int val3);
+                       u32 val3);
 
 asmlinkage long sys_init_module(void __user *umod, unsigned long len,
                                const char __user *uargs);
index 349ef908a2222d313ea7f87932a3a2d1d44b36b2..46e4d8f2771f9fa5812205c01a0fc85778fa9a44 100644 (file)
@@ -149,6 +149,7 @@ enum
        KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */
        KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */
        KERN_COMPAT_LOG=73,     /* int: print compat layer  messages */
+       KERN_MAX_LOCK_DEPTH=74,
 };
 
 
@@ -189,6 +190,7 @@ enum
        VM_ZONE_RECLAIM_MODE=31, /* reclaim local zone memory before going off node */
        VM_ZONE_RECLAIM_INTERVAL=32, /* time period to wait after reclaim failure */
        VM_PANIC_ON_OOM=33,     /* panic at out-of-memory */
+       VM_VDSO_ENABLED=34,     /* map VDSO into new processes? */
 };
 
 
index a305ae2e44b6dde305d3afe241768e32c47d8907..ec1eca85290ade96c5f42da4d74acac2a8ae2407 100644 (file)
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
                                | SD_BALANCE_EXEC       \
-                               | SD_WAKE_AFFINE,       \
+                               | SD_WAKE_AFFINE        \
+                               | BALANCE_FOR_POWER,    \
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
        .nr_balance_failed      = 0,                    \
index cb35ca50a0a66feffff3a63b598634efc9f1f027..b3b807e4b050031cf5a2e0e4dad2e1e4b31503a3 100644 (file)
@@ -57,7 +57,6 @@ struct tty_buffer {
        unsigned char *flag_buf_ptr;
        int used;
        int size;
-       int active;
        int commit;
        int read;
        /* Data points here */
@@ -259,7 +258,6 @@ struct tty_struct {
 #define TTY_DO_WRITE_WAKEUP    5       /* Call write_wakeup after queuing new */
 #define TTY_PUSH               6       /* n_tty private */
 #define TTY_CLOSING            7       /* ->close() in progress */
-#define TTY_DONT_FLIP          8       /* Defer buffer flip */
 #define TTY_LDISC              9       /* Line discipline attached */
 #define TTY_HW_COOK_OUT        14      /* Hardware can do output cooking */
 #define TTY_HW_COOK_IN                 15      /* Hardware can do input cooking */
index 31548303ee3767095f86efb47696ce433662450e..eb677cf56106cc17dfc1f05873c9478e93813935 100644 (file)
@@ -12,7 +12,7 @@ static inline int tty_insert_flip_char(struct tty_struct *tty,
                                        unsigned char ch, char flag)
 {
        struct tty_buffer *tb = tty->buf.tail;
-       if (tb && tb->active && tb->used < tb->size) {
+       if (tb && tb->used < tb->size) {
                tb->flag_buf_ptr[tb->used] = flag;
                tb->char_buf_ptr[tb->used++] = ch;
                return 1;
index a5e46e783ffa03ca4d38e918e09f4e8b78367380..3f235660a3cd6a76c4fa0480e649deaa5a4077d3 100644 (file)
@@ -177,8 +177,15 @@ typedef __u64 __bitwise __be64;
 
 #ifdef __KERNEL__
 typedef unsigned __bitwise__ gfp_t;
+
+#ifdef CONFIG_RESOURCES_64BIT
+typedef u64 resource_size_t;
+#else
+typedef u32 resource_size_t;
 #endif
 
+#endif /* __KERNEL__ */
+
 struct ustat {
        __kernel_daddr_t        f_tfree;
        __kernel_ino_t          f_tinode;
index 914f911325be9483cc29ab481f3014e0e27df879..e39b7cc433902565d9b7aa5d450f5be86a10118b 100644 (file)
@@ -966,7 +966,7 @@ extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
 extern struct inode_operations ufs_file_inode_operations;
 extern const struct file_operations ufs_file_operations;
 
-extern struct address_space_operations ufs_aops;
+extern const struct address_space_operations ufs_aops;
 
 /* ialloc.c */
 extern void ufs_free_inode (struct inode *inode);
index 1192ed8f4fe8ae965ccca10ce7ca745e0440b61d..011bcfeb9f090a7a49dbf54c4819d3306160c852 100644 (file)
@@ -28,6 +28,9 @@ struct watchdog_info {
 #define        WDIOC_KEEPALIVE         _IOR(WATCHDOG_IOCTL_BASE, 5, int)
 #define        WDIOC_SETTIMEOUT        _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
 #define        WDIOC_GETTIMEOUT        _IOR(WATCHDOG_IOCTL_BASE, 7, int)
+#define        WDIOC_SETPRETIMEOUT     _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
+#define        WDIOC_GETPRETIMEOUT     _IOR(WATCHDOG_IOCTL_BASE, 9, int)
+#define        WDIOC_GETTIMELEFT       _IOR(WATCHDOG_IOCTL_BASE, 10, int)
 
 #define        WDIOF_UNKNOWN           -1      /* Unknown flag error */
 #define        WDIOS_UNKNOWN           -1      /* Unknown status error */
@@ -38,9 +41,10 @@ struct watchdog_info {
 #define        WDIOF_EXTERN2           0x0008  /* External relay 2 */
 #define        WDIOF_POWERUNDER        0x0010  /* Power bad/power fault */
 #define        WDIOF_CARDRESET         0x0020  /* Card previously reset the CPU */
-#define WDIOF_POWEROVER                0x0040  /* Power over voltage */
-#define WDIOF_SETTIMEOUT       0x0080  /* Set timeout (in seconds) */
-#define WDIOF_MAGICCLOSE       0x0100  /* Supports magic close char */
+#define        WDIOF_POWEROVER         0x0040  /* Power over voltage */
+#define        WDIOF_SETTIMEOUT        0x0080  /* Set timeout (in seconds) */
+#define        WDIOF_MAGICCLOSE        0x0100  /* Supports magic close char */
+#define        WDIOF_PRETIMEOUT        0x0200  /* Pretimeout (in seconds), get/set */
 #define        WDIOF_KEEPALIVEPING     0x8000  /* Keep alive ping reply */
 
 #define        WDIOS_DISABLECARD       0x0001  /* Turn off the watchdog timer */
index 074c4008ad5296fa5f73c5c21e67dd3d42fd69d2..d91d88f93c8b3485e36f3c5bda8ed8dab31b905c 100644 (file)
@@ -89,9 +89,9 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
                struct v4l2_queryctrl *qctrl);
 const char **cx2341x_ctrl_get_menu(u32 id);
 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
-               struct v4l2_ext_controls *ctrls, int cmd);
+               struct v4l2_ext_controls *ctrls, unsigned int cmd);
 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
-void cx2341x_log_status(struct cx2341x_mpeg_params *p, int cardid);
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix);
 
 /* Firmware names */
 #define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
index df55b36656010b726aeb8b7a3e08984e2940a8da..f70f2fd273c2152708bdac6800d038229b58a8cc 100644 (file)
@@ -339,9 +339,14 @@ config BASE_FULL
          kernel data structures. This saves memory on small machines,
          but may reduce performance.
 
+config RT_MUTEXES
+       boolean
+       select PLIST
+
 config FUTEX
        bool "Enable futex support" if EMBEDDED
        default y
+       select RT_MUTEXES
        help
          Disabling this option will cause the kernel to be built without
          support for "fast userspace mutexes".  The resulting kernel may not
index 80af1a52485fcfd5b272e747d7a1576b0993167f..0d57f6ccb63a1a7c1f1efd47810727feb40e8ae8 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/mempolicy.h>
 #include <linux/key.h>
 #include <linux/unwind.h>
+#include <linux/buffer_head.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -80,7 +81,6 @@ extern void mca_init(void);
 extern void sbus_init(void);
 extern void sysctl_init(void);
 extern void signals_init(void);
-extern void buffer_init(void);
 extern void pidhash_init(void);
 extern void pidmap_init(void);
 extern void prio_tree_init(void);
index 752bd7d383af34ecf7f72b3472d4fa9ccbd9a519..82fb182f6f618421cb822aac8131914486b8a651 100644 (file)
@@ -16,6 +16,9 @@ obj-$(CONFIG_FUTEX) += futex.o
 ifeq ($(CONFIG_COMPAT),y)
 obj-$(CONFIG_FUTEX) += futex_compat.o
 endif
+obj-$(CONFIG_RT_MUTEXES) += rtmutex.o
+obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o
+obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o spinlock.o
 obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
index 368c4f03fe0e9fd0b7426b650d83a847badb05d7..126ca43d5d2ba9eb566af4380668c9546266efcd 100644 (file)
@@ -521,6 +521,7 @@ static void do_acct_process(struct file *file)
 
 /**
  * acct_init_pacct - initialize a new pacct_struct
+ * @pacct: per-process accounting info struct to initialize
  */
 void acct_init_pacct(struct pacct_struct *pacct)
 {
@@ -576,7 +577,7 @@ void acct_collect(long exitcode, int group_dead)
  *
  * handles process accounting for an exiting task
  */
-void acct_process()
+void acct_process(void)
 {
        struct file *file = NULL;
 
index 7dfac7031bd734f6c117e66b660b436b842e41be..82443fb433efcb9d550126be82dabf80c0308c23 100644 (file)
@@ -818,7 +818,7 @@ err:
  */
 unsigned int audit_serial(void)
 {
-       static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
+       static DEFINE_SPINLOCK(serial_lock);
        static unsigned int serial = 0;
 
        unsigned long flags;
index 9ebd96fda2958835a7d0d0aa6dc1993ee11f1098..dc5e3f01efe747c9d1816895ae1a1e40fb527489 100644 (file)
@@ -658,8 +658,7 @@ static void audit_log_task_context(struct audit_buffer *ab)
        return;
 
 error_path:
-       if (ctx)
-               kfree(ctx);
+       kfree(ctx);
        audit_panic("error in audit_log_task_context");
        return;
 }
@@ -1367,7 +1366,7 @@ int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
  * @mqdes: MQ descriptor
  * @msg_len: Message length
  * @msg_prio: Message priority
- * @abs_timeout: Message timeout in absolute time
+ * @u_abs_timeout: Message timeout in absolute time
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
@@ -1409,8 +1408,8 @@ int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
  * __audit_mq_timedreceive - record audit data for a POSIX MQ timed receive
  * @mqdes: MQ descriptor
  * @msg_len: Message length
- * @msg_prio: Message priority
- * @abs_timeout: Message timeout in absolute time
+ * @u_msg_prio: Message priority
+ * @u_abs_timeout: Message timeout in absolute time
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
@@ -1558,7 +1557,6 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp)
  * @uid: msgq user id
  * @gid: msgq group id
  * @mode: msgq mode (permissions)
- * @ipcp: in-kernel IPC permissions
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
index 03dcd981846a6b8020a07c058312c7277621be49..70fbf2e83766abb527d84bc6c4ddc30646036609 100644 (file)
@@ -18,7 +18,7 @@
 /* This protects CPUs going up and down... */
 static DEFINE_MUTEX(cpucontrol);
 
-static BLOCKING_NOTIFIER_HEAD(cpu_chain);
+static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain);
 
 #ifdef CONFIG_HOTPLUG_CPU
 static struct task_struct *lock_cpu_hotplug_owner;
@@ -69,10 +69,13 @@ EXPORT_SYMBOL_GPL(lock_cpu_hotplug_interruptible);
 #endif /* CONFIG_HOTPLUG_CPU */
 
 /* Need to know about CPUs going up/down? */
-int register_cpu_notifier(struct notifier_block *nb)
+int __cpuinit register_cpu_notifier(struct notifier_block *nb)
 {
        return blocking_notifier_chain_register(&cpu_chain, nb);
 }
+
+#ifdef CONFIG_HOTPLUG_CPU
+
 EXPORT_SYMBOL(register_cpu_notifier);
 
 void unregister_cpu_notifier(struct notifier_block *nb)
@@ -81,7 +84,6 @@ void unregister_cpu_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_cpu_notifier);
 
-#ifdef CONFIG_HOTPLUG_CPU
 static inline void check_for_tasks(int cpu)
 {
        struct task_struct *p;
index 304ef637be6c700e7b5d73172222a0e05e5f96d8..ab06b9f88f64677ca036dea0285f740ccb54e1e9 100644 (file)
@@ -925,10 +925,19 @@ fastcall NORET_TYPE void do_exit(long code)
        mpol_free(tsk->mempolicy);
        tsk->mempolicy = NULL;
 #endif
+       /*
+        * This must happen late, after the PID is not
+        * hashed anymore:
+        */
+       if (unlikely(!list_empty(&tsk->pi_state_list)))
+               exit_pi_state_list(tsk);
+       if (unlikely(current->pi_state_cache))
+               kfree(current->pi_state_cache);
        /*
         * If DEBUG_MUTEXES is on, make sure we are holding no locks:
         */
        mutex_debug_check_no_locks_held(tsk);
+       rt_mutex_debug_check_no_locks_held(tsk);
 
        if (tsk->io_context)
                exit_io_context();
index 9b4e54ef0225e21f92366302ae9430933b330dbd..628198a4f28a722b25b37c26ecbd401c67919a8d 100644 (file)
@@ -104,6 +104,7 @@ static kmem_cache_t *mm_cachep;
 void free_task(struct task_struct *tsk)
 {
        free_thread_info(tsk->thread_info);
+       rt_mutex_debug_task_free(tsk);
        free_task_struct(tsk);
 }
 EXPORT_SYMBOL(free_task);
@@ -913,6 +914,19 @@ asmlinkage long sys_set_tid_address(int __user *tidptr)
        return current->pid;
 }
 
+static inline void rt_mutex_init_task(struct task_struct *p)
+{
+#ifdef CONFIG_RT_MUTEXES
+       spin_lock_init(&p->pi_lock);
+       plist_head_init(&p->pi_waiters, &p->pi_lock);
+       p->pi_blocked_on = NULL;
+# ifdef CONFIG_DEBUG_RT_MUTEXES
+       spin_lock_init(&p->held_list_lock);
+       INIT_LIST_HEAD(&p->held_list_head);
+# endif
+#endif
+}
+
 /*
  * This creates a new process as a copy of the old one,
  * but does not actually start it yet.
@@ -1034,6 +1048,8 @@ static task_t *copy_process(unsigned long clone_flags,
        mpol_fix_fork_child_flag(p);
 #endif
 
+       rt_mutex_init_task(p);
+
 #ifdef CONFIG_DEBUG_MUTEXES
        p->blocked_on = NULL; /* not blocked yet */
 #endif
@@ -1076,6 +1092,9 @@ static task_t *copy_process(unsigned long clone_flags,
 #ifdef CONFIG_COMPAT
        p->compat_robust_list = NULL;
 #endif
+       INIT_LIST_HEAD(&p->pi_state_list);
+       p->pi_state_cache = NULL;
+
        /*
         * sigaltstack should be cleared when sharing the same VM
         */
index e1a380c77a5a2ac947f4fceee190fa7518488f41..6c91f938005db0719bac62a643fff9b411b7f594 100644 (file)
  *  (C) Copyright 2006 Red Hat Inc, All Rights Reserved
  *  Thanks to Thomas Gleixner for suggestions, analysis and fixes.
  *
+ *  PI-futex support started by Ingo Molnar and Thomas Gleixner
+ *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
  *  Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
  *  enough at me, Linus for the original (flawed) idea, Matthew
  *  Kirkwood for proof-of-concept implementation.
@@ -46,6 +50,8 @@
 #include <linux/signal.h>
 #include <asm/futex.h>
 
+#include "rtmutex_common.h"
+
 #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
 
 /*
@@ -63,7 +69,7 @@ union futex_key {
                int offset;
        } shared;
        struct {
-               unsigned long uaddr;
+               unsigned long address;
                struct mm_struct *mm;
                int offset;
        } private;
@@ -74,6 +80,27 @@ union futex_key {
        } both;
 };
 
+/*
+ * Priority Inheritance state:
+ */
+struct futex_pi_state {
+       /*
+        * list of 'owned' pi_state instances - these have to be
+        * cleaned up in do_exit() if the task exits prematurely:
+        */
+       struct list_head list;
+
+       /*
+        * The PI object:
+        */
+       struct rt_mutex pi_mutex;
+
+       struct task_struct *owner;
+       atomic_t refcount;
+
+       union futex_key key;
+};
+
 /*
  * We use this hashed waitqueue instead of a normal wait_queue_t, so
  * we can wake only the relevant ones (hashed queues may be shared).
@@ -87,15 +114,19 @@ struct futex_q {
        struct list_head list;
        wait_queue_head_t waiters;
 
-       /* Which hash list lock to use. */
+       /* Which hash list lock to use: */
        spinlock_t *lock_ptr;
 
-       /* Key which the futex is hashed on. */
+       /* Key which the futex is hashed on: */
        union futex_key key;
 
-       /* For fd, sigio sent using these. */
+       /* For fd, sigio sent using these: */
        int fd;
        struct file *filp;
+
+       /* Optional priority inheritance state: */
+       struct futex_pi_state *pi_state;
+       struct task_struct *task;
 };
 
 /*
@@ -144,8 +175,9 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
  *
  * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
  */
-static int get_futex_key(unsigned long uaddr, union futex_key *key)
+static int get_futex_key(u32 __user *uaddr, union futex_key *key)
 {
+       unsigned long address = (unsigned long)uaddr;
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        struct page *page;
@@ -154,16 +186,16 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
        /*
         * The futex address must be "naturally" aligned.
         */
-       key->both.offset = uaddr % PAGE_SIZE;
+       key->both.offset = address % PAGE_SIZE;
        if (unlikely((key->both.offset % sizeof(u32)) != 0))
                return -EINVAL;
-       uaddr -= key->both.offset;
+       address -= key->both.offset;
 
        /*
         * The futex is hashed differently depending on whether
         * it's in a shared or private mapping.  So check vma first.
         */
-       vma = find_extend_vma(mm, uaddr);
+       vma = find_extend_vma(mm, address);
        if (unlikely(!vma))
                return -EFAULT;
 
@@ -184,7 +216,7 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
         */
        if (likely(!(vma->vm_flags & VM_MAYSHARE))) {
                key->private.mm = mm;
-               key->private.uaddr = uaddr;
+               key->private.address = address;
                return 0;
        }
 
@@ -194,7 +226,7 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
        key->shared.inode = vma->vm_file->f_dentry->d_inode;
        key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
        if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
-               key->shared.pgoff = (((uaddr - vma->vm_start) >> PAGE_SHIFT)
+               key->shared.pgoff = (((address - vma->vm_start) >> PAGE_SHIFT)
                                     + vma->vm_pgoff);
                return 0;
        }
@@ -205,7 +237,7 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
         * from swap.  But that's a lot of code to duplicate here
         * for a rare case, so we simply fetch the page.
         */
-       err = get_user_pages(current, mm, uaddr, 1, 0, 0, &page, NULL);
+       err = get_user_pages(current, mm, address, 1, 0, 0, &page, NULL);
        if (err >= 0) {
                key->shared.pgoff =
                        page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
@@ -246,17 +278,243 @@ static void drop_key_refs(union futex_key *key)
        }
 }
 
-static inline int get_futex_value_locked(int *dest, int __user *from)
+static inline int get_futex_value_locked(u32 *dest, u32 __user *from)
 {
        int ret;
 
        inc_preempt_count();
-       ret = __copy_from_user_inatomic(dest, from, sizeof(int));
+       ret = __copy_from_user_inatomic(dest, from, sizeof(u32));
        dec_preempt_count();
 
        return ret ? -EFAULT : 0;
 }
 
+/*
+ * Fault handling. Called with current->mm->mmap_sem held.
+ */
+static int futex_handle_fault(unsigned long address, int attempt)
+{
+       struct vm_area_struct * vma;
+       struct mm_struct *mm = current->mm;
+
+       if (attempt >= 2 || !(vma = find_vma(mm, address)) ||
+           vma->vm_start > address || !(vma->vm_flags & VM_WRITE))
+               return -EFAULT;
+
+       switch (handle_mm_fault(mm, vma, address, 1)) {
+       case VM_FAULT_MINOR:
+               current->min_flt++;
+               break;
+       case VM_FAULT_MAJOR:
+               current->maj_flt++;
+               break;
+       default:
+               return -EFAULT;
+       }
+       return 0;
+}
+
+/*
+ * PI code:
+ */
+static int refill_pi_state_cache(void)
+{
+       struct futex_pi_state *pi_state;
+
+       if (likely(current->pi_state_cache))
+               return 0;
+
+       pi_state = kmalloc(sizeof(*pi_state), GFP_KERNEL);
+
+       if (!pi_state)
+               return -ENOMEM;
+
+       memset(pi_state, 0, sizeof(*pi_state));
+       INIT_LIST_HEAD(&pi_state->list);
+       /* pi_mutex gets initialized later */
+       pi_state->owner = NULL;
+       atomic_set(&pi_state->refcount, 1);
+
+       current->pi_state_cache = pi_state;
+
+       return 0;
+}
+
+static struct futex_pi_state * alloc_pi_state(void)
+{
+       struct futex_pi_state *pi_state = current->pi_state_cache;
+
+       WARN_ON(!pi_state);
+       current->pi_state_cache = NULL;
+
+       return pi_state;
+}
+
+static void free_pi_state(struct futex_pi_state *pi_state)
+{
+       if (!atomic_dec_and_test(&pi_state->refcount))
+               return;
+
+       /*
+        * If pi_state->owner is NULL, the owner is most probably dying
+        * and has cleaned up the pi_state already
+        */
+       if (pi_state->owner) {
+               spin_lock_irq(&pi_state->owner->pi_lock);
+               list_del_init(&pi_state->list);
+               spin_unlock_irq(&pi_state->owner->pi_lock);
+
+               rt_mutex_proxy_unlock(&pi_state->pi_mutex, pi_state->owner);
+       }
+
+       if (current->pi_state_cache)
+               kfree(pi_state);
+       else {
+               /*
+                * pi_state->list is already empty.
+                * clear pi_state->owner.
+                * refcount is at 0 - put it back to 1.
+                */
+               pi_state->owner = NULL;
+               atomic_set(&pi_state->refcount, 1);
+               current->pi_state_cache = pi_state;
+       }
+}
+
+/*
+ * Look up the task based on what TID userspace gave us.
+ * We dont trust it.
+ */
+static struct task_struct * futex_find_get_task(pid_t pid)
+{
+       struct task_struct *p;
+
+       read_lock(&tasklist_lock);
+       p = find_task_by_pid(pid);
+       if (!p)
+               goto out_unlock;
+       if ((current->euid != p->euid) && (current->euid != p->uid)) {
+               p = NULL;
+               goto out_unlock;
+       }
+       if (p->state == EXIT_ZOMBIE || p->exit_state == EXIT_ZOMBIE) {
+               p = NULL;
+               goto out_unlock;
+       }
+       get_task_struct(p);
+out_unlock:
+       read_unlock(&tasklist_lock);
+
+       return p;
+}
+
+/*
+ * This task is holding PI mutexes at exit time => bad.
+ * Kernel cleans up PI-state, but userspace is likely hosed.
+ * (Robust-futex cleanup is separate and might save the day for userspace.)
+ */
+void exit_pi_state_list(struct task_struct *curr)
+{
+       struct futex_hash_bucket *hb;
+       struct list_head *next, *head = &curr->pi_state_list;
+       struct futex_pi_state *pi_state;
+       union futex_key key;
+
+       /*
+        * We are a ZOMBIE and nobody can enqueue itself on
+        * pi_state_list anymore, but we have to be careful
+        * versus waiters unqueueing themselfs
+        */
+       spin_lock_irq(&curr->pi_lock);
+       while (!list_empty(head)) {
+
+               next = head->next;
+               pi_state = list_entry(next, struct futex_pi_state, list);
+               key = pi_state->key;
+               spin_unlock_irq(&curr->pi_lock);
+
+               hb = hash_futex(&key);
+               spin_lock(&hb->lock);
+
+               spin_lock_irq(&curr->pi_lock);
+               if (head->next != next) {
+                       spin_unlock(&hb->lock);
+                       continue;
+               }
+
+               list_del_init(&pi_state->list);
+
+               WARN_ON(pi_state->owner != curr);
+
+               pi_state->owner = NULL;
+               spin_unlock_irq(&curr->pi_lock);
+
+               rt_mutex_unlock(&pi_state->pi_mutex);
+
+               spin_unlock(&hb->lock);
+
+               spin_lock_irq(&curr->pi_lock);
+       }
+       spin_unlock_irq(&curr->pi_lock);
+}
+
+static int
+lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
+{
+       struct futex_pi_state *pi_state = NULL;
+       struct futex_q *this, *next;
+       struct list_head *head;
+       struct task_struct *p;
+       pid_t pid;
+
+       head = &hb->chain;
+
+       list_for_each_entry_safe(this, next, head, list) {
+               if (match_futex (&this->key, &me->key)) {
+                       /*
+                        * Another waiter already exists - bump up
+                        * the refcount and return its pi_state:
+                        */
+                       pi_state = this->pi_state;
+                       atomic_inc(&pi_state->refcount);
+                       me->pi_state = pi_state;
+
+                       return 0;
+               }
+       }
+
+       /*
+        * We are the first waiter - try to look up the real owner and
+        * attach the new pi_state to it:
+        */
+       pid = uval & FUTEX_TID_MASK;
+       p = futex_find_get_task(pid);
+       if (!p)
+               return -ESRCH;
+
+       pi_state = alloc_pi_state();
+
+       /*
+        * Initialize the pi_mutex in locked state and make 'p'
+        * the owner of it:
+        */
+       rt_mutex_init_proxy_locked(&pi_state->pi_mutex, p);
+
+       /* Store the key for possible exit cleanups: */
+       pi_state->key = me->key;
+
+       spin_lock_irq(&p->pi_lock);
+       list_add(&pi_state->list, &p->pi_state_list);
+       pi_state->owner = p;
+       spin_unlock_irq(&p->pi_lock);
+
+       put_task_struct(p);
+
+       me->pi_state = pi_state;
+
+       return 0;
+}
+
 /*
  * The hash bucket lock must be held when this is called.
  * Afterwards, the futex_q must not be accessed.
@@ -284,16 +542,80 @@ static void wake_futex(struct futex_q *q)
        q->lock_ptr = NULL;
 }
 
+static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
+{
+       struct task_struct *new_owner;
+       struct futex_pi_state *pi_state = this->pi_state;
+       u32 curval, newval;
+
+       if (!pi_state)
+               return -EINVAL;
+
+       new_owner = rt_mutex_next_owner(&pi_state->pi_mutex);
+
+       /*
+        * This happens when we have stolen the lock and the original
+        * pending owner did not enqueue itself back on the rt_mutex.
+        * Thats not a tragedy. We know that way, that a lock waiter
+        * is on the fly. We make the futex_q waiter the pending owner.
+        */
+       if (!new_owner)
+               new_owner = this->task;
+
+       /*
+        * We pass it to the next owner. (The WAITERS bit is always
+        * kept enabled while there is PI state around. We must also
+        * preserve the owner died bit.)
+        */
+       newval = (uval & FUTEX_OWNER_DIED) | FUTEX_WAITERS | new_owner->pid;
+
+       inc_preempt_count();
+       curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+       dec_preempt_count();
+
+       if (curval == -EFAULT)
+               return -EFAULT;
+       if (curval != uval)
+               return -EINVAL;
+
+       list_del_init(&pi_state->owner->pi_state_list);
+       list_add(&pi_state->list, &new_owner->pi_state_list);
+       pi_state->owner = new_owner;
+       rt_mutex_unlock(&pi_state->pi_mutex);
+
+       return 0;
+}
+
+static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
+{
+       u32 oldval;
+
+       /*
+        * There is no waiter, so we unlock the futex. The owner died
+        * bit has not to be preserved here. We are the owner:
+        */
+       inc_preempt_count();
+       oldval = futex_atomic_cmpxchg_inatomic(uaddr, uval, 0);
+       dec_preempt_count();
+
+       if (oldval == -EFAULT)
+               return oldval;
+       if (oldval != uval)
+               return -EAGAIN;
+
+       return 0;
+}
+
 /*
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
  */
-static int futex_wake(unsigned long uaddr, int nr_wake)
+static int futex_wake(u32 __user *uaddr, int nr_wake)
 {
-       union futex_key key;
-       struct futex_hash_bucket *bh;
-       struct list_head *head;
+       struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
+       struct list_head *head;
+       union futex_key key;
        int ret;
 
        down_read(&current->mm->mmap_sem);
@@ -302,19 +624,21 @@ static int futex_wake(unsigned long uaddr, int nr_wake)
        if (unlikely(ret != 0))
                goto out;
 
-       bh = hash_futex(&key);
-       spin_lock(&bh->lock);
-       head = &bh->chain;
+       hb = hash_futex(&key);
+       spin_lock(&hb->lock);
+       head = &hb->chain;
 
        list_for_each_entry_safe(this, next, head, list) {
                if (match_futex (&this->key, &key)) {
+                       if (this->pi_state)
+                               return -EINVAL;
                        wake_futex(this);
                        if (++ret >= nr_wake)
                                break;
                }
        }
 
-       spin_unlock(&bh->lock);
+       spin_unlock(&hb->lock);
 out:
        up_read(&current->mm->mmap_sem);
        return ret;
@@ -324,10 +648,12 @@ out:
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
  */
-static int futex_wake_op(unsigned long uaddr1, unsigned long uaddr2, int nr_wake, int nr_wake2, int op)
+static int
+futex_wake_op(u32 __user *uaddr1, u32 __user *uaddr2,
+             int nr_wake, int nr_wake2, int op)
 {
        union futex_key key1, key2;
-       struct futex_hash_bucket *bh1, *bh2;
+       struct futex_hash_bucket *hb1, *hb2;
        struct list_head *head;
        struct futex_q *this, *next;
        int ret, op_ret, attempt = 0;
@@ -342,27 +668,29 @@ retryfull:
        if (unlikely(ret != 0))
                goto out;
 
-       bh1 = hash_futex(&key1);
-       bh2 = hash_futex(&key2);
+       hb1 = hash_futex(&key1);
+       hb2 = hash_futex(&key2);
 
 retry:
-       if (bh1 < bh2)
-               spin_lock(&bh1->lock);
-       spin_lock(&bh2->lock);
-       if (bh1 > bh2)
-               spin_lock(&bh1->lock);
+       if (hb1 < hb2)
+               spin_lock(&hb1->lock);
+       spin_lock(&hb2->lock);
+       if (hb1 > hb2)
+               spin_lock(&hb1->lock);
 
-       op_ret = futex_atomic_op_inuser(op, (int __user *)uaddr2);
+       op_ret = futex_atomic_op_inuser(op, uaddr2);
        if (unlikely(op_ret < 0)) {
-               int dummy;
+               u32 dummy;
 
-               spin_unlock(&bh1->lock);
-               if (bh1 != bh2)
-                       spin_unlock(&bh2->lock);
+               spin_unlock(&hb1->lock);
+               if (hb1 != hb2)
+                       spin_unlock(&hb2->lock);
 
 #ifndef CONFIG_MMU
-               /* we don't get EFAULT from MMU faults if we don't have an MMU,
-                * but we might get them from range checking */
+               /*
+                * we don't get EFAULT from MMU faults if we don't have an MMU,
+                * but we might get them from range checking
+                */
                ret = op_ret;
                goto out;
 #endif
@@ -372,47 +700,34 @@ retry:
                        goto out;
                }
 
-               /* futex_atomic_op_inuser needs to both read and write
+               /*
+                * futex_atomic_op_inuser needs to both read and write
                 * *(int __user *)uaddr2, but we can't modify it
                 * non-atomically.  Therefore, if get_user below is not
                 * enough, we need to handle the fault ourselves, while
-                * still holding the mmap_sem.  */
+                * still holding the mmap_sem.
+                */
                if (attempt++) {
-                       struct vm_area_struct * vma;
-                       struct mm_struct *mm = current->mm;
-
-                       ret = -EFAULT;
-                       if (attempt >= 2 ||
-                           !(vma = find_vma(mm, uaddr2)) ||
-                           vma->vm_start > uaddr2 ||
-                           !(vma->vm_flags & VM_WRITE))
-                               goto out;
-
-                       switch (handle_mm_fault(mm, vma, uaddr2, 1)) {
-                       case VM_FAULT_MINOR:
-                               current->min_flt++;
-                               break;
-                       case VM_FAULT_MAJOR:
-                               current->maj_flt++;
-                               break;
-                       default:
+                       if (futex_handle_fault((unsigned long)uaddr2,
+                                              attempt))
                                goto out;
-                       }
                        goto retry;
                }
 
-               /* If we would have faulted, release mmap_sem,
-                * fault it in and start all over again.  */
+               /*
+                * If we would have faulted, release mmap_sem,
+                * fault it in and start all over again.
+                */
                up_read(&current->mm->mmap_sem);
 
-               ret = get_user(dummy, (int __user *)uaddr2);
+               ret = get_user(dummy, uaddr2);
                if (ret)
                        return ret;
 
                goto retryfull;
        }
 
-       head = &bh1->chain;
+       head = &hb1->chain;
 
        list_for_each_entry_safe(this, next, head, list) {
                if (match_futex (&this->key, &key1)) {
@@ -423,7 +738,7 @@ retry:
        }
 
        if (op_ret > 0) {
-               head = &bh2->chain;
+               head = &hb2->chain;
 
                op_ret = 0;
                list_for_each_entry_safe(this, next, head, list) {
@@ -436,9 +751,9 @@ retry:
                ret += op_ret;
        }
 
-       spin_unlock(&bh1->lock);
-       if (bh1 != bh2)
-               spin_unlock(&bh2->lock);
+       spin_unlock(&hb1->lock);
+       if (hb1 != hb2)
+               spin_unlock(&hb2->lock);
 out:
        up_read(&current->mm->mmap_sem);
        return ret;
@@ -448,11 +763,11 @@ out:
  * Requeue all waiters hashed on one physical page to another
  * physical page.
  */
-static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
-                        int nr_wake, int nr_requeue, int *valp)
+static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
+                        int nr_wake, int nr_requeue, u32 *cmpval)
 {
        union futex_key key1, key2;
-       struct futex_hash_bucket *bh1, *bh2;
+       struct futex_hash_bucket *hb1, *hb2;
        struct list_head *head1;
        struct futex_q *this, *next;
        int ret, drop_count = 0;
@@ -467,68 +782,72 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
        if (unlikely(ret != 0))
                goto out;
 
-       bh1 = hash_futex(&key1);
-       bh2 = hash_futex(&key2);
+       hb1 = hash_futex(&key1);
+       hb2 = hash_futex(&key2);
 
-       if (bh1 < bh2)
-               spin_lock(&bh1->lock);
-       spin_lock(&bh2->lock);
-       if (bh1 > bh2)
-               spin_lock(&bh1->lock);
+       if (hb1 < hb2)
+               spin_lock(&hb1->lock);
+       spin_lock(&hb2->lock);
+       if (hb1 > hb2)
+               spin_lock(&hb1->lock);
 
-       if (likely(valp != NULL)) {
-               int curval;
+       if (likely(cmpval != NULL)) {
+               u32 curval;
 
-               ret = get_futex_value_locked(&curval, (int __user *)uaddr1);
+               ret = get_futex_value_locked(&curval, uaddr1);
 
                if (unlikely(ret)) {
-                       spin_unlock(&bh1->lock);
-                       if (bh1 != bh2)
-                               spin_unlock(&bh2->lock);
+                       spin_unlock(&hb1->lock);
+                       if (hb1 != hb2)
+                               spin_unlock(&hb2->lock);
 
-                       /* If we would have faulted, release mmap_sem, fault
+                       /*
+                        * If we would have faulted, release mmap_sem, fault
                         * it in and start all over again.
                         */
                        up_read(&current->mm->mmap_sem);
 
-                       ret = get_user(curval, (int __user *)uaddr1);
+                       ret = get_user(curval, uaddr1);
 
                        if (!ret)
                                goto retry;
 
                        return ret;
                }
-               if (curval != *valp) {
+               if (curval != *cmpval) {
                        ret = -EAGAIN;
                        goto out_unlock;
                }
        }
 
-       head1 = &bh1->chain;
+       head1 = &hb1->chain;
        list_for_each_entry_safe(this, next, head1, list) {
                if (!match_futex (&this->key, &key1))
                        continue;
                if (++ret <= nr_wake) {
                        wake_futex(this);
                } else {
-                       list_move_tail(&this->list, &bh2->chain);
-                       this->lock_ptr = &bh2->lock;
+                       /*
+                        * If key1 and key2 hash to the same bucket, no need to
+                        * requeue.
+                        */
+                       if (likely(head1 != &hb2->chain)) {
+                               list_move_tail(&this->list, &hb2->chain);
+                               this->lock_ptr = &hb2->lock;
+                       }
                        this->key = key2;
                        get_key_refs(&key2);
                        drop_count++;
 
                        if (ret - nr_wake >= nr_requeue)
                                break;
-                       /* Make sure to stop if key1 == key2 */
-                       if (head1 == &bh2->chain && head1 != &next->list)
-                               head1 = &this->list;
                }
        }
 
 out_unlock:
-       spin_unlock(&bh1->lock);
-       if (bh1 != bh2)
-               spin_unlock(&bh2->lock);
+       spin_unlock(&hb1->lock);
+       if (hb1 != hb2)
+               spin_unlock(&hb2->lock);
 
        /* drop_key_refs() must be called outside the spinlocks. */
        while (--drop_count >= 0)
@@ -543,7 +862,7 @@ out:
 static inline struct futex_hash_bucket *
 queue_lock(struct futex_q *q, int fd, struct file *filp)
 {
-       struct futex_hash_bucket *bh;
+       struct futex_hash_bucket *hb;
 
        q->fd = fd;
        q->filp = filp;
@@ -551,23 +870,24 @@ queue_lock(struct futex_q *q, int fd, struct file *filp)
        init_waitqueue_head(&q->waiters);
 
        get_key_refs(&q->key);
-       bh = hash_futex(&q->key);
-       q->lock_ptr = &bh->lock;
+       hb = hash_futex(&q->key);
+       q->lock_ptr = &hb->lock;
 
-       spin_lock(&bh->lock);
-       return bh;
+       spin_lock(&hb->lock);
+       return hb;
 }
 
-static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *bh)
+static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
 {
-       list_add_tail(&q->list, &bh->chain);
-       spin_unlock(&bh->lock);
+       list_add_tail(&q->list, &hb->chain);
+       q->task = current;
+       spin_unlock(&hb->lock);
 }
 
 static inline void
-queue_unlock(struct futex_q *q, struct futex_hash_bucket *bh)
+queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
 {
-       spin_unlock(&bh->lock);
+       spin_unlock(&hb->lock);
        drop_key_refs(&q->key);
 }
 
@@ -579,16 +899,17 @@ queue_unlock(struct futex_q *q, struct futex_hash_bucket *bh)
 /* The key must be already stored in q->key. */
 static void queue_me(struct futex_q *q, int fd, struct file *filp)
 {
-       struct futex_hash_bucket *bh;
-       bh = queue_lock(q, fd, filp);
-       __queue_me(q, bh);
+       struct futex_hash_bucket *hb;
+
+       hb = queue_lock(q, fd, filp);
+       __queue_me(q, hb);
 }
 
 /* Return 1 if we were still queued (ie. 0 means we were woken) */
 static int unqueue_me(struct futex_q *q)
 {
-       int ret = 0;
        spinlock_t *lock_ptr;
+       int ret = 0;
 
        /* In the common case we don't take the spinlock, which is nice. */
  retry:
@@ -614,6 +935,9 @@ static int unqueue_me(struct futex_q *q)
                }
                WARN_ON(list_empty(&q->list));
                list_del(&q->list);
+
+               BUG_ON(q->pi_state);
+
                spin_unlock(lock_ptr);
                ret = 1;
        }
@@ -622,21 +946,42 @@ static int unqueue_me(struct futex_q *q)
        return ret;
 }
 
-static int futex_wait(unsigned long uaddr, int val, unsigned long time)
+/*
+ * PI futexes can not be requeued and must remove themself from the
+ * hash bucket. The hash bucket lock is held on entry and dropped here.
+ */
+static void unqueue_me_pi(struct futex_q *q, struct futex_hash_bucket *hb)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int ret, curval;
+       WARN_ON(list_empty(&q->list));
+       list_del(&q->list);
+
+       BUG_ON(!q->pi_state);
+       free_pi_state(q->pi_state);
+       q->pi_state = NULL;
+
+       spin_unlock(&hb->lock);
+
+       drop_key_refs(&q->key);
+}
+
+static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
+{
+       struct task_struct *curr = current;
+       DECLARE_WAITQUEUE(wait, curr);
+       struct futex_hash_bucket *hb;
        struct futex_q q;
-       struct futex_hash_bucket *bh;
+       u32 uval;
+       int ret;
 
+       q.pi_state = NULL;
  retry:
-       down_read(&current->mm->mmap_sem);
+       down_read(&curr->mm->mmap_sem);
 
        ret = get_futex_key(uaddr, &q.key);
        if (unlikely(ret != 0))
                goto out_release_sem;
 
-       bh = queue_lock(&q, -1, NULL);
+       hb = queue_lock(&q, -1, NULL);
 
        /*
         * Access the page AFTER the futex is queued.
@@ -658,37 +1003,35 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
         * We hold the mmap semaphore, so the mapping cannot have changed
         * since we looked it up in get_futex_key.
         */
-
-       ret = get_futex_value_locked(&curval, (int __user *)uaddr);
+       ret = get_futex_value_locked(&uval, uaddr);
 
        if (unlikely(ret)) {
-               queue_unlock(&q, bh);
+               queue_unlock(&q, hb);
 
-               /* If we would have faulted, release mmap_sem, fault it in and
+               /*
+                * If we would have faulted, release mmap_sem, fault it in and
                 * start all over again.
                 */
-               up_read(&current->mm->mmap_sem);
+               up_read(&curr->mm->mmap_sem);
 
-               ret = get_user(curval, (int __user *)uaddr);
+               ret = get_user(uval, uaddr);
 
                if (!ret)
                        goto retry;
                return ret;
        }
-       if (curval != val) {
-               ret = -EWOULDBLOCK;
-               queue_unlock(&q, bh);
-               goto out_release_sem;
-       }
+       ret = -EWOULDBLOCK;
+       if (uval != val)
+               goto out_unlock_release_sem;
 
        /* Only actually queue if *uaddr contained val.  */
-       __queue_me(&q, bh);
+       __queue_me(&q, hb);
 
        /*
         * Now the futex is queued and we have checked the data, we
         * don't want to hold mmap_sem while we sleep.
-        */     
-       up_read(&current->mm->mmap_sem);
+        */
+       up_read(&curr->mm->mmap_sem);
 
        /*
         * There might have been scheduling since the queue_me(), as we
@@ -720,12 +1063,421 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
                return 0;
        if (time == 0)
                return -ETIMEDOUT;
-       /* We expect signal_pending(current), but another thread may
-        * have handled it for us already. */
+       /*
+        * We expect signal_pending(current), but another thread may
+        * have handled it for us already.
+        */
        return -EINTR;
 
+ out_unlock_release_sem:
+       queue_unlock(&q, hb);
+
  out_release_sem:
+       up_read(&curr->mm->mmap_sem);
+       return ret;
+}
+
+/*
+ * Userspace tried a 0 -> TID atomic transition of the futex value
+ * and failed. The kernel side here does the whole locking operation:
+ * if there are waiters then it will block, it does PI, etc. (Due to
+ * races the kernel might see a 0 value of the futex too.)
+ */
+static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock,
+                           struct hrtimer_sleeper *to)
+{
+       struct task_struct *curr = current;
+       struct futex_hash_bucket *hb;
+       u32 uval, newval, curval;
+       struct futex_q q;
+       int ret, attempt = 0;
+
+       if (refill_pi_state_cache())
+               return -ENOMEM;
+
+       q.pi_state = NULL;
+ retry:
+       down_read(&curr->mm->mmap_sem);
+
+       ret = get_futex_key(uaddr, &q.key);
+       if (unlikely(ret != 0))
+               goto out_release_sem;
+
+       hb = queue_lock(&q, -1, NULL);
+
+ retry_locked:
+       /*
+        * To avoid races, we attempt to take the lock here again
+        * (by doing a 0 -> TID atomic cmpxchg), while holding all
+        * the locks. It will most likely not succeed.
+        */
+       newval = current->pid;
+
+       inc_preempt_count();
+       curval = futex_atomic_cmpxchg_inatomic(uaddr, 0, newval);
+       dec_preempt_count();
+
+       if (unlikely(curval == -EFAULT))
+               goto uaddr_faulted;
+
+       /* We own the lock already */
+       if (unlikely((curval & FUTEX_TID_MASK) == current->pid)) {
+               if (!detect && 0)
+                       force_sig(SIGKILL, current);
+               ret = -EDEADLK;
+               goto out_unlock_release_sem;
+       }
+
+       /*
+        * Surprise - we got the lock. Just return
+        * to userspace:
+        */
+       if (unlikely(!curval))
+               goto out_unlock_release_sem;
+
+       uval = curval;
+       newval = uval | FUTEX_WAITERS;
+
+       inc_preempt_count();
+       curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+       dec_preempt_count();
+
+       if (unlikely(curval == -EFAULT))
+               goto uaddr_faulted;
+       if (unlikely(curval != uval))
+               goto retry_locked;
+
+       /*
+        * We dont have the lock. Look up the PI state (or create it if
+        * we are the first waiter):
+        */
+       ret = lookup_pi_state(uval, hb, &q);
+
+       if (unlikely(ret)) {
+               /*
+                * There were no waiters and the owner task lookup
+                * failed. When the OWNER_DIED bit is set, then we
+                * know that this is a robust futex and we actually
+                * take the lock. This is safe as we are protected by
+                * the hash bucket lock. We also set the waiters bit
+                * unconditionally here, to simplify glibc handling of
+                * multiple tasks racing to acquire the lock and
+                * cleanup the problems which were left by the dead
+                * owner.
+                */
+               if (curval & FUTEX_OWNER_DIED) {
+                       uval = newval;
+                       newval = current->pid |
+                               FUTEX_OWNER_DIED | FUTEX_WAITERS;
+
+                       inc_preempt_count();
+                       curval = futex_atomic_cmpxchg_inatomic(uaddr,
+                                                              uval, newval);
+                       dec_preempt_count();
+
+                       if (unlikely(curval == -EFAULT))
+                               goto uaddr_faulted;
+                       if (unlikely(curval != uval))
+                               goto retry_locked;
+                       ret = 0;
+               }
+               goto out_unlock_release_sem;
+       }
+
+       /*
+        * Only actually queue now that the atomic ops are done:
+        */
+       __queue_me(&q, hb);
+
+       /*
+        * Now the futex is queued and we have checked the data, we
+        * don't want to hold mmap_sem while we sleep.
+        */
+       up_read(&curr->mm->mmap_sem);
+
+       WARN_ON(!q.pi_state);
+       /*
+        * Block on the PI mutex:
+        */
+       if (!trylock)
+               ret = rt_mutex_timed_lock(&q.pi_state->pi_mutex, to, 1);
+       else {
+               ret = rt_mutex_trylock(&q.pi_state->pi_mutex);
+               /* Fixup the trylock return value: */
+               ret = ret ? 0 : -EWOULDBLOCK;
+       }
+
+       down_read(&curr->mm->mmap_sem);
+       hb = queue_lock(&q, -1, NULL);
+
+       /*
+        * Got the lock. We might not be the anticipated owner if we
+        * did a lock-steal - fix up the PI-state in that case.
+        */
+       if (!ret && q.pi_state->owner != curr) {
+               u32 newtid = current->pid | FUTEX_WAITERS;
+
+               /* Owner died? */
+               if (q.pi_state->owner != NULL) {
+                       spin_lock_irq(&q.pi_state->owner->pi_lock);
+                       list_del_init(&q.pi_state->list);
+                       spin_unlock_irq(&q.pi_state->owner->pi_lock);
+               } else
+                       newtid |= FUTEX_OWNER_DIED;
+
+               q.pi_state->owner = current;
+
+               spin_lock_irq(&current->pi_lock);
+               list_add(&q.pi_state->list, &current->pi_state_list);
+               spin_unlock_irq(&current->pi_lock);
+
+               /* Unqueue and drop the lock */
+               unqueue_me_pi(&q, hb);
+               up_read(&curr->mm->mmap_sem);
+               /*
+                * We own it, so we have to replace the pending owner
+                * TID. This must be atomic as we have preserve the
+                * owner died bit here.
+                */
+               ret = get_user(uval, uaddr);
+               while (!ret) {
+                       newval = (uval & FUTEX_OWNER_DIED) | newtid;
+                       curval = futex_atomic_cmpxchg_inatomic(uaddr,
+                                                              uval, newval);
+                       if (curval == -EFAULT)
+                               ret = -EFAULT;
+                       if (curval == uval)
+                               break;
+                       uval = curval;
+               }
+       } else {
+               /*
+                * Catch the rare case, where the lock was released
+                * when we were on the way back before we locked
+                * the hash bucket.
+                */
+               if (ret && q.pi_state->owner == curr) {
+                       if (rt_mutex_trylock(&q.pi_state->pi_mutex))
+                               ret = 0;
+               }
+               /* Unqueue and drop the lock */
+               unqueue_me_pi(&q, hb);
+               up_read(&curr->mm->mmap_sem);
+       }
+
+       if (!detect && ret == -EDEADLK && 0)
+               force_sig(SIGKILL, current);
+
+       return ret;
+
+ out_unlock_release_sem:
+       queue_unlock(&q, hb);
+
+ out_release_sem:
+       up_read(&curr->mm->mmap_sem);
+       return ret;
+
+ uaddr_faulted:
+       /*
+        * We have to r/w  *(int __user *)uaddr, but we can't modify it
+        * non-atomically.  Therefore, if get_user below is not
+        * enough, we need to handle the fault ourselves, while
+        * still holding the mmap_sem.
+        */
+       if (attempt++) {
+               if (futex_handle_fault((unsigned long)uaddr, attempt))
+                       goto out_unlock_release_sem;
+
+               goto retry_locked;
+       }
+
+       queue_unlock(&q, hb);
+       up_read(&curr->mm->mmap_sem);
+
+       ret = get_user(uval, uaddr);
+       if (!ret && (uval != -EFAULT))
+               goto retry;
+
+       return ret;
+}
+
+/*
+ * Restart handler
+ */
+static long futex_lock_pi_restart(struct restart_block *restart)
+{
+       struct hrtimer_sleeper timeout, *to = NULL;
+       int ret;
+
+       restart->fn = do_no_restart_syscall;
+
+       if (restart->arg2 || restart->arg3) {
+               to = &timeout;
+               hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS);
+               hrtimer_init_sleeper(to, current);
+               to->timer.expires.tv64 = ((u64)restart->arg1 << 32) |
+                       (u64) restart->arg0;
+       }
+
+       pr_debug("lock_pi restart: %p, %d (%d)\n",
+                (u32 __user *)restart->arg0, current->pid);
+
+       ret = do_futex_lock_pi((u32 __user *)restart->arg0, restart->arg1,
+                              0, to);
+
+       if (ret != -EINTR)
+               return ret;
+
+       restart->fn = futex_lock_pi_restart;
+
+       /* The other values are filled in */
+       return -ERESTART_RESTARTBLOCK;
+}
+
+/*
+ * Called from the syscall entry below.
+ */
+static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
+                        long nsec, int trylock)
+{
+       struct hrtimer_sleeper timeout, *to = NULL;
+       struct restart_block *restart;
+       int ret;
+
+       if (sec != MAX_SCHEDULE_TIMEOUT) {
+               to = &timeout;
+               hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS);
+               hrtimer_init_sleeper(to, current);
+               to->timer.expires = ktime_set(sec, nsec);
+       }
+
+       ret = do_futex_lock_pi(uaddr, detect, trylock, to);
+
+       if (ret != -EINTR)
+               return ret;
+
+       pr_debug("lock_pi interrupted: %p, %d (%d)\n", uaddr, current->pid);
+
+       restart = &current_thread_info()->restart_block;
+       restart->fn = futex_lock_pi_restart;
+       restart->arg0 = (unsigned long) uaddr;
+       restart->arg1 = detect;
+       if (to) {
+               restart->arg2 = to->timer.expires.tv64 & 0xFFFFFFFF;
+               restart->arg3 = to->timer.expires.tv64 >> 32;
+       } else
+               restart->arg2 = restart->arg3 = 0;
+
+       return -ERESTART_RESTARTBLOCK;
+}
+
+/*
+ * Userspace attempted a TID -> 0 atomic transition, and failed.
+ * This is the in-kernel slowpath: we look up the PI state (if any),
+ * and do the rt-mutex unlock.
+ */
+static int futex_unlock_pi(u32 __user *uaddr)
+{
+       struct futex_hash_bucket *hb;
+       struct futex_q *this, *next;
+       u32 uval;
+       struct list_head *head;
+       union futex_key key;
+       int ret, attempt = 0;
+
+retry:
+       if (get_user(uval, uaddr))
+               return -EFAULT;
+       /*
+        * We release only a lock we actually own:
+        */
+       if ((uval & FUTEX_TID_MASK) != current->pid)
+               return -EPERM;
+       /*
+        * First take all the futex related locks:
+        */
+       down_read(&current->mm->mmap_sem);
+
+       ret = get_futex_key(uaddr, &key);
+       if (unlikely(ret != 0))
+               goto out;
+
+       hb = hash_futex(&key);
+       spin_lock(&hb->lock);
+
+retry_locked:
+       /*
+        * To avoid races, try to do the TID -> 0 atomic transition
+        * again. If it succeeds then we can return without waking
+        * anyone else up:
+        */
+       inc_preempt_count();
+       uval = futex_atomic_cmpxchg_inatomic(uaddr, current->pid, 0);
+       dec_preempt_count();
+
+       if (unlikely(uval == -EFAULT))
+               goto pi_faulted;
+       /*
+        * Rare case: we managed to release the lock atomically,
+        * no need to wake anyone else up:
+        */
+       if (unlikely(uval == current->pid))
+               goto out_unlock;
+
+       /*
+        * Ok, other tasks may need to be woken up - check waiters
+        * and do the wakeup if necessary:
+        */
+       head = &hb->chain;
+
+       list_for_each_entry_safe(this, next, head, list) {
+               if (!match_futex (&this->key, &key))
+                       continue;
+               ret = wake_futex_pi(uaddr, uval, this);
+               /*
+                * The atomic access to the futex value
+                * generated a pagefault, so retry the
+                * user-access and the wakeup:
+                */
+               if (ret == -EFAULT)
+                       goto pi_faulted;
+               goto out_unlock;
+       }
+       /*
+        * No waiters - kernel unlocks the futex:
+        */
+       ret = unlock_futex_pi(uaddr, uval);
+       if (ret == -EFAULT)
+               goto pi_faulted;
+
+out_unlock:
+       spin_unlock(&hb->lock);
+out:
        up_read(&current->mm->mmap_sem);
+
+       return ret;
+
+pi_faulted:
+       /*
+        * We have to r/w  *(int __user *)uaddr, but we can't modify it
+        * non-atomically.  Therefore, if get_user below is not
+        * enough, we need to handle the fault ourselves, while
+        * still holding the mmap_sem.
+        */
+       if (attempt++) {
+               if (futex_handle_fault((unsigned long)uaddr, attempt))
+                       goto out_unlock;
+
+               goto retry_locked;
+       }
+
+       spin_unlock(&hb->lock);
+       up_read(&current->mm->mmap_sem);
+
+       ret = get_user(uval, uaddr);
+       if (!ret && (uval != -EFAULT))
+               goto retry;
+
        return ret;
 }
 
@@ -735,6 +1487,7 @@ static int futex_close(struct inode *inode, struct file *filp)
 
        unqueue_me(q);
        kfree(q);
+
        return 0;
 }
 
@@ -766,7 +1519,7 @@ static struct file_operations futex_fops = {
  * Signal allows caller to avoid the race which would occur if they
  * set the sigio stuff up afterwards.
  */
-static int futex_fd(unsigned long uaddr, int signal)
+static int futex_fd(u32 __user *uaddr, int signal)
 {
        struct futex_q *q;
        struct file *filp;
@@ -803,6 +1556,7 @@ static int futex_fd(unsigned long uaddr, int signal)
                err = -ENOMEM;
                goto error;
        }
+       q->pi_state = NULL;
 
        down_read(&current->mm->mmap_sem);
        err = get_futex_key(uaddr, &q->key);
@@ -840,7 +1594,7 @@ error:
  * Implementation: user-space maintains a per-thread list of locks it
  * is holding. Upon do_exit(), the kernel carefully walks this list,
  * and marks all locks that are owned by this thread with the
- * FUTEX_OWNER_DEAD bit, and wakes up a waiter (if any). The list is
+ * FUTEX_OWNER_DIED bit, and wakes up a waiter (if any). The list is
  * always manipulated with the lock held, so the list is private and
  * per-thread. Userspace also maintains a per-thread 'list_op_pending'
  * field, to allow the kernel to clean up if the thread dies after
@@ -915,7 +1669,7 @@ err_unlock:
  */
 int handle_futex_death(u32 __user *uaddr, struct task_struct *curr)
 {
-       u32 uval;
+       u32 uval, nval;
 
 retry:
        if (get_user(uval, uaddr))
@@ -932,12 +1686,16 @@ retry:
                 * thread-death.) The rest of the cleanup is done in
                 * userspace.
                 */
-               if (futex_atomic_cmpxchg_inatomic(uaddr, uval,
-                                        uval | FUTEX_OWNER_DIED) != uval)
+               nval = futex_atomic_cmpxchg_inatomic(uaddr, uval,
+                                                    uval | FUTEX_OWNER_DIED);
+               if (nval == -EFAULT)
+                       return -1;
+
+               if (nval != uval)
                        goto retry;
 
                if (uval & FUTEX_WAITERS)
-                       futex_wake((unsigned long)uaddr, 1);
+                       futex_wake(uaddr, 1);
        }
        return 0;
 }
@@ -978,7 +1736,7 @@ void exit_robust_list(struct task_struct *curr)
        while (entry != &head->list) {
                /*
                 * A pending lock might already be on the list, so
-                * dont process it twice:
+                * don't process it twice:
                 */
                if (entry != pending)
                        if (handle_futex_death((void *)entry + futex_offset,
@@ -999,8 +1757,8 @@ void exit_robust_list(struct task_struct *curr)
        }
 }
 
-long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
-               unsigned long uaddr2, int val2, int val3)
+long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+               u32 __user *uaddr2, u32 val2, u32 val3)
 {
        int ret;
 
@@ -1024,6 +1782,15 @@ long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
        case FUTEX_WAKE_OP:
                ret = futex_wake_op(uaddr, uaddr2, val, val2, val3);
                break;
+       case FUTEX_LOCK_PI:
+               ret = futex_lock_pi(uaddr, val, timeout, val2, 0);
+               break;
+       case FUTEX_UNLOCK_PI:
+               ret = futex_unlock_pi(uaddr);
+               break;
+       case FUTEX_TRYLOCK_PI:
+               ret = futex_lock_pi(uaddr, 0, timeout, val2, 1);
+               break;
        default:
                ret = -ENOSYS;
        }
@@ -1031,29 +1798,33 @@ long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
 }
 
 
-asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
+asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
                          struct timespec __user *utime, u32 __user *uaddr2,
-                         int val3)
+                         u32 val3)
 {
        struct timespec t;
        unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
-       int val2 = 0;
+       u32 val2 = 0;
 
-       if (utime && (op == FUTEX_WAIT)) {
+       if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
                if (copy_from_user(&t, utime, sizeof(t)) != 0)
                        return -EFAULT;
                if (!timespec_valid(&t))
                        return -EINVAL;
-               timeout = timespec_to_jiffies(&t) + 1;
+               if (op == FUTEX_WAIT)
+                       timeout = timespec_to_jiffies(&t) + 1;
+               else {
+                       timeout = t.tv_sec;
+                       val2 = t.tv_nsec;
+               }
        }
        /*
         * requeue parameter in 'utime' if op == FUTEX_REQUEUE.
         */
-       if (op >= FUTEX_REQUEUE)
-               val2 = (int) (unsigned long) utime;
+       if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
+               val2 = (u32) (unsigned long) utime;
 
-       return do_futex((unsigned long)uaddr, op, val, timeout,
-                       (unsigned long)uaddr2, val2, val3);
+       return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
 }
 
 static int futexfs_get_sb(struct file_system_type *fs_type,
index 1ab6a0ea3d14776e9a84d3b8af71ffd418da5498..d1d92b441fb7d7a327f229def2db99d4359063ee 100644 (file)
@@ -129,16 +129,20 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
        unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
        int val2 = 0;
 
-       if (utime && (op == FUTEX_WAIT)) {
+       if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
                if (get_compat_timespec(&t, utime))
                        return -EFAULT;
                if (!timespec_valid(&t))
                        return -EINVAL;
-               timeout = timespec_to_jiffies(&t) + 1;
+               if (op == FUTEX_WAIT)
+                       timeout = timespec_to_jiffies(&t) + 1;
+               else {
+                       timeout = t.tv_sec;
+                       val2 = t.tv_nsec;
+               }
        }
-       if (op >= FUTEX_REQUEUE)
+       if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
                val2 = (int) (unsigned long) utime;
 
-       return do_futex((unsigned long)uaddr, op, val, timeout,
-                       (unsigned long)uaddr2, val2, val3);
+       return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
 }
index 55601b3ce60e92717fa6c6d771bc1a67dea7a03e..8d3dc29ef41ae1fb616d4d8765cb1d077c862852 100644 (file)
@@ -833,7 +833,7 @@ static void migrate_hrtimers(int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int hrtimer_cpu_notify(struct notifier_block *self,
+static int __devinit hrtimer_cpu_notify(struct notifier_block *self,
                                        unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
@@ -857,7 +857,7 @@ static int hrtimer_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block hrtimers_nb = {
+static struct notifier_block __devinitdata hrtimers_nb = {
        .notifier_call = hrtimer_cpu_notify,
 };
 
index 9f77f50d814317409f1ed02ce73372bfb428c99f..1dab0ac3f79782a129dc5736ac8d838ee9d4ba01 100644 (file)
@@ -1,5 +1,5 @@
 
-obj-y := handle.o manage.o spurious.o
+obj-y := handle.o manage.o spurious.o resend.o chip.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
index 3467097ca61ae476a74a7eb1519950acc9a8ebcf..533068cfb607fad10202210b916909efd314cbb7 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
+#include "internals.h"
+
 /*
  * Autodetection depends on the fact that any interrupt that
  * comes in on to an unassigned handler will get stuck with
  * "IRQ_WAITING" cleared and the interrupt disabled.
  */
-static DECLARE_MUTEX(probe_sem);
+static DEFINE_MUTEX(probing_active);
 
 /**
  *     probe_irq_on    - begin an interrupt autodetect
@@ -27,11 +29,11 @@ static DECLARE_MUTEX(probe_sem);
  */
 unsigned long probe_irq_on(void)
 {
-       unsigned long val;
-       irq_desc_t *desc;
+       struct irq_desc *desc;
+       unsigned long mask;
        unsigned int i;
 
-       down(&probe_sem);
+       mutex_lock(&probing_active);
        /*
         * something may have generated an irq long ago and we want to
         * flush such a longstanding irq before considering it as spurious.
@@ -40,8 +42,21 @@ unsigned long probe_irq_on(void)
                desc = irq_desc + i;
 
                spin_lock_irq(&desc->lock);
-               if (!irq_desc[i].action)
-                       irq_desc[i].handler->startup(i);
+               if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
+                       /*
+                        * An old-style architecture might still have
+                        * the handle_bad_irq handler there:
+                        */
+                       compat_irq_chip_set_default_handler(desc);
+
+                       /*
+                        * Some chips need to know about probing in
+                        * progress:
+                        */
+                       if (desc->chip->set_type)
+                               desc->chip->set_type(i, IRQ_TYPE_PROBE);
+                       desc->chip->startup(i);
+               }
                spin_unlock_irq(&desc->lock);
        }
 
@@ -57,9 +72,9 @@ unsigned long probe_irq_on(void)
                desc = irq_desc + i;
 
                spin_lock_irq(&desc->lock);
-               if (!desc->action) {
+               if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
                        desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
-                       if (desc->handler->startup(i))
+                       if (desc->chip->startup(i))
                                desc->status |= IRQ_PENDING;
                }
                spin_unlock_irq(&desc->lock);
@@ -73,11 +88,11 @@ unsigned long probe_irq_on(void)
        /*
         * Now filter out any obviously spurious interrupts
         */
-       val = 0;
+       mask = 0;
        for (i = 0; i < NR_IRQS; i++) {
-               irq_desc_t *desc = irq_desc + i;
                unsigned int status;
 
+               desc = irq_desc + i;
                spin_lock_irq(&desc->lock);
                status = desc->status;
 
@@ -85,17 +100,16 @@ unsigned long probe_irq_on(void)
                        /* It triggered already - consider it spurious. */
                        if (!(status & IRQ_WAITING)) {
                                desc->status = status & ~IRQ_AUTODETECT;
-                               desc->handler->shutdown(i);
+                               desc->chip->shutdown(i);
                        } else
                                if (i < 32)
-                                       val |= 1 << i;
+                                       mask |= 1 << i;
                }
                spin_unlock_irq(&desc->lock);
        }
 
-       return val;
+       return mask;
 }
-
 EXPORT_SYMBOL(probe_irq_on);
 
 /**
@@ -117,7 +131,7 @@ unsigned int probe_irq_mask(unsigned long val)
 
        mask = 0;
        for (i = 0; i < NR_IRQS; i++) {
-               irq_desc_t *desc = irq_desc + i;
+               struct irq_desc *desc = irq_desc + i;
                unsigned int status;
 
                spin_lock_irq(&desc->lock);
@@ -128,11 +142,11 @@ unsigned int probe_irq_mask(unsigned long val)
                                mask |= 1 << i;
 
                        desc->status = status & ~IRQ_AUTODETECT;
-                       desc->handler->shutdown(i);
+                       desc->chip->shutdown(i);
                }
                spin_unlock_irq(&desc->lock);
        }
-       up(&probe_sem);
+       mutex_unlock(&probing_active);
 
        return mask & val;
 }
@@ -160,7 +174,7 @@ int probe_irq_off(unsigned long val)
        int i, irq_found = 0, nr_irqs = 0;
 
        for (i = 0; i < NR_IRQS; i++) {
-               irq_desc_t *desc = irq_desc + i;
+               struct irq_desc *desc = irq_desc + i;
                unsigned int status;
 
                spin_lock_irq(&desc->lock);
@@ -173,16 +187,16 @@ int probe_irq_off(unsigned long val)
                                nr_irqs++;
                        }
                        desc->status = status & ~IRQ_AUTODETECT;
-                       desc->handler->shutdown(i);
+                       desc->chip->shutdown(i);
                }
                spin_unlock_irq(&desc->lock);
        }
-       up(&probe_sem);
+       mutex_unlock(&probing_active);
 
        if (nr_irqs > 1)
                irq_found = -irq_found;
+
        return irq_found;
 }
-
 EXPORT_SYMBOL(probe_irq_off);
 
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
new file mode 100644 (file)
index 0000000..4a0952d
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * linux/kernel/irq/chip.c
+ *
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006, Thomas Gleixner, Russell King
+ *
+ * This file contains the core interrupt handling code, for irq-chip
+ * based architectures.
+ *
+ * Detailed information is available in Documentation/DocBook/genericirq
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include "internals.h"
+
+/**
+ *     set_irq_chip - set the irq chip for an irq
+ *     @irq:   irq number
+ *     @chip:  pointer to irq chip description structure
+ */
+int set_irq_chip(unsigned int irq, struct irq_chip *chip)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       if (!chip)
+               chip = &no_irq_chip;
+
+       desc = irq_desc + irq;
+       spin_lock_irqsave(&desc->lock, flags);
+       irq_chip_set_defaults(chip);
+       desc->chip = chip;
+       /*
+        * For compatibility only:
+        */
+       desc->chip = chip;
+       spin_unlock_irqrestore(&desc->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(set_irq_chip);
+
+/**
+ *     set_irq_type - set the irq type for an irq
+ *     @irq:   irq number
+ *     @type:  interrupt type - see include/linux/interrupt.h
+ */
+int set_irq_type(unsigned int irq, unsigned int type)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+       int ret = -ENXIO;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
+               return -ENODEV;
+       }
+
+       desc = irq_desc + irq;
+       if (desc->chip->set_type) {
+               spin_lock_irqsave(&desc->lock, flags);
+               ret = desc->chip->set_type(irq, type);
+               spin_unlock_irqrestore(&desc->lock, flags);
+       }
+       return ret;
+}
+EXPORT_SYMBOL(set_irq_type);
+
+/**
+ *     set_irq_data - set irq type data for an irq
+ *     @irq:   Interrupt number
+ *     @data:  Pointer to interrupt specific data
+ *
+ *     Set the hardware irq controller data for an irq
+ */
+int set_irq_data(unsigned int irq, void *data)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR
+                      "Trying to install controller data for IRQ%d\n", irq);
+               return -EINVAL;
+       }
+
+       desc = irq_desc + irq;
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->handler_data = data;
+       spin_unlock_irqrestore(&desc->lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL(set_irq_data);
+
+/**
+ *     set_irq_chip_data - set irq chip data for an irq
+ *     @irq:   Interrupt number
+ *     @data:  Pointer to chip specific data
+ *
+ *     Set the hardware irq chip data for an irq
+ */
+int set_irq_chip_data(unsigned int irq, void *data)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS || !desc->chip) {
+               printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->chip_data = data;
+       spin_unlock_irqrestore(&desc->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(set_irq_chip_data);
+
+/*
+ * default enable function
+ */
+static void default_enable(unsigned int irq)
+{
+       struct irq_desc *desc = irq_desc + irq;
+
+       desc->chip->unmask(irq);
+       desc->status &= ~IRQ_MASKED;
+}
+
+/*
+ * default disable function
+ */
+static void default_disable(unsigned int irq)
+{
+       struct irq_desc *desc = irq_desc + irq;
+
+       if (!(desc->status & IRQ_DELAYED_DISABLE))
+               irq_desc[irq].chip->mask(irq);
+}
+
+/*
+ * default startup function
+ */
+static unsigned int default_startup(unsigned int irq)
+{
+       irq_desc[irq].chip->enable(irq);
+
+       return 0;
+}
+
+/*
+ * Fixup enable/disable function pointers
+ */
+void irq_chip_set_defaults(struct irq_chip *chip)
+{
+       if (!chip->enable)
+               chip->enable = default_enable;
+       if (!chip->disable)
+               chip->disable = default_disable;
+       if (!chip->startup)
+               chip->startup = default_startup;
+       if (!chip->shutdown)
+               chip->shutdown = chip->disable;
+       if (!chip->name)
+               chip->name = chip->typename;
+}
+
+static inline void mask_ack_irq(struct irq_desc *desc, int irq)
+{
+       if (desc->chip->mask_ack)
+               desc->chip->mask_ack(irq);
+       else {
+               desc->chip->mask(irq);
+               desc->chip->ack(irq);
+       }
+}
+
+/**
+ *     handle_simple_irq - Simple and software-decoded IRQs.
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Simple interrupts are either sent from a demultiplexing interrupt
+ *     handler or come from hardware, where no interrupt hardware control
+ *     is necessary.
+ *
+ *     Note: The caller is expected to handle the ack, clear, mask and
+ *     unmask issues if necessary.
+ */
+void fastcall
+handle_simple_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       struct irqaction *action;
+       irqreturn_t action_ret;
+       const unsigned int cpu = smp_processor_id();
+
+       spin_lock(&desc->lock);
+
+       if (unlikely(desc->status & IRQ_INPROGRESS))
+               goto out_unlock;
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       kstat_cpu(cpu).irqs[irq]++;
+
+       action = desc->action;
+       if (unlikely(!action || (desc->status & IRQ_DISABLED)))
+               goto out_unlock;
+
+       desc->status |= IRQ_INPROGRESS;
+       spin_unlock(&desc->lock);
+
+       action_ret = handle_IRQ_event(irq, regs, action);
+       if (!noirqdebug)
+               note_interrupt(irq, desc, action_ret, regs);
+
+       spin_lock(&desc->lock);
+       desc->status &= ~IRQ_INPROGRESS;
+out_unlock:
+       spin_unlock(&desc->lock);
+}
+
+/**
+ *     handle_level_irq - Level type irq handler
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Level type interrupts are active as long as the hardware line has
+ *     the active level. This may require to mask the interrupt and unmask
+ *     it after the associated handler has acknowledged the device, so the
+ *     interrupt line is back to inactive.
+ */
+void fastcall
+handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       unsigned int cpu = smp_processor_id();
+       struct irqaction *action;
+       irqreturn_t action_ret;
+
+       spin_lock(&desc->lock);
+       mask_ack_irq(desc, irq);
+
+       if (unlikely(desc->status & IRQ_INPROGRESS))
+               goto out;
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       kstat_cpu(cpu).irqs[irq]++;
+
+       /*
+        * If its disabled or no action available
+        * keep it masked and get out of here
+        */
+       action = desc->action;
+       if (unlikely(!action || (desc->status & IRQ_DISABLED)))
+               goto out;
+
+       desc->status |= IRQ_INPROGRESS;
+       spin_unlock(&desc->lock);
+
+       action_ret = handle_IRQ_event(irq, regs, action);
+       if (!noirqdebug)
+               note_interrupt(irq, desc, action_ret, regs);
+
+       spin_lock(&desc->lock);
+       desc->status &= ~IRQ_INPROGRESS;
+out:
+       if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+               desc->chip->unmask(irq);
+       spin_unlock(&desc->lock);
+}
+
+/**
+ *     handle_fasteoi_irq - irq handler for transparent controllers
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Only a single callback will be issued to the chip: an ->eoi()
+ *     call when the interrupt has been serviced. This enables support
+ *     for modern forms of interrupt handlers, which handle the flow
+ *     details in hardware, transparently.
+ */
+void fastcall
+handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
+                  struct pt_regs *regs)
+{
+       unsigned int cpu = smp_processor_id();
+       struct irqaction *action;
+       irqreturn_t action_ret;
+
+       spin_lock(&desc->lock);
+
+       if (unlikely(desc->status & IRQ_INPROGRESS))
+               goto out;
+
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       kstat_cpu(cpu).irqs[irq]++;
+
+       /*
+        * If its disabled or no action available
+        * keep it masked and get out of here
+        */
+       action = desc->action;
+       if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
+               desc->status |= IRQ_PENDING;
+               goto out;
+       }
+
+       desc->status |= IRQ_INPROGRESS;
+       desc->status &= ~IRQ_PENDING;
+       spin_unlock(&desc->lock);
+
+       action_ret = handle_IRQ_event(irq, regs, action);
+       if (!noirqdebug)
+               note_interrupt(irq, desc, action_ret, regs);
+
+       spin_lock(&desc->lock);
+       desc->status &= ~IRQ_INPROGRESS;
+out:
+       desc->chip->eoi(irq);
+
+       spin_unlock(&desc->lock);
+}
+
+/**
+ *     handle_edge_irq - edge type IRQ handler
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Interrupt occures on the falling and/or rising edge of a hardware
+ *     signal. The occurence is latched into the irq controller hardware
+ *     and must be acked in order to be reenabled. After the ack another
+ *     interrupt can happen on the same source even before the first one
+ *     is handled by the assosiacted event handler. If this happens it
+ *     might be necessary to disable (mask) the interrupt depending on the
+ *     controller hardware. This requires to reenable the interrupt inside
+ *     of the loop which handles the interrupts which have arrived while
+ *     the handler was running. If all pending interrupts are handled, the
+ *     loop is left.
+ */
+void fastcall
+handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       const unsigned int cpu = smp_processor_id();
+
+       spin_lock(&desc->lock);
+
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+
+       /*
+        * If we're currently running this IRQ, or its disabled,
+        * we shouldn't process the IRQ. Mark it pending, handle
+        * the necessary masking and go out
+        */
+       if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
+                   !desc->action)) {
+               desc->status |= (IRQ_PENDING | IRQ_MASKED);
+               mask_ack_irq(desc, irq);
+               goto out_unlock;
+       }
+
+       kstat_cpu(cpu).irqs[irq]++;
+
+       /* Start handling the irq */
+       desc->chip->ack(irq);
+
+       /* Mark the IRQ currently in progress.*/
+       desc->status |= IRQ_INPROGRESS;
+
+       do {
+               struct irqaction *action = desc->action;
+               irqreturn_t action_ret;
+
+               if (unlikely(!action)) {
+                       desc->chip->mask(irq);
+                       goto out_unlock;
+               }
+
+               /*
+                * When another irq arrived while we were handling
+                * one, we could have masked the irq.
+                * Renable it, if it was not disabled in meantime.
+                */
+               if (unlikely((desc->status &
+                              (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
+                             (IRQ_PENDING | IRQ_MASKED))) {
+                       desc->chip->unmask(irq);
+                       desc->status &= ~IRQ_MASKED;
+               }
+
+               desc->status &= ~IRQ_PENDING;
+               spin_unlock(&desc->lock);
+               action_ret = handle_IRQ_event(irq, regs, action);
+               if (!noirqdebug)
+                       note_interrupt(irq, desc, action_ret, regs);
+               spin_lock(&desc->lock);
+
+       } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
+
+       desc->status &= ~IRQ_INPROGRESS;
+out_unlock:
+       spin_unlock(&desc->lock);
+}
+
+#ifdef CONFIG_SMP
+/**
+ *     handle_percpu_IRQ - Per CPU local irq handler
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Per CPU interrupts on SMP machines without locking requirements
+ */
+void fastcall
+handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       irqreturn_t action_ret;
+
+       kstat_this_cpu.irqs[irq]++;
+
+       if (desc->chip->ack)
+               desc->chip->ack(irq);
+
+       action_ret = handle_IRQ_event(irq, regs, desc->action);
+       if (!noirqdebug)
+               note_interrupt(irq, desc, action_ret, regs);
+
+       if (desc->chip->eoi)
+               desc->chip->eoi(irq);
+}
+
+#endif /* CONFIG_SMP */
+
+void
+__set_irq_handler(unsigned int irq,
+                 void fastcall (*handle)(unsigned int, irq_desc_t *,
+                                         struct pt_regs *),
+                 int is_chained)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR
+                      "Trying to install type control for IRQ%d\n", irq);
+               return;
+       }
+
+       desc = irq_desc + irq;
+
+       if (!handle)
+               handle = handle_bad_irq;
+
+       if (is_chained && desc->chip == &no_irq_chip)
+               printk(KERN_WARNING "Trying to install "
+                      "chained interrupt type for IRQ%d\n", irq);
+
+       spin_lock_irqsave(&desc->lock, flags);
+
+       /* Uninstall? */
+       if (handle == handle_bad_irq) {
+               if (desc->chip != &no_irq_chip) {
+                       desc->chip->mask(irq);
+                       desc->chip->ack(irq);
+               }
+               desc->status |= IRQ_DISABLED;
+               desc->depth = 1;
+       }
+       desc->handle_irq = handle;
+
+       if (handle != handle_bad_irq && is_chained) {
+               desc->status &= ~IRQ_DISABLED;
+               desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
+               desc->depth = 0;
+               desc->chip->unmask(irq);
+       }
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+void
+set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
+                        void fastcall (*handle)(unsigned int,
+                                                struct irq_desc *,
+                                                struct pt_regs *))
+{
+       set_irq_chip(irq, chip);
+       __set_irq_handler(irq, handle, 0);
+}
+
+/*
+ * Get a descriptive string for the highlevel handler, for
+ * /proc/interrupts output:
+ */
+const char *
+handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                       struct pt_regs *))
+{
+       if (handle == handle_level_irq)
+               return "level  ";
+       if (handle == handle_fasteoi_irq)
+               return "fasteoi";
+       if (handle == handle_edge_irq)
+               return "edge   ";
+       if (handle == handle_simple_irq)
+               return "simple ";
+#ifdef CONFIG_SMP
+       if (handle == handle_percpu_irq)
+               return "percpu ";
+#endif
+       if (handle == handle_bad_irq)
+               return "bad    ";
+
+       return NULL;
+}
index 0f6530117105c6f000668c3bcae8ca8be1b6e4bd..5a360dd4331b0505a6f4e54c0c26317f23d3c189 100644 (file)
@@ -1,9 +1,13 @@
 /*
  * linux/kernel/irq/handle.c
  *
- * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006, Thomas Gleixner, Russell King
  *
  * This file contains the core interrupt handling code.
+ *
+ * Detailed information is available in Documentation/DocBook/genericirq
+ *
  */
 
 #include <linux/irq.h>
 
 #include "internals.h"
 
+/**
+ * handle_bad_irq - handle spurious and unhandled irqs
+ */
+void fastcall
+handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       print_irq_desc(irq, desc);
+       kstat_this_cpu.irqs[irq]++;
+       ack_bad_irq(irq);
+}
+
 /*
  * Linux has a controller-independent interrupt architecture.
  * Every controller has a 'controller-template', that is used
  * by the main code to do the right thing. Each driver-visible
- * interrupt source is transparently wired to the apropriate
+ * interrupt source is transparently wired to the appropriate
  * controller. Thus drivers need not be aware of the
  * interrupt-controller.
  *
  *
  * Controller mappings for all interrupt sources:
  */
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
+struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned = {
        [0 ... NR_IRQS-1] = {
                .status = IRQ_DISABLED,
-               .handler = &no_irq_type,
-               .lock = SPIN_LOCK_UNLOCKED
+               .chip = &no_irq_chip,
+               .handle_irq = handle_bad_irq,
+               .depth = 1,
+               .lock = SPIN_LOCK_UNLOCKED,
+#ifdef CONFIG_SMP
+               .affinity = CPU_MASK_ALL
+#endif
        }
 };
 
 /*
- * Generic 'no controller' code
+ * What should we do if we get a hw irq event on an illegal vector?
+ * Each architecture has to answer this themself.
  */
-static void end_none(unsigned int irq) { }
-static void enable_none(unsigned int irq) { }
-static void disable_none(unsigned int irq) { }
-static void shutdown_none(unsigned int irq) { }
-static unsigned int startup_none(unsigned int irq) { return 0; }
-
-static void ack_none(unsigned int irq)
+static void ack_bad(unsigned int irq)
 {
-       /*
-        * 'what should we do if we get a hw irq event on an illegal vector'.
-        * each architecture has to answer this themself.
-        */
+       print_irq_desc(irq, irq_desc + irq);
        ack_bad_irq(irq);
 }
 
-struct hw_interrupt_type no_irq_type = {
-       .typename =     "none",
-       .startup =      startup_none,
-       .shutdown =     shutdown_none,
-       .enable =       enable_none,
-       .disable =      disable_none,
-       .ack =          ack_none,
-       .end =          end_none,
-       .set_affinity = NULL
+/*
+ * NOP functions
+ */
+static void noop(unsigned int irq)
+{
+}
+
+static unsigned int noop_ret(unsigned int irq)
+{
+       return 0;
+}
+
+/*
+ * Generic no controller implementation
+ */
+struct irq_chip no_irq_chip = {
+       .name           = "none",
+       .startup        = noop_ret,
+       .shutdown       = noop,
+       .enable         = noop,
+       .disable        = noop,
+       .ack            = ack_bad,
+       .end            = noop,
 };
 
 /*
@@ -73,11 +99,16 @@ irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
        return IRQ_NONE;
 }
 
-/*
- * Have got an event to handle:
+/**
+ * handle_IRQ_event - irq action chain handler
+ * @irq:       the interrupt number
+ * @regs:      pointer to a register structure
+ * @action:    the interrupt action chain for this irq
+ *
+ * Handles the action chain of an irq event
  */
-fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
-                               struct irqaction *action)
+irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+                            struct irqaction *action)
 {
        irqreturn_t ret, retval = IRQ_NONE;
        unsigned int status = 0;
@@ -100,15 +131,22 @@ fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
        return retval;
 }
 
-/*
- * do_IRQ handles all normal device IRQ's (the special
+/**
+ * __do_IRQ - original all in one highlevel IRQ handler
+ * @irq:       the interrupt number
+ * @regs:      pointer to a register structure
+ *
+ * __do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
  * handlers).
+ *
+ * This is the original x86 implementation which is used for every
+ * interrupt type.
  */
 fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
 {
-       irq_desc_t *desc = irq_desc + irq;
-       struct irqaction * action;
+       struct irq_desc *desc = irq_desc + irq;
+       struct irqaction *action;
        unsigned int status;
 
        kstat_this_cpu.irqs[irq]++;
@@ -118,16 +156,16 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
                /*
                 * No locking required for CPU-local interrupts:
                 */
-               if (desc->handler->ack)
-                       desc->handler->ack(irq);
+               if (desc->chip->ack)
+                       desc->chip->ack(irq);
                action_ret = handle_IRQ_event(irq, regs, desc->action);
-               desc->handler->end(irq);
+               desc->chip->end(irq);
                return 1;
        }
 
        spin_lock(&desc->lock);
-       if (desc->handler->ack)
-               desc->handler->ack(irq);
+       if (desc->chip->ack)
+               desc->chip->ack(irq);
        /*
         * REPLAY is when Linux resends an IRQ that was dropped earlier
         * WAITING is used by probe to mark irqs that are being tested
@@ -187,7 +225,7 @@ out:
         * The ->end() handler has to deal with interrupts which got
         * disabled while the handler was running.
         */
-       desc->handler->end(irq);
+       desc->chip->end(irq);
        spin_unlock(&desc->lock);
 
        return 1;
index 46feba630266eedb5ac55b83d5dfdbf86b3c7d0c..08a849a224475102084ca807de6861b6ab7286b5 100644 (file)
@@ -4,6 +4,12 @@
 
 extern int noirqdebug;
 
+/* Set default functions for irq_chip structures: */
+extern void irq_chip_set_defaults(struct irq_chip *chip);
+
+/* Set default handler: */
+extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
+
 #ifdef CONFIG_PROC_FS
 extern void register_irq_proc(unsigned int irq);
 extern void register_handler_proc(unsigned int irq, struct irqaction *action);
@@ -16,3 +22,43 @@ static inline void unregister_handler_proc(unsigned int irq,
                                           struct irqaction *action) { }
 #endif
 
+/*
+ * Debugging printout:
+ */
+
+#include <linux/kallsyms.h>
+
+#define P(f) if (desc->status & f) printk("%14s set\n", #f)
+
+static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc)
+{
+       printk("irq %d, desc: %p, depth: %d, count: %d, unhandled: %d\n",
+               irq, desc, desc->depth, desc->irq_count, desc->irqs_unhandled);
+       printk("->handle_irq():  %p, ", desc->handle_irq);
+       print_symbol("%s\n", (unsigned long)desc->handle_irq);
+       printk("->chip(): %p, ", desc->chip);
+       print_symbol("%s\n", (unsigned long)desc->chip);
+       printk("->action(): %p\n", desc->action);
+       if (desc->action) {
+               printk("->action->handler(): %p, ", desc->action->handler);
+               print_symbol("%s\n", (unsigned long)desc->action->handler);
+       }
+
+       P(IRQ_INPROGRESS);
+       P(IRQ_DISABLED);
+       P(IRQ_PENDING);
+       P(IRQ_REPLAY);
+       P(IRQ_AUTODETECT);
+       P(IRQ_WAITING);
+       P(IRQ_LEVEL);
+       P(IRQ_MASKED);
+#ifdef CONFIG_IRQ_PER_CPU
+       P(IRQ_PER_CPU);
+#endif
+       P(IRQ_NOPROBE);
+       P(IRQ_NOREQUEST);
+       P(IRQ_NOAUTOEN);
+}
+
+#undef P
+
index 1279e3499534d490212053812a64671a59b3132d..9eb1d518ee1c8dc8da68f7903cd207482352e8fa 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * linux/kernel/irq/manage.c
  *
- * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006 Thomas Gleixner
  *
  * This file contains driver APIs to the irq subsystem.
  */
 
 #ifdef CONFIG_SMP
 
-cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
-
-#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
-cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
-#endif
-
 /**
  *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
  *     @irq: interrupt number to wait for
@@ -42,7 +37,6 @@ void synchronize_irq(unsigned int irq)
        while (desc->status & IRQ_INPROGRESS)
                cpu_relax();
 }
-
 EXPORT_SYMBOL(synchronize_irq);
 
 #endif
@@ -60,7 +54,7 @@ EXPORT_SYMBOL(synchronize_irq);
  */
 void disable_irq_nosync(unsigned int irq)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
 
        if (irq >= NR_IRQS)
@@ -69,11 +63,10 @@ void disable_irq_nosync(unsigned int irq)
        spin_lock_irqsave(&desc->lock, flags);
        if (!desc->depth++) {
                desc->status |= IRQ_DISABLED;
-               desc->handler->disable(irq);
+               desc->chip->disable(irq);
        }
        spin_unlock_irqrestore(&desc->lock, flags);
 }
-
 EXPORT_SYMBOL(disable_irq_nosync);
 
 /**
@@ -90,7 +83,7 @@ EXPORT_SYMBOL(disable_irq_nosync);
  */
 void disable_irq(unsigned int irq)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
 
        if (irq >= NR_IRQS)
                return;
@@ -99,7 +92,6 @@ void disable_irq(unsigned int irq)
        if (desc->action)
                synchronize_irq(irq);
 }
-
 EXPORT_SYMBOL(disable_irq);
 
 /**
@@ -114,7 +106,7 @@ EXPORT_SYMBOL(disable_irq);
  */
 void enable_irq(unsigned int irq)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
 
        if (irq >= NR_IRQS)
@@ -123,17 +115,15 @@ void enable_irq(unsigned int irq)
        spin_lock_irqsave(&desc->lock, flags);
        switch (desc->depth) {
        case 0:
+               printk(KERN_WARNING "Unablanced enable_irq(%d)\n", irq);
                WARN_ON(1);
                break;
        case 1: {
                unsigned int status = desc->status & ~IRQ_DISABLED;
 
-               desc->status = status;
-               if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
-                       desc->status = status | IRQ_REPLAY;
-                       hw_resend_irq(desc->handler,irq);
-               }
-               desc->handler->enable(irq);
+               /* Prevent probing on this irq: */
+               desc->status = status | IRQ_NOPROBE;
+               check_irq_resend(desc, irq);
                /* fall-through */
        }
        default:
@@ -141,9 +131,29 @@ void enable_irq(unsigned int irq)
        }
        spin_unlock_irqrestore(&desc->lock, flags);
 }
-
 EXPORT_SYMBOL(enable_irq);
 
+/**
+ *     set_irq_wake - control irq power management wakeup
+ *     @irq:   interrupt to control
+ *     @on:    enable/disable power management wakeup
+ *
+ *     Enable/disable power management wakeup mode
+ */
+int set_irq_wake(unsigned int irq, unsigned int on)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       unsigned long flags;
+       int ret = -ENXIO;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       if (desc->chip->set_wake)
+               ret = desc->chip->set_wake(irq, on);
+       spin_unlock_irqrestore(&desc->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(set_irq_wake);
+
 /*
  * Internal function that tells the architecture code whether a
  * particular irq has been exclusively allocated or is available
@@ -153,7 +163,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
 {
        struct irqaction *action;
 
-       if (irq >= NR_IRQS)
+       if (irq >= NR_IRQS || irq_desc[irq].status & IRQ_NOREQUEST)
                return 0;
 
        action = irq_desc[irq].action;
@@ -164,11 +174,22 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
        return !action;
 }
 
+void compat_irq_chip_set_default_handler(struct irq_desc *desc)
+{
+       /*
+        * If the architecture still has not overriden
+        * the flow handler then zap the default. This
+        * should catch incorrect flow-type setting.
+        */
+       if (desc->handle_irq == &handle_bad_irq)
+               desc->handle_irq = NULL;
+}
+
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
  */
-int setup_irq(unsigned int irq, struct irqaction * new)
+int setup_irq(unsigned int irq, struct irqaction *new)
 {
        struct irq_desc *desc = irq_desc + irq;
        struct irqaction *old, **p;
@@ -178,7 +199,7 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        if (irq >= NR_IRQS)
                return -EINVAL;
 
-       if (desc->handler == &no_irq_type)
+       if (desc->chip == &no_irq_chip)
                return -ENOSYS;
        /*
         * Some drivers like serial.c use request_irq() heavily,
@@ -200,14 +221,21 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        /*
         * The following block of code has to be executed atomically
         */
-       spin_lock_irqsave(&desc->lock,flags);
+       spin_lock_irqsave(&desc->lock, flags);
        p = &desc->action;
-       if ((old = *p) != NULL) {
-               /* Can't share interrupts unless both agree to */
-               if (!(old->flags & new->flags & SA_SHIRQ))
+       old = *p;
+       if (old) {
+               /*
+                * Can't share interrupts unless both agree to and are
+                * the same type (level, edge, polarity). So both flag
+                * fields must have SA_SHIRQ set and the bits which
+                * set the trigger type must match.
+                */
+               if (!((old->flags & new->flags) & SA_SHIRQ) ||
+                   ((old->flags ^ new->flags) & SA_TRIGGER_MASK))
                        goto mismatch;
 
-#if defined(ARCH_HAS_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
+#if defined(CONFIG_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
                /* All handlers must agree on per-cpuness */
                if ((old->flags & IRQ_PER_CPU) != (new->flags & IRQ_PER_CPU))
                        goto mismatch;
@@ -222,20 +250,44 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        }
 
        *p = new;
-#if defined(ARCH_HAS_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
+#if defined(CONFIG_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
        if (new->flags & SA_PERCPU_IRQ)
                desc->status |= IRQ_PER_CPU;
 #endif
        if (!shared) {
-               desc->depth = 0;
-               desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
-                                 IRQ_WAITING | IRQ_INPROGRESS);
-               if (desc->handler->startup)
-                       desc->handler->startup(irq);
-               else
-                       desc->handler->enable(irq);
+               irq_chip_set_defaults(desc->chip);
+
+               /* Setup the type (level, edge polarity) if configured: */
+               if (new->flags & SA_TRIGGER_MASK) {
+                       if (desc->chip && desc->chip->set_type)
+                               desc->chip->set_type(irq,
+                                               new->flags & SA_TRIGGER_MASK);
+                       else
+                               /*
+                                * SA_TRIGGER_* but the PIC does not support
+                                * multiple flow-types?
+                                */
+                               printk(KERN_WARNING "setup_irq(%d) SA_TRIGGER"
+                                      "set. No set_type function available\n",
+                                      irq);
+               } else
+                       compat_irq_chip_set_default_handler(desc);
+
+               desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
+                                 IRQ_INPROGRESS);
+
+               if (!(desc->status & IRQ_NOAUTOEN)) {
+                       desc->depth = 0;
+                       desc->status &= ~IRQ_DISABLED;
+                       if (desc->chip->startup)
+                               desc->chip->startup(irq);
+                       else
+                               desc->chip->enable(irq);
+               } else
+                       /* Undo nested disables: */
+                       desc->depth = 1;
        }
-       spin_unlock_irqrestore(&desc->lock,flags);
+       spin_unlock_irqrestore(&desc->lock, flags);
 
        new->irq = irq;
        register_irq_proc(irq);
@@ -278,10 +330,10 @@ void free_irq(unsigned int irq, void *dev_id)
                return;
 
        desc = irq_desc + irq;
-       spin_lock_irqsave(&desc->lock,flags);
+       spin_lock_irqsave(&desc->lock, flags);
        p = &desc->action;
        for (;;) {
-               struct irqaction * action = *p;
+               struct irqaction *action = *p;
 
                if (action) {
                        struct irqaction **pp = p;
@@ -295,18 +347,18 @@ void free_irq(unsigned int irq, void *dev_id)
 
                        /* Currently used only by UML, might disappear one day.*/
 #ifdef CONFIG_IRQ_RELEASE_METHOD
-                       if (desc->handler->release)
-                               desc->handler->release(irq, dev_id);
+                       if (desc->chip->release)
+                               desc->chip->release(irq, dev_id);
 #endif
 
                        if (!desc->action) {
                                desc->status |= IRQ_DISABLED;
-                               if (desc->handler->shutdown)
-                                       desc->handler->shutdown(irq);
+                               if (desc->chip->shutdown)
+                                       desc->chip->shutdown(irq);
                                else
-                                       desc->handler->disable(irq);
+                                       desc->chip->disable(irq);
                        }
-                       spin_unlock_irqrestore(&desc->lock,flags);
+                       spin_unlock_irqrestore(&desc->lock, flags);
                        unregister_handler_proc(irq, action);
 
                        /* Make sure it's not being used on another CPU */
@@ -314,12 +366,11 @@ void free_irq(unsigned int irq, void *dev_id)
                        kfree(action);
                        return;
                }
-               printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
-               spin_unlock_irqrestore(&desc->lock,flags);
+               printk(KERN_ERR "Trying to free free IRQ%d\n", irq);
+               spin_unlock_irqrestore(&desc->lock, flags);
                return;
        }
 }
-
 EXPORT_SYMBOL(free_irq);
 
 /**
@@ -353,9 +404,9 @@ EXPORT_SYMBOL(free_irq);
  */
 int request_irq(unsigned int irq,
                irqreturn_t (*handler)(int, void *, struct pt_regs *),
-               unsigned long irqflags, const char * devname, void *dev_id)
+               unsigned long irqflags, const char *devname, void *dev_id)
 {
-       struct irqaction * action;
+       struct irqaction *action;
        int retval;
 
        /*
@@ -368,6 +419,8 @@ int request_irq(unsigned int irq,
                return -EINVAL;
        if (irq >= NR_IRQS)
                return -EINVAL;
+       if (irq_desc[irq].status & IRQ_NOREQUEST)
+               return -EINVAL;
        if (!handler)
                return -EINVAL;
 
@@ -390,6 +443,5 @@ int request_irq(unsigned int irq,
 
        return retval;
 }
-
 EXPORT_SYMBOL(request_irq);
 
index a12d00eb5e7c01e9495704fbfdae248ab081ed8e..a57ebe9fa6f6b89169eb7e7e093167c341caed71 100644 (file)
@@ -3,19 +3,19 @@
 
 void set_pending_irq(unsigned int irq, cpumask_t mask)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
 
        spin_lock_irqsave(&desc->lock, flags);
        desc->move_irq = 1;
-       pending_irq_cpumask[irq] = mask;
+       irq_desc[irq].pending_mask = mask;
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 
 void move_native_irq(int irq)
 {
+       struct irq_desc *desc = irq_desc + irq;
        cpumask_t tmp;
-       irq_desc_t *desc = irq_descp(irq);
 
        if (likely(!desc->move_irq))
                return;
@@ -30,15 +30,15 @@ void move_native_irq(int irq)
 
        desc->move_irq = 0;
 
-       if (unlikely(cpus_empty(pending_irq_cpumask[irq])))
+       if (unlikely(cpus_empty(irq_desc[irq].pending_mask)))
                return;
 
-       if (!desc->handler->set_affinity)
+       if (!desc->chip->set_affinity)
                return;
 
        assert_spin_locked(&desc->lock);
 
-       cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
+       cpus_and(tmp, irq_desc[irq].pending_mask, cpu_online_map);
 
        /*
         * If there was a valid mask to work with, please
@@ -51,12 +51,12 @@ void move_native_irq(int irq)
         */
        if (likely(!cpus_empty(tmp))) {
                if (likely(!(desc->status & IRQ_DISABLED)))
-                       desc->handler->disable(irq);
+                       desc->chip->disable(irq);
 
-               desc->handler->set_affinity(irq,tmp);
+               desc->chip->set_affinity(irq,tmp);
 
                if (likely(!(desc->status & IRQ_DISABLED)))
-                       desc->handler->enable(irq);
+                       desc->chip->enable(irq);
        }
-       cpus_clear(pending_irq_cpumask[irq]);
+       cpus_clear(irq_desc[irq].pending_mask);
 }
index afacd6f585fad187cfa950e651ad7e08a0301d81..607c7809ad0125e7aad8d28a308319601a7223ea 100644 (file)
 
 #include "internals.h"
 
-static struct proc_dir_entry *root_irq_dir, *irq_dir[NR_IRQS];
+static struct proc_dir_entry *root_irq_dir;
 
 #ifdef CONFIG_SMP
 
-/*
- * The /proc/irq/<irq>/smp_affinity values:
- */
-static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
-
 #ifdef CONFIG_GENERIC_PENDING_IRQ
 void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
 {
@@ -36,15 +31,15 @@ void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
 void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
 {
        set_balance_irq_affinity(irq, mask_val);
-       irq_affinity[irq] = mask_val;
-       irq_desc[irq].handler->set_affinity(irq, mask_val);
+       irq_desc[irq].affinity = mask_val;
+       irq_desc[irq].chip->set_affinity(irq, mask_val);
 }
 #endif
 
 static int irq_affinity_read_proc(char *page, char **start, off_t off,
                                  int count, int *eof, void *data)
 {
-       int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
+       int len = cpumask_scnprintf(page, count, irq_desc[(long)data].affinity);
 
        if (count - len < 2)
                return -EINVAL;
@@ -59,7 +54,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
        unsigned int irq = (int)(long)data, full_count = count, err;
        cpumask_t new_value, tmp;
 
-       if (!irq_desc[irq].handler->set_affinity || no_irq_affinity)
+       if (!irq_desc[irq].chip->set_affinity || no_irq_affinity)
                return -EIO;
 
        err = cpumask_parse(buffer, count, new_value);
@@ -102,7 +97,7 @@ void register_handler_proc(unsigned int irq, struct irqaction *action)
 {
        char name [MAX_NAMELEN];
 
-       if (!irq_dir[irq] || action->dir || !action->name ||
+       if (!irq_desc[irq].dir || action->dir || !action->name ||
                                        !name_unique(irq, action))
                return;
 
@@ -110,7 +105,7 @@ void register_handler_proc(unsigned int irq, struct irqaction *action)
        snprintf(name, MAX_NAMELEN, "%s", action->name);
 
        /* create /proc/irq/1234/handler/ */
-       action->dir = proc_mkdir(name, irq_dir[irq]);
+       action->dir = proc_mkdir(name, irq_desc[irq].dir);
 }
 
 #undef MAX_NAMELEN
@@ -122,22 +117,22 @@ void register_irq_proc(unsigned int irq)
        char name [MAX_NAMELEN];
 
        if (!root_irq_dir ||
-               (irq_desc[irq].handler == &no_irq_type) ||
-                       irq_dir[irq])
+               (irq_desc[irq].chip == &no_irq_chip) ||
+                       irq_desc[irq].dir)
                return;
 
        memset(name, 0, MAX_NAMELEN);
        sprintf(name, "%d", irq);
 
        /* create /proc/irq/1234 */
-       irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+       irq_desc[irq].dir = proc_mkdir(name, root_irq_dir);
 
 #ifdef CONFIG_SMP
        {
                struct proc_dir_entry *entry;
 
                /* create /proc/irq/<irq>/smp_affinity */
-               entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+               entry = create_proc_entry("smp_affinity", 0600, irq_desc[irq].dir);
 
                if (entry) {
                        entry->nlink = 1;
@@ -145,7 +140,6 @@ void register_irq_proc(unsigned int irq)
                        entry->read_proc = irq_affinity_read_proc;
                        entry->write_proc = irq_affinity_write_proc;
                }
-               smp_affinity_entry[irq] = entry;
        }
 #endif
 }
@@ -155,7 +149,7 @@ void register_irq_proc(unsigned int irq)
 void unregister_handler_proc(unsigned int irq, struct irqaction *action)
 {
        if (action->dir)
-               remove_proc_entry(action->dir->name, irq_dir[irq]);
+               remove_proc_entry(action->dir->name, irq_desc[irq].dir);
 }
 
 void init_irq_proc(void)
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
new file mode 100644 (file)
index 0000000..872f91b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * linux/kernel/irq/resend.c
+ *
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006, Thomas Gleixner
+ *
+ * This file contains the IRQ-resend code
+ *
+ * If the interrupt is waiting to be processed, we try to re-run it.
+ * We can't directly run it from here since the caller might be in an
+ * interrupt-protected region. Not all irq controller chips can
+ * retrigger interrupts at the hardware level, so in those cases
+ * we allow the resending of IRQs via a tasklet.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/interrupt.h>
+
+#include "internals.h"
+
+#ifdef CONFIG_HARDIRQS_SW_RESEND
+
+/* Bitmap to handle software resend of interrupts: */
+static DECLARE_BITMAP(irqs_resend, NR_IRQS);
+
+/*
+ * Run software resends of IRQ's
+ */
+static void resend_irqs(unsigned long arg)
+{
+       struct irq_desc *desc;
+       int irq;
+
+       while (!bitmap_empty(irqs_resend, NR_IRQS)) {
+               irq = find_first_bit(irqs_resend, NR_IRQS);
+               clear_bit(irq, irqs_resend);
+               desc = irq_desc + irq;
+               local_irq_disable();
+               desc->handle_irq(irq, desc, NULL);
+               local_irq_enable();
+       }
+}
+
+/* Tasklet to handle resend: */
+static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);
+
+#endif
+
+/*
+ * IRQ resend
+ *
+ * Is called with interrupts disabled and desc->lock held.
+ */
+void check_irq_resend(struct irq_desc *desc, unsigned int irq)
+{
+       unsigned int status = desc->status;
+
+       /*
+        * Make sure the interrupt is enabled, before resending it:
+        */
+       desc->chip->enable(irq);
+
+       if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+               desc->status &= ~IRQ_PENDING;
+               desc->status = status | IRQ_REPLAY;
+
+               if (!desc->chip || !desc->chip->retrigger ||
+                                       !desc->chip->retrigger(irq)) {
+#ifdef CONFIG_HARDIRQS_SW_RESEND
+                       /* Set it pending and activate the softirq: */
+                       set_bit(irq, irqs_resend);
+                       tasklet_schedule(&resend_tasklet);
+#endif
+               }
+       }
+}
index b2fb3c18d06bd77d88ed9eb8784f8a4254712a83..b483deed311cf7a3111fd31aafd938a1aae1f9f7 100644 (file)
@@ -16,22 +16,20 @@ static int irqfixup __read_mostly;
 /*
  * Recovery handler for misrouted interrupts.
  */
-
 static int misrouted_irq(int irq, struct pt_regs *regs)
 {
        int i;
-       irq_desc_t *desc;
        int ok = 0;
        int work = 0;   /* Did we do work for a real IRQ */
 
-       for(i = 1; i < NR_IRQS; i++) {
+       for (i = 1; i < NR_IRQS; i++) {
+               struct irq_desc *desc = irq_desc + i;
                struct irqaction *action;
 
                if (i == irq)   /* Already tried */
                        continue;
-               desc = &irq_desc[i];
+
                spin_lock(&desc->lock);
-               action = desc->action;
                /* Already running on another processor */
                if (desc->status & IRQ_INPROGRESS) {
                        /*
@@ -45,7 +43,9 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
                }
                /* Honour the normal IRQ locking */
                desc->status |= IRQ_INPROGRESS;
+               action = desc->action;
                spin_unlock(&desc->lock);
+
                while (action) {
                        /* Only shared IRQ handlers are safe to call */
                        if (action->flags & SA_SHIRQ) {
@@ -62,9 +62,8 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
 
                /*
                 * While we were looking for a fixup someone queued a real
-                * IRQ clashing with our walk
+                * IRQ clashing with our walk:
                 */
-
                while ((desc->status & IRQ_PENDING) && action) {
                        /*
                         * Perform real IRQ processing for the IRQ we deferred
@@ -80,8 +79,8 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
                 * If we did actual work for the real IRQ line we must let the
                 * IRQ controller clean up too
                 */
-               if(work)
-                       desc->handler->end(i);
+               if (work && desc->chip && desc->chip->end)
+                       desc->chip->end(i);
                spin_unlock(&desc->lock);
        }
        /* So the caller can adjust the irq error counts */
@@ -100,7 +99,8 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
  */
 
 static void
-__report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+__report_bad_irq(unsigned int irq, struct irq_desc *desc,
+                irqreturn_t action_ret)
 {
        struct irqaction *action;
 
@@ -113,6 +113,7 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
        }
        dump_stack();
        printk(KERN_ERR "handlers:\n");
+
        action = desc->action;
        while (action) {
                printk(KERN_ERR "[<%p>]", action->handler);
@@ -123,7 +124,8 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
        }
 }
 
-static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+static void
+report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
 {
        static int count = 100;
 
@@ -133,8 +135,8 @@ static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t actio
        }
 }
 
-void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
-                       struct pt_regs *regs)
+void note_interrupt(unsigned int irq, struct irq_desc *desc,
+                   irqreturn_t action_ret, struct pt_regs *regs)
 {
        if (unlikely(action_ret != IRQ_HANDLED)) {
                desc->irqs_unhandled++;
@@ -166,7 +168,8 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
                 */
                printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
                desc->status |= IRQ_DISABLED;
-               desc->handler->disable(irq);
+               desc->depth = 1;
+               desc->chip->disable(irq);
        }
        desc->irqs_unhandled = 0;
 }
@@ -177,6 +180,7 @@ int __init noirqdebug_setup(char *str)
 {
        noirqdebug = 1;
        printk(KERN_INFO "IRQ lockup detection disabled\n");
+
        return 1;
 }
 
@@ -187,6 +191,7 @@ static int __init irqfixup_setup(char *str)
        irqfixup = 1;
        printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
        printk(KERN_WARNING "This may impact system performance.\n");
+
        return 1;
 }
 
index 10e5b872adf6f56d2755976dee65a6e8a9a6ab8a..99c022ac3d21c7105e5d37fdc288e0dc7527d8a8 100644 (file)
@@ -1,4 +1,4 @@
-/* Rewritten by Rusty Russell, on the backs of many others...
+/*
    Copyright (C) 2002 Richard Henderson
    Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
 
@@ -122,9 +122,17 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
 extern const struct kernel_symbol __start___ksymtab_gpl_future[];
 extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
+extern const struct kernel_symbol __start___ksymtab_unused[];
+extern const struct kernel_symbol __stop___ksymtab_unused[];
+extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
+extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
 extern const unsigned long __start___kcrctab_gpl_future[];
+extern const unsigned long __start___kcrctab_unused[];
+extern const unsigned long __start___kcrctab_unused_gpl[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -144,6 +152,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
        return NULL;
 }
 
+static void printk_unused_warning(const char *name)
+{
+       printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
+               "however this module is using it.\n", name);
+       printk(KERN_WARNING "This symbol will go away in the future.\n");
+       printk(KERN_WARNING "Please evalute if this is the right api to use, "
+               "and if it really is, submit a report the linux kernel "
+               "mailinglist together with submitting your code for "
+               "inclusion.\n");
+}
+
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
                                   struct module **owner,
@@ -186,6 +205,25 @@ static unsigned long __find_symbol(const char *name,
                return ks->value;
        }
 
+       ks = lookup_symbol(name, __start___ksymtab_unused,
+                                __stop___ksymtab_unused);
+       if (ks) {
+               printk_unused_warning(name);
+               *crc = symversion(__start___kcrctab_unused,
+                                 (ks - __start___ksymtab_unused));
+               return ks->value;
+       }
+
+       if (gplok)
+               ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
+                                __stop___ksymtab_unused_gpl);
+       if (ks) {
+               printk_unused_warning(name);
+               *crc = symversion(__start___kcrctab_unused_gpl,
+                                 (ks - __start___ksymtab_unused_gpl));
+               return ks->value;
+       }
+
        /* Now try modules. */ 
        list_for_each_entry(mod, &modules, list) {
                *owner = mod;
@@ -204,6 +242,23 @@ static unsigned long __find_symbol(const char *name,
                                return ks->value;
                        }
                }
+               ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
+               if (ks) {
+                       printk_unused_warning(name);
+                       *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
+                       return ks->value;
+               }
+
+               if (gplok) {
+                       ks = lookup_symbol(name, mod->unused_gpl_syms,
+                                          mod->unused_gpl_syms + mod->num_unused_gpl_syms);
+                       if (ks) {
+                               printk_unused_warning(name);
+                               *crc = symversion(mod->unused_gpl_crcs,
+                                                 (ks - mod->unused_gpl_syms));
+                               return ks->value;
+                       }
+               }
                ks = lookup_symbol(name, mod->gpl_future_syms,
                                   (mod->gpl_future_syms +
                                    mod->num_gpl_future_syms));
@@ -1403,10 +1458,27 @@ static struct module *load_module(void __user *umod,
        Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
        char *secstrings, *args, *modmagic, *strtab = NULL;
-       unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
-               exportindex, modindex, obsparmindex, infoindex, gplindex,
-               crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
-               gplfuturecrcindex, unwindex = 0;
+       unsigned int i;
+       unsigned int symindex = 0;
+       unsigned int strindex = 0;
+       unsigned int setupindex;
+       unsigned int exindex;
+       unsigned int exportindex;
+       unsigned int modindex;
+       unsigned int obsparmindex;
+       unsigned int infoindex;
+       unsigned int gplindex;
+       unsigned int crcindex;
+       unsigned int gplcrcindex;
+       unsigned int versindex;
+       unsigned int pcpuindex;
+       unsigned int gplfutureindex;
+       unsigned int gplfuturecrcindex;
+       unsigned int unwindex = 0;
+       unsigned int unusedindex;
+       unsigned int unusedcrcindex;
+       unsigned int unusedgplindex;
+       unsigned int unusedgplcrcindex;
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1487,9 +1559,13 @@ static struct module *load_module(void __user *umod,
        exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
        gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
        gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
+       unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused");
+       unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl");
        crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
        gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
        gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
+       unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused");
+       unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl");
        setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
        exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
        obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
@@ -1638,14 +1714,27 @@ static struct module *load_module(void __user *umod,
                mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
        mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
                                        sizeof(*mod->gpl_future_syms);
+       mod->num_unused_syms = sechdrs[unusedindex].sh_size /
+                                       sizeof(*mod->unused_syms);
+       mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size /
+                                       sizeof(*mod->unused_gpl_syms);
        mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
        if (gplfuturecrcindex)
                mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
 
+       mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
+       if (unusedcrcindex)
+               mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
+       mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
+       if (unusedgplcrcindex)
+               mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
+
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !crcindex) || 
            (mod->num_gpl_syms && !gplcrcindex) ||
-           (mod->num_gpl_future_syms && !gplfuturecrcindex)) {
+           (mod->num_gpl_future_syms && !gplfuturecrcindex) ||
+           (mod->num_unused_syms && !unusedcrcindex) ||
+           (mod->num_unused_gpl_syms && !unusedgplcrcindex)) {
                printk(KERN_WARNING "%s: No versions for exported symbols."
                       " Tainting kernel.\n", mod->name);
                add_taint(TAINT_FORCED_MODULE);
index 036b6285b15ccb195848a64e03fa741fd20e8d89..e38e4bac97cac6dde3cacd552f189ef77882bb62 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/poison.h>
 #include <linux/spinlock.h>
 #include <linux/kallsyms.h>
 #include <linux/interrupt.h>
@@ -381,7 +382,7 @@ void debug_mutex_set_owner(struct mutex *lock,
 
 void debug_mutex_init_waiter(struct mutex_waiter *waiter)
 {
-       memset(waiter, 0x11, sizeof(*waiter));
+       memset(waiter, MUTEX_DEBUG_INIT, sizeof(*waiter));
        waiter->magic = waiter;
        INIT_LIST_HEAD(&waiter->list);
 }
@@ -397,7 +398,7 @@ void debug_mutex_wake_waiter(struct mutex *lock, struct mutex_waiter *waiter)
 void debug_mutex_free_waiter(struct mutex_waiter *waiter)
 {
        DEBUG_WARN_ON(!list_empty(&waiter->list));
-       memset(waiter, 0x22, sizeof(*waiter));
+       memset(waiter, MUTEX_DEBUG_FREE, sizeof(*waiter));
 }
 
 void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
index fc311a4673a25e451e94c1eef38c00bc425acf5a..857b4fa091244758b5fc0976cf44d58f914f20ec 100644 (file)
@@ -38,13 +38,22 @@ config PM_DEBUG
 
 config PM_TRACE
        bool "Suspend/resume event tracing"
-       depends on PM && PM_DEBUG && X86_32
-       default y
+       depends on PM && PM_DEBUG && X86_32 && EXPERIMENTAL
+       default n
        ---help---
        This enables some cheesy code to save the last PM event point in the
        RTC across reboots, so that you can debug a machine that just hangs
        during suspend (or more commonly, during resume).
 
+       To use this debugging feature you should attempt to suspend the machine,
+       then reboot it, then run
+
+               dmesg -s 1000000 | grep 'hash matches'
+
+       CAUTION: this option will cause your machine's real-time clock to be
+       set to an invalid time after a resume.
+
+
 config SOFTWARE_SUSPEND
        bool "Software Suspend"
        depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)
index 68afe121e5071f0574e37e7b9e20f1d66bd4c290..5a730fdb1a2cecf6b10c2112ba777fbb5fb7c794 100644 (file)
@@ -299,7 +299,7 @@ out:
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static int profile_cpu_callback(struct notifier_block *info,
+static int __devinit profile_cpu_callback(struct notifier_block *info,
                                        unsigned long action, void *__cpu)
 {
        int node, cpu = (unsigned long)__cpu;
index 20e9710fc21c5fa5bc3d6c88342f8ba1dc4f5f0b..f464f5ae3f11a8edfe12d7ff83b609013526cfe6 100644 (file)
@@ -182,6 +182,15 @@ long rcu_batches_completed(void)
        return rcu_ctrlblk.completed;
 }
 
+/*
+ * Return the number of RCU batches processed thus far.  Useful
+ * for debug and statistics.
+ */
+long rcu_batches_completed_bh(void)
+{
+       return rcu_bh_ctrlblk.completed;
+}
+
 static void rcu_barrier_callback(struct rcu_head *notused)
 {
        if (atomic_dec_and_test(&rcu_barrier_cpu_count))
@@ -539,7 +548,7 @@ static void __devinit rcu_online_cpu(int cpu)
        tasklet_init(&per_cpu(rcu_tasklet, cpu), rcu_process_callbacks, 0UL);
 }
 
-static int rcu_cpu_notify(struct notifier_block *self,
+static int __devinit rcu_cpu_notify(struct notifier_block *self,
                                unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
@@ -556,7 +565,7 @@ static int rcu_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block rcu_nb = {
+static struct notifier_block __devinitdata rcu_nb = {
        .notifier_call  = rcu_cpu_notify,
 };
 
@@ -619,6 +628,7 @@ module_param(qlowmark, int, 0);
 module_param(rsinterval, int, 0);
 #endif
 EXPORT_SYMBOL_GPL(rcu_batches_completed);
+EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
 EXPORT_SYMBOL_GPL(call_rcu);
 EXPORT_SYMBOL_GPL(call_rcu_bh);
 EXPORT_SYMBOL_GPL(synchronize_rcu);
index 8154e7589d1284a7f96b1aa3b587ab2ffc01c299..4d1c3d2471278ebe93e00d7291eb253e83f7d89a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Read-Copy Update /proc-based torture test facility
+ * Read-Copy Update module-based torture test facility
  *
  * 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
@@ -53,6 +53,7 @@ static int stat_interval;     /* Interval between stats, in seconds. */
 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)*/
+static char *torture_type = "rcu"; /* What to torture. */
 
 module_param(nreaders, int, 0);
 MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
@@ -64,13 +65,16 @@ module_param(test_no_idle_hz, bool, 0);
 MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
 module_param(shuffle_interval, int, 0);
 MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-#define TORTURE_FLAG "rcutorture: "
+module_param(torture_type, charp, 0);
+MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh)");
+
+#define TORTURE_FLAG "-torture:"
 #define PRINTK_STRING(s) \
-       do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
+       do { printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
 #define VERBOSE_PRINTK_STRING(s) \
-       do { if (verbose) printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
+       do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
 #define VERBOSE_PRINTK_ERRSTRING(s) \
-       do { if (verbose) printk(KERN_ALERT TORTURE_FLAG "!!! " s "\n"); } while (0)
+       do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0)
 
 static char printk_buf[4096];
 
@@ -139,28 +143,6 @@ rcu_torture_free(struct rcu_torture *p)
        spin_unlock_bh(&rcu_torture_lock);
 }
 
-static void
-rcu_torture_cb(struct rcu_head *p)
-{
-       int i;
-       struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
-
-       if (fullstop) {
-               /* Test is ending, just drop callbacks on the floor. */
-               /* The next initialization will pick up the pieces. */
-               return;
-       }
-       i = rp->rtort_pipe_count;
-       if (i > RCU_TORTURE_PIPE_LEN)
-               i = RCU_TORTURE_PIPE_LEN;
-       atomic_inc(&rcu_torture_wcount[i]);
-       if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
-               rp->rtort_mbtest = 0;
-               rcu_torture_free(rp);
-       } else
-               call_rcu(p, rcu_torture_cb);
-}
-
 struct rcu_random_state {
        unsigned long rrs_state;
        unsigned long rrs_count;
@@ -190,6 +172,119 @@ rcu_random(struct rcu_random_state *rrsp)
        return swahw32(rrsp->rrs_state);
 }
 
+/*
+ * Operations vector for selecting different types of tests.
+ */
+
+struct rcu_torture_ops {
+       void (*init)(void);
+       void (*cleanup)(void);
+       int (*readlock)(void);
+       void (*readunlock)(int idx);
+       int (*completed)(void);
+       void (*deferredfree)(struct rcu_torture *p);
+       int (*stats)(char *page);
+       char *name;
+};
+static struct rcu_torture_ops *cur_ops = NULL;
+
+/*
+ * Definitions for rcu torture testing.
+ */
+
+static int rcu_torture_read_lock(void)
+{
+       rcu_read_lock();
+       return 0;
+}
+
+static void rcu_torture_read_unlock(int idx)
+{
+       rcu_read_unlock();
+}
+
+static int rcu_torture_completed(void)
+{
+       return rcu_batches_completed();
+}
+
+static void
+rcu_torture_cb(struct rcu_head *p)
+{
+       int i;
+       struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
+
+       if (fullstop) {
+               /* Test is ending, just drop callbacks on the floor. */
+               /* The next initialization will pick up the pieces. */
+               return;
+       }
+       i = rp->rtort_pipe_count;
+       if (i > RCU_TORTURE_PIPE_LEN)
+               i = RCU_TORTURE_PIPE_LEN;
+       atomic_inc(&rcu_torture_wcount[i]);
+       if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
+               rp->rtort_mbtest = 0;
+               rcu_torture_free(rp);
+       } else
+               cur_ops->deferredfree(rp);
+}
+
+static void rcu_torture_deferred_free(struct rcu_torture *p)
+{
+       call_rcu(&p->rtort_rcu, rcu_torture_cb);
+}
+
+static struct rcu_torture_ops rcu_ops = {
+       .init = NULL,
+       .cleanup = NULL,
+       .readlock = rcu_torture_read_lock,
+       .readunlock = rcu_torture_read_unlock,
+       .completed = rcu_torture_completed,
+       .deferredfree = rcu_torture_deferred_free,
+       .stats = NULL,
+       .name = "rcu"
+};
+
+/*
+ * Definitions for rcu_bh torture testing.
+ */
+
+static int rcu_bh_torture_read_lock(void)
+{
+       rcu_read_lock_bh();
+       return 0;
+}
+
+static void rcu_bh_torture_read_unlock(int idx)
+{
+       rcu_read_unlock_bh();
+}
+
+static int rcu_bh_torture_completed(void)
+{
+       return rcu_batches_completed_bh();
+}
+
+static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
+{
+       call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
+}
+
+static struct rcu_torture_ops rcu_bh_ops = {
+       .init = NULL,
+       .cleanup = NULL,
+       .readlock = rcu_bh_torture_read_lock,
+       .readunlock = rcu_bh_torture_read_unlock,
+       .completed = rcu_bh_torture_completed,
+       .deferredfree = rcu_bh_torture_deferred_free,
+       .stats = NULL,
+       .name = "rcu_bh"
+};
+
+static struct rcu_torture_ops *torture_ops[] =
+       { &rcu_ops, &rcu_bh_ops, NULL };
+
 /*
  * RCU torture writer kthread.  Repeatedly substitutes a new structure
  * for that pointed to by rcu_torture_current, freeing the old structure
@@ -209,8 +304,6 @@ rcu_torture_writer(void *arg)
 
        do {
                schedule_timeout_uninterruptible(1);
-               if (rcu_batches_completed() == oldbatch)
-                       continue;
                if ((rp = rcu_torture_alloc()) == NULL)
                        continue;
                rp->rtort_pipe_count = 0;
@@ -225,10 +318,10 @@ rcu_torture_writer(void *arg)
                                i = RCU_TORTURE_PIPE_LEN;
                        atomic_inc(&rcu_torture_wcount[i]);
                        old_rp->rtort_pipe_count++;
-                       call_rcu(&old_rp->rtort_rcu, rcu_torture_cb);
+                       cur_ops->deferredfree(old_rp);
                }
                rcu_torture_current_version++;
-               oldbatch = rcu_batches_completed();
+               oldbatch = cur_ops->completed();
        } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
        while (!kthread_should_stop())
@@ -246,6 +339,7 @@ static int
 rcu_torture_reader(void *arg)
 {
        int completed;
+       int idx;
        DEFINE_RCU_RANDOM(rand);
        struct rcu_torture *p;
        int pipe_count;
@@ -254,12 +348,12 @@ rcu_torture_reader(void *arg)
        set_user_nice(current, 19);
 
        do {
-               rcu_read_lock();
-               completed = rcu_batches_completed();
+               idx = cur_ops->readlock();
+               completed = cur_ops->completed();
                p = rcu_dereference(rcu_torture_current);
                if (p == NULL) {
                        /* Wait for rcu_torture_writer to get underway */
-                       rcu_read_unlock();
+                       cur_ops->readunlock(idx);
                        schedule_timeout_interruptible(HZ);
                        continue;
                }
@@ -273,14 +367,14 @@ rcu_torture_reader(void *arg)
                        pipe_count = RCU_TORTURE_PIPE_LEN;
                }
                ++__get_cpu_var(rcu_torture_count)[pipe_count];
-               completed = rcu_batches_completed() - completed;
+               completed = cur_ops->completed() - completed;
                if (completed > RCU_TORTURE_PIPE_LEN) {
                        /* Should not happen, but... */
                        completed = RCU_TORTURE_PIPE_LEN;
                }
                ++__get_cpu_var(rcu_torture_batch)[completed];
                preempt_enable();
-               rcu_read_unlock();
+               cur_ops->readunlock(idx);
                schedule();
        } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
@@ -311,7 +405,7 @@ rcu_torture_printk(char *page)
                if (pipesummary[i] != 0)
                        break;
        }
-       cnt += sprintf(&page[cnt], "rcutorture: ");
+       cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt],
                       "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
                       "rtmbe: %d",
@@ -324,7 +418,7 @@ rcu_torture_printk(char *page)
                       atomic_read(&n_rcu_torture_mberror));
        if (atomic_read(&n_rcu_torture_mberror) != 0)
                cnt += sprintf(&page[cnt], " !!!");
-       cnt += sprintf(&page[cnt], "\nrcutorture: ");
+       cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
        if (i > 1) {
                cnt += sprintf(&page[cnt], "!!! ");
                atomic_inc(&n_rcu_torture_error);
@@ -332,17 +426,19 @@ rcu_torture_printk(char *page)
        cnt += sprintf(&page[cnt], "Reader Pipe: ");
        for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
                cnt += sprintf(&page[cnt], " %ld", pipesummary[i]);
-       cnt += sprintf(&page[cnt], "\nrcutorture: ");
+       cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt], "Reader Batch: ");
-       for (i = 0; i < RCU_TORTURE_PIPE_LEN; i++)
+       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
                cnt += sprintf(&page[cnt], " %ld", batchsummary[i]);
-       cnt += sprintf(&page[cnt], "\nrcutorture: ");
+       cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt], "Free-Block Circulation: ");
        for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
                cnt += sprintf(&page[cnt], " %d",
                               atomic_read(&rcu_torture_wcount[i]));
        }
        cnt += sprintf(&page[cnt], "\n");
+       if (cur_ops->stats != NULL)
+               cnt += cur_ops->stats(&page[cnt]);
        return cnt;
 }
 
@@ -444,11 +540,11 @@ rcu_torture_shuffle(void *arg)
 static inline void
 rcu_torture_print_module_parms(char *tag)
 {
-       printk(KERN_ALERT TORTURE_FLAG "--- %s: nreaders=%d "
+       printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d "
                "stat_interval=%d verbose=%d test_no_idle_hz=%d "
                "shuffle_interval = %d\n",
-               tag, nrealreaders, stat_interval, verbose, test_no_idle_hz,
-               shuffle_interval);
+               torture_type, tag, nrealreaders, stat_interval, verbose,
+               test_no_idle_hz, shuffle_interval);
 }
 
 static void
@@ -493,6 +589,9 @@ rcu_torture_cleanup(void)
        rcu_barrier();
 
        rcu_torture_stats_print();  /* -After- the stats thread is stopped! */
+
+       if (cur_ops->cleanup != NULL)
+               cur_ops->cleanup();
        if (atomic_read(&n_rcu_torture_error))
                rcu_torture_print_module_parms("End of test: FAILURE");
        else
@@ -508,6 +607,20 @@ rcu_torture_init(void)
 
        /* Process args and tell the world that the torturer is on the job. */
 
+       for (i = 0; cur_ops = torture_ops[i], cur_ops != NULL; i++) {
+               cur_ops = torture_ops[i];
+               if (strcmp(torture_type, cur_ops->name) == 0) {
+                       break;
+               }
+       }
+       if (cur_ops == NULL) {
+               printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
+                      torture_type);
+               return (-EINVAL);
+       }
+       if (cur_ops->init != NULL)
+               cur_ops->init(); /* no "goto unwind" prior to this point!!! */
+
        if (nreaders >= 0)
                nrealreaders = nreaders;
        else
index e3080fcc66a3b1237e30326782eed2a8fd184323..bf1130d81b7f09d35c81e436592b407e56c526d3 100644 (file)
 
 struct resource ioport_resource = {
        .name   = "PCI IO",
-       .start  = 0x0000,
+       .start  = 0,
        .end    = IO_SPACE_LIMIT,
        .flags  = IORESOURCE_IO,
 };
-
 EXPORT_SYMBOL(ioport_resource);
 
 struct resource iomem_resource = {
        .name   = "PCI mem",
-       .start  = 0UL,
-       .end    = ~0UL,
+       .start  = 0,
+       .end    = -1,
        .flags  = IORESOURCE_MEM,
 };
-
 EXPORT_SYMBOL(iomem_resource);
 
 static DEFINE_RWLOCK(resource_lock);
@@ -83,10 +81,10 @@ static int r_show(struct seq_file *m, void *v)
        for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
                if (p->parent == root)
                        break;
-       seq_printf(m, "%*s%0*lx-%0*lx : %s\n",
+       seq_printf(m, "%*s%0*llx-%0*llx : %s\n",
                        depth * 2, "",
-                       width, r->start,
-                       width, r->end,
+                       width, (unsigned long long) r->start,
+                       width, (unsigned long long) r->end,
                        r->name ? r->name : "<BAD>");
        return 0;
 }
@@ -151,8 +149,8 @@ __initcall(ioresources_init);
 /* Return the conflict entry if you can't request it */
 static struct resource * __request_resource(struct resource *root, struct resource *new)
 {
-       unsigned long start = new->start;
-       unsigned long end = new->end;
+       resource_size_t start = new->start;
+       resource_size_t end = new->end;
        struct resource *tmp, **p;
 
        if (end < start)
@@ -232,15 +230,52 @@ int release_resource(struct resource *old)
 
 EXPORT_SYMBOL(release_resource);
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * Finds the lowest memory reosurce exists within [res->start.res->end)
+ * the caller must specify res->start, res->end, res->flags.
+ * If found, returns 0, res is overwritten, if not found, returns -1.
+ */
+int find_next_system_ram(struct resource *res)
+{
+       resource_size_t start, end;
+       struct resource *p;
+
+       BUG_ON(!res);
+
+       start = res->start;
+       end = res->end;
+
+       read_lock(&resource_lock);
+       for (p = iomem_resource.child; p ; p = p->sibling) {
+               /* system ram is just marked as IORESOURCE_MEM */
+               if (p->flags != res->flags)
+                       continue;
+               if (p->start > end) {
+                       p = NULL;
+                       break;
+               }
+               if (p->start >= start)
+                       break;
+       }
+       read_unlock(&resource_lock);
+       if (!p)
+               return -1;
+       /* copy data */
+       res->start = p->start;
+       res->end = p->end;
+       return 0;
+}
+#endif
+
 /*
  * Find empty slot in the resource tree given range and alignment.
  */
 static int find_resource(struct resource *root, struct resource *new,
-                        unsigned long size,
-                        unsigned long min, unsigned long max,
-                        unsigned long align,
+                        resource_size_t size, resource_size_t min,
+                        resource_size_t max, resource_size_t align,
                         void (*alignf)(void *, struct resource *,
-                                       unsigned long, unsigned long),
+                                       resource_size_t, resource_size_t),
                         void *alignf_data)
 {
        struct resource *this = root->child;
@@ -282,11 +317,10 @@ static int find_resource(struct resource *root, struct resource *new,
  * Allocate empty slot in the resource tree given range and alignment.
  */
 int allocate_resource(struct resource *root, struct resource *new,
-                     unsigned long size,
-                     unsigned long min, unsigned long max,
-                     unsigned long align,
+                     resource_size_t size, resource_size_t min,
+                     resource_size_t max, resource_size_t align,
                      void (*alignf)(void *, struct resource *,
-                                    unsigned long, unsigned long),
+                                    resource_size_t, resource_size_t),
                      void *alignf_data)
 {
        int err;
@@ -378,10 +412,10 @@ EXPORT_SYMBOL(insert_resource);
  * arguments.  Returns -EBUSY if it can't fit.  Existing children of
  * the resource are assumed to be immutable.
  */
-int adjust_resource(struct resource *res, unsigned long start, unsigned long size)
+int adjust_resource(struct resource *res, resource_size_t start, resource_size_t size)
 {
        struct resource *tmp, *parent = res->parent;
-       unsigned long end = start + size - 1;
+       resource_size_t end = start + size - 1;
        int result = -EBUSY;
 
        write_lock(&resource_lock);
@@ -428,7 +462,9 @@ EXPORT_SYMBOL(adjust_resource);
  *
  * Release-region releases a matching busy region.
  */
-struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
+struct resource * __request_region(struct resource *parent,
+                                  resource_size_t start, resource_size_t n,
+                                  const char *name)
 {
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
@@ -464,7 +500,8 @@ struct resource * __request_region(struct resource *parent, unsigned long start,
 
 EXPORT_SYMBOL(__request_region);
 
-int __check_region(struct resource *parent, unsigned long start, unsigned long n)
+int __check_region(struct resource *parent, resource_size_t start,
+                       resource_size_t n)
 {
        struct resource * res;
 
@@ -479,10 +516,11 @@ int __check_region(struct resource *parent, unsigned long start, unsigned long n
 
 EXPORT_SYMBOL(__check_region);
 
-void __release_region(struct resource *parent, unsigned long start, unsigned long n)
+void __release_region(struct resource *parent, resource_size_t start,
+                       resource_size_t n)
 {
        struct resource **p;
-       unsigned long end;
+       resource_size_t end;
 
        p = &parent->child;
        end = start + n - 1;
@@ -511,7 +549,9 @@ void __release_region(struct resource *parent, unsigned long start, unsigned lon
 
        write_unlock(&resource_lock);
 
-       printk(KERN_WARNING "Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
+       printk(KERN_WARNING "Trying to free nonexistent resource "
+               "<%016llx-%016llx>\n", (unsigned long long)start,
+               (unsigned long long)end);
 }
 
 EXPORT_SYMBOL(__release_region);
diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c
new file mode 100644 (file)
index 0000000..4aa8a2c
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * RT-Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This code is based on the rt.c implementation in the preempt-rt tree.
+ * Portions of said code are
+ *
+ *  Copyright (C) 2004  LynuxWorks, Inc., Igor Manyilov, Bill Huey
+ *  Copyright (C) 2006  Esben Nielsen
+ *  Copyright (C) 2006  Kihon Technologies Inc.,
+ *                     Steven Rostedt <rostedt@goodmis.org>
+ *
+ * See rt.c in preempt-rt for proper credits and further information
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/kallsyms.h>
+#include <linux/syscalls.h>
+#include <linux/interrupt.h>
+#include <linux/plist.h>
+#include <linux/fs.h>
+
+#include "rtmutex_common.h"
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# include "rtmutex-debug.h"
+#else
+# include "rtmutex.h"
+#endif
+
+# define TRACE_WARN_ON(x)                      WARN_ON(x)
+# define TRACE_BUG_ON(x)                       BUG_ON(x)
+
+# define TRACE_OFF()                                           \
+do {                                                           \
+       if (rt_trace_on) {                                      \
+               rt_trace_on = 0;                                \
+               console_verbose();                              \
+               if (spin_is_locked(&current->pi_lock))          \
+                       spin_unlock(&current->pi_lock);         \
+               if (spin_is_locked(&current->held_list_lock))   \
+                       spin_unlock(&current->held_list_lock);  \
+       }                                                       \
+} while (0)
+
+# define TRACE_OFF_NOLOCK()                                    \
+do {                                                           \
+       if (rt_trace_on) {                                      \
+               rt_trace_on = 0;                                \
+               console_verbose();                              \
+       }                                                       \
+} while (0)
+
+# define TRACE_BUG_LOCKED()                    \
+do {                                           \
+       TRACE_OFF();                            \
+       BUG();                                  \
+} while (0)
+
+# define TRACE_WARN_ON_LOCKED(c)               \
+do {                                           \
+       if (unlikely(c)) {                      \
+               TRACE_OFF();                    \
+               WARN_ON(1);                     \
+       }                                       \
+} while (0)
+
+# define TRACE_BUG_ON_LOCKED(c)                        \
+do {                                           \
+       if (unlikely(c))                        \
+               TRACE_BUG_LOCKED();             \
+} while (0)
+
+#ifdef CONFIG_SMP
+# define SMP_TRACE_BUG_ON_LOCKED(c)    TRACE_BUG_ON_LOCKED(c)
+#else
+# define SMP_TRACE_BUG_ON_LOCKED(c)    do { } while (0)
+#endif
+
+/*
+ * deadlock detection flag. We turn it off when we detect
+ * the first problem because we dont want to recurse back
+ * into the tracing code when doing error printk or
+ * executing a BUG():
+ */
+int rt_trace_on = 1;
+
+void deadlock_trace_off(void)
+{
+       rt_trace_on = 0;
+}
+
+static void printk_task(task_t *p)
+{
+       if (p)
+               printk("%16s:%5d [%p, %3d]", p->comm, p->pid, p, p->prio);
+       else
+               printk("<none>");
+}
+
+static void printk_task_short(task_t *p)
+{
+       if (p)
+               printk("%s/%d [%p, %3d]", p->comm, p->pid, p, p->prio);
+       else
+               printk("<none>");
+}
+
+static void printk_lock(struct rt_mutex *lock, int print_owner)
+{
+       if (lock->name)
+               printk(" [%p] {%s}\n",
+                       lock, lock->name);
+       else
+               printk(" [%p] {%s:%d}\n",
+                       lock, lock->file, lock->line);
+
+       if (print_owner && rt_mutex_owner(lock)) {
+               printk(".. ->owner: %p\n", lock->owner);
+               printk(".. held by:  ");
+               printk_task(rt_mutex_owner(lock));
+               printk("\n");
+       }
+       if (rt_mutex_owner(lock)) {
+               printk("... acquired at:               ");
+               print_symbol("%s\n", lock->acquire_ip);
+       }
+}
+
+static void printk_waiter(struct rt_mutex_waiter *w)
+{
+       printk("-------------------------\n");
+       printk("| waiter struct %p:\n", w);
+       printk("| w->list_entry: [DP:%p/%p|SP:%p/%p|PRI:%d]\n",
+              w->list_entry.plist.prio_list.prev, w->list_entry.plist.prio_list.next,
+              w->list_entry.plist.node_list.prev, w->list_entry.plist.node_list.next,
+              w->list_entry.prio);
+       printk("| w->pi_list_entry: [DP:%p/%p|SP:%p/%p|PRI:%d]\n",
+              w->pi_list_entry.plist.prio_list.prev, w->pi_list_entry.plist.prio_list.next,
+              w->pi_list_entry.plist.node_list.prev, w->pi_list_entry.plist.node_list.next,
+              w->pi_list_entry.prio);
+       printk("\n| lock:\n");
+       printk_lock(w->lock, 1);
+       printk("| w->ti->task:\n");
+       printk_task(w->task);
+       printk("| blocked at:  ");
+       print_symbol("%s\n", w->ip);
+       printk("-------------------------\n");
+}
+
+static void show_task_locks(task_t *p)
+{
+       switch (p->state) {
+       case TASK_RUNNING:              printk("R"); break;
+       case TASK_INTERRUPTIBLE:        printk("S"); break;
+       case TASK_UNINTERRUPTIBLE:      printk("D"); break;
+       case TASK_STOPPED:              printk("T"); break;
+       case EXIT_ZOMBIE:               printk("Z"); break;
+       case EXIT_DEAD:                 printk("X"); break;
+       default:                        printk("?"); break;
+       }
+       printk_task(p);
+       if (p->pi_blocked_on) {
+               struct rt_mutex *lock = p->pi_blocked_on->lock;
+
+               printk(" blocked on:");
+               printk_lock(lock, 1);
+       } else
+               printk(" (not blocked)\n");
+}
+
+void rt_mutex_show_held_locks(task_t *task, int verbose)
+{
+       struct list_head *curr, *cursor = NULL;
+       struct rt_mutex *lock;
+       task_t *t;
+       unsigned long flags;
+       int count = 0;
+
+       if (!rt_trace_on)
+               return;
+
+       if (verbose) {
+               printk("------------------------------\n");
+               printk("| showing all locks held by: |  (");
+               printk_task_short(task);
+               printk("):\n");
+               printk("------------------------------\n");
+       }
+
+next:
+       spin_lock_irqsave(&task->held_list_lock, flags);
+       list_for_each(curr, &task->held_list_head) {
+               if (cursor && curr != cursor)
+                       continue;
+               lock = list_entry(curr, struct rt_mutex, held_list_entry);
+               t = rt_mutex_owner(lock);
+               WARN_ON(t != task);
+               count++;
+               cursor = curr->next;
+               spin_unlock_irqrestore(&task->held_list_lock, flags);
+
+               printk("\n#%03d:            ", count);
+               printk_lock(lock, 0);
+               goto next;
+       }
+       spin_unlock_irqrestore(&task->held_list_lock, flags);
+
+       printk("\n");
+}
+
+void rt_mutex_show_all_locks(void)
+{
+       task_t *g, *p;
+       int count = 10;
+       int unlock = 1;
+
+       printk("\n");
+       printk("----------------------\n");
+       printk("| showing all tasks: |\n");
+       printk("----------------------\n");
+
+       /*
+        * Here we try to get the tasklist_lock as hard as possible,
+        * if not successful after 2 seconds we ignore it (but keep
+        * trying). This is to enable a debug printout even if a
+        * tasklist_lock-holding task deadlocks or crashes.
+        */
+retry:
+       if (!read_trylock(&tasklist_lock)) {
+               if (count == 10)
+                       printk("hm, tasklist_lock locked, retrying... ");
+               if (count) {
+                       count--;
+                       printk(" #%d", 10-count);
+                       mdelay(200);
+                       goto retry;
+               }
+               printk(" ignoring it.\n");
+               unlock = 0;
+       }
+       if (count != 10)
+               printk(" locked it.\n");
+
+       do_each_thread(g, p) {
+               show_task_locks(p);
+               if (!unlock)
+                       if (read_trylock(&tasklist_lock))
+                               unlock = 1;
+       } while_each_thread(g, p);
+
+       printk("\n");
+
+       printk("-----------------------------------------\n");
+       printk("| showing all locks held in the system: |\n");
+       printk("-----------------------------------------\n");
+
+       do_each_thread(g, p) {
+               rt_mutex_show_held_locks(p, 0);
+               if (!unlock)
+                       if (read_trylock(&tasklist_lock))
+                               unlock = 1;
+       } while_each_thread(g, p);
+
+
+       printk("=============================================\n\n");
+
+       if (unlock)
+               read_unlock(&tasklist_lock);
+}
+
+void rt_mutex_debug_check_no_locks_held(task_t *task)
+{
+       struct rt_mutex_waiter *w;
+       struct list_head *curr;
+       struct rt_mutex *lock;
+
+       if (!rt_trace_on)
+               return;
+       if (!rt_prio(task->normal_prio) && rt_prio(task->prio)) {
+               printk("BUG: PI priority boost leaked!\n");
+               printk_task(task);
+               printk("\n");
+       }
+       if (list_empty(&task->held_list_head))
+               return;
+
+       spin_lock(&task->pi_lock);
+       plist_for_each_entry(w, &task->pi_waiters, pi_list_entry) {
+               TRACE_OFF();
+
+               printk("hm, PI interest held at exit time? Task:\n");
+               printk_task(task);
+               printk_waiter(w);
+               return;
+       }
+       spin_unlock(&task->pi_lock);
+
+       list_for_each(curr, &task->held_list_head) {
+               lock = list_entry(curr, struct rt_mutex, held_list_entry);
+
+               printk("BUG: %s/%d, lock held at task exit time!\n",
+                      task->comm, task->pid);
+               printk_lock(lock, 1);
+               if (rt_mutex_owner(lock) != task)
+                       printk("exiting task is not even the owner??\n");
+       }
+}
+
+int rt_mutex_debug_check_no_locks_freed(const void *from, unsigned long len)
+{
+       const void *to = from + len;
+       struct list_head *curr;
+       struct rt_mutex *lock;
+       unsigned long flags;
+       void *lock_addr;
+
+       if (!rt_trace_on)
+               return 0;
+
+       spin_lock_irqsave(&current->held_list_lock, flags);
+       list_for_each(curr, &current->held_list_head) {
+               lock = list_entry(curr, struct rt_mutex, held_list_entry);
+               lock_addr = lock;
+               if (lock_addr < from || lock_addr >= to)
+                       continue;
+               TRACE_OFF();
+
+               printk("BUG: %s/%d, active lock [%p(%p-%p)] freed!\n",
+                       current->comm, current->pid, lock, from, to);
+               dump_stack();
+               printk_lock(lock, 1);
+               if (rt_mutex_owner(lock) != current)
+                       printk("freeing task is not even the owner??\n");
+               return 1;
+       }
+       spin_unlock_irqrestore(&current->held_list_lock, flags);
+
+       return 0;
+}
+
+void rt_mutex_debug_task_free(struct task_struct *task)
+{
+       WARN_ON(!plist_head_empty(&task->pi_waiters));
+       WARN_ON(task->pi_blocked_on);
+}
+
+/*
+ * We fill out the fields in the waiter to store the information about
+ * the deadlock. We print when we return. act_waiter can be NULL in
+ * case of a remove waiter operation.
+ */
+void debug_rt_mutex_deadlock(int detect, struct rt_mutex_waiter *act_waiter,
+                            struct rt_mutex *lock)
+{
+       struct task_struct *task;
+
+       if (!rt_trace_on || detect || !act_waiter)
+               return;
+
+       task = rt_mutex_owner(act_waiter->lock);
+       if (task && task != current) {
+               act_waiter->deadlock_task_pid = task->pid;
+               act_waiter->deadlock_lock = lock;
+       }
+}
+
+void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter)
+{
+       struct task_struct *task;
+
+       if (!waiter->deadlock_lock || !rt_trace_on)
+               return;
+
+       task = find_task_by_pid(waiter->deadlock_task_pid);
+       if (!task)
+               return;
+
+       TRACE_OFF_NOLOCK();
+
+       printk("\n============================================\n");
+       printk(  "[ BUG: circular locking deadlock detected! ]\n");
+       printk(  "--------------------------------------------\n");
+       printk("%s/%d is deadlocking current task %s/%d\n\n",
+              task->comm, task->pid, current->comm, current->pid);
+
+       printk("\n1) %s/%d is trying to acquire this lock:\n",
+              current->comm, current->pid);
+       printk_lock(waiter->lock, 1);
+
+       printk("... trying at:                 ");
+       print_symbol("%s\n", waiter->ip);
+
+       printk("\n2) %s/%d is blocked on this lock:\n", task->comm, task->pid);
+       printk_lock(waiter->deadlock_lock, 1);
+
+       rt_mutex_show_held_locks(current, 1);
+       rt_mutex_show_held_locks(task, 1);
+
+       printk("\n%s/%d's [blocked] stackdump:\n\n", task->comm, task->pid);
+       show_stack(task, NULL);
+       printk("\n%s/%d's [current] stackdump:\n\n",
+              current->comm, current->pid);
+       dump_stack();
+       rt_mutex_show_all_locks();
+       printk("[ turning off deadlock detection."
+              "Please report this trace. ]\n\n");
+       local_irq_disable();
+}
+
+void debug_rt_mutex_lock(struct rt_mutex *lock __IP_DECL__)
+{
+       unsigned long flags;
+
+       if (rt_trace_on) {
+               TRACE_WARN_ON_LOCKED(!list_empty(&lock->held_list_entry));
+
+               spin_lock_irqsave(&current->held_list_lock, flags);
+               list_add_tail(&lock->held_list_entry, &current->held_list_head);
+               spin_unlock_irqrestore(&current->held_list_lock, flags);
+
+               lock->acquire_ip = ip;
+       }
+}
+
+void debug_rt_mutex_unlock(struct rt_mutex *lock)
+{
+       unsigned long flags;
+
+       if (rt_trace_on) {
+               TRACE_WARN_ON_LOCKED(rt_mutex_owner(lock) != current);
+               TRACE_WARN_ON_LOCKED(list_empty(&lock->held_list_entry));
+
+               spin_lock_irqsave(&current->held_list_lock, flags);
+               list_del_init(&lock->held_list_entry);
+               spin_unlock_irqrestore(&current->held_list_lock, flags);
+       }
+}
+
+void debug_rt_mutex_proxy_lock(struct rt_mutex *lock,
+                              struct task_struct *powner __IP_DECL__)
+{
+       unsigned long flags;
+
+       if (rt_trace_on) {
+               TRACE_WARN_ON_LOCKED(!list_empty(&lock->held_list_entry));
+
+               spin_lock_irqsave(&powner->held_list_lock, flags);
+               list_add_tail(&lock->held_list_entry, &powner->held_list_head);
+               spin_unlock_irqrestore(&powner->held_list_lock, flags);
+
+               lock->acquire_ip = ip;
+       }
+}
+
+void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock)
+{
+       unsigned long flags;
+
+       if (rt_trace_on) {
+               struct task_struct *owner = rt_mutex_owner(lock);
+
+               TRACE_WARN_ON_LOCKED(!owner);
+               TRACE_WARN_ON_LOCKED(list_empty(&lock->held_list_entry));
+
+               spin_lock_irqsave(&owner->held_list_lock, flags);
+               list_del_init(&lock->held_list_entry);
+               spin_unlock_irqrestore(&owner->held_list_lock, flags);
+       }
+}
+
+void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter)
+{
+       memset(waiter, 0x11, sizeof(*waiter));
+       plist_node_init(&waiter->list_entry, MAX_PRIO);
+       plist_node_init(&waiter->pi_list_entry, MAX_PRIO);
+}
+
+void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter)
+{
+       TRACE_WARN_ON(!plist_node_empty(&waiter->list_entry));
+       TRACE_WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
+       TRACE_WARN_ON(waiter->task);
+       memset(waiter, 0x22, sizeof(*waiter));
+}
+
+void debug_rt_mutex_init(struct rt_mutex *lock, const char *name)
+{
+       void *addr = lock;
+
+       if (rt_trace_on) {
+               rt_mutex_debug_check_no_locks_freed(addr,
+                                                   sizeof(struct rt_mutex));
+               INIT_LIST_HEAD(&lock->held_list_entry);
+               lock->name = name;
+       }
+}
+
+void rt_mutex_deadlock_account_lock(struct rt_mutex *lock, task_t *task)
+{
+}
+
+void rt_mutex_deadlock_account_unlock(struct task_struct *task)
+{
+}
+
diff --git a/kernel/rtmutex-debug.h b/kernel/rtmutex-debug.h
new file mode 100644 (file)
index 0000000..7612fbc
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * RT-Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This file contains macros used solely by rtmutex.c. Debug version.
+ */
+
+#define __IP_DECL__            , unsigned long ip
+#define __IP__                 , ip
+#define __RET_IP__             , (unsigned long)__builtin_return_address(0)
+
+extern void
+rt_mutex_deadlock_account_lock(struct rt_mutex *lock, struct task_struct *task);
+extern void rt_mutex_deadlock_account_unlock(struct task_struct *task);
+extern void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter);
+extern void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter);
+extern void debug_rt_mutex_init(struct rt_mutex *lock, const char *name);
+extern void debug_rt_mutex_lock(struct rt_mutex *lock __IP_DECL__);
+extern void debug_rt_mutex_unlock(struct rt_mutex *lock);
+extern void debug_rt_mutex_proxy_lock(struct rt_mutex *lock,
+                                     struct task_struct *powner __IP_DECL__);
+extern void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock);
+extern void debug_rt_mutex_deadlock(int detect, struct rt_mutex_waiter *waiter,
+                                   struct rt_mutex *lock);
+extern void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter);
+# define debug_rt_mutex_reset_waiter(w)                        \
+       do { (w)->deadlock_lock = NULL; } while (0)
+
+static inline int debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter,
+                                                int detect)
+{
+       return (waiter != NULL);
+}
diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c
new file mode 100644 (file)
index 0000000..e82c2f8
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * RT-Mutex-tester: scriptable tester for rt mutexes
+ *
+ * started by Thomas Gleixner:
+ *
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ */
+#include <linux/config.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+
+#include "rtmutex.h"
+
+#define MAX_RT_TEST_THREADS    8
+#define MAX_RT_TEST_MUTEXES    8
+
+static spinlock_t rttest_lock;
+static atomic_t rttest_event;
+
+struct test_thread_data {
+       int                     opcode;
+       int                     opdata;
+       int                     mutexes[MAX_RT_TEST_MUTEXES];
+       int                     bkl;
+       int                     event;
+       struct sys_device       sysdev;
+};
+
+static struct test_thread_data thread_data[MAX_RT_TEST_THREADS];
+static task_t *threads[MAX_RT_TEST_THREADS];
+static struct rt_mutex mutexes[MAX_RT_TEST_MUTEXES];
+
+enum test_opcodes {
+       RTTEST_NOP = 0,
+       RTTEST_SCHEDOT,         /* 1 Sched other, data = nice */
+       RTTEST_SCHEDRT,         /* 2 Sched fifo, data = prio */
+       RTTEST_LOCK,            /* 3 Lock uninterruptible, data = lockindex */
+       RTTEST_LOCKNOWAIT,      /* 4 Lock uninterruptible no wait in wakeup, data = lockindex */
+       RTTEST_LOCKINT,         /* 5 Lock interruptible, data = lockindex */
+       RTTEST_LOCKINTNOWAIT,   /* 6 Lock interruptible no wait in wakeup, data = lockindex */
+       RTTEST_LOCKCONT,        /* 7 Continue locking after the wakeup delay */
+       RTTEST_UNLOCK,          /* 8 Unlock, data = lockindex */
+       RTTEST_LOCKBKL,         /* 9 Lock BKL */
+       RTTEST_UNLOCKBKL,       /* 10 Unlock BKL */
+       RTTEST_SIGNAL,          /* 11 Signal other test thread, data = thread id */
+       RTTEST_RESETEVENT = 98, /* 98 Reset event counter */
+       RTTEST_RESET = 99,      /* 99 Reset all pending operations */
+};
+
+static int handle_op(struct test_thread_data *td, int lockwakeup)
+{
+       int i, id, ret = -EINVAL;
+
+       switch(td->opcode) {
+
+       case RTTEST_NOP:
+               return 0;
+
+       case RTTEST_LOCKCONT:
+               td->mutexes[td->opdata] = 1;
+               td->event = atomic_add_return(1, &rttest_event);
+               return 0;
+
+       case RTTEST_RESET:
+               for (i = 0; i < MAX_RT_TEST_MUTEXES; i++) {
+                       if (td->mutexes[i] == 4) {
+                               rt_mutex_unlock(&mutexes[i]);
+                               td->mutexes[i] = 0;
+                       }
+               }
+
+               if (!lockwakeup && td->bkl == 4) {
+                       unlock_kernel();
+                       td->bkl = 0;
+               }
+               return 0;
+
+       case RTTEST_RESETEVENT:
+               atomic_set(&rttest_event, 0);
+               return 0;
+
+       default:
+               if (lockwakeup)
+                       return ret;
+       }
+
+       switch(td->opcode) {
+
+       case RTTEST_LOCK:
+       case RTTEST_LOCKNOWAIT:
+               id = td->opdata;
+               if (id < 0 || id >= MAX_RT_TEST_MUTEXES)
+                       return ret;
+
+               td->mutexes[id] = 1;
+               td->event = atomic_add_return(1, &rttest_event);
+               rt_mutex_lock(&mutexes[id]);
+               td->event = atomic_add_return(1, &rttest_event);
+               td->mutexes[id] = 4;
+               return 0;
+
+       case RTTEST_LOCKINT:
+       case RTTEST_LOCKINTNOWAIT:
+               id = td->opdata;
+               if (id < 0 || id >= MAX_RT_TEST_MUTEXES)
+                       return ret;
+
+               td->mutexes[id] = 1;
+               td->event = atomic_add_return(1, &rttest_event);
+               ret = rt_mutex_lock_interruptible(&mutexes[id], 0);
+               td->event = atomic_add_return(1, &rttest_event);
+               td->mutexes[id] = ret ? 0 : 4;
+               return ret ? -EINTR : 0;
+
+       case RTTEST_UNLOCK:
+               id = td->opdata;
+               if (id < 0 || id >= MAX_RT_TEST_MUTEXES || td->mutexes[id] != 4)
+                       return ret;
+
+               td->event = atomic_add_return(1, &rttest_event);
+               rt_mutex_unlock(&mutexes[id]);
+               td->event = atomic_add_return(1, &rttest_event);
+               td->mutexes[id] = 0;
+               return 0;
+
+       case RTTEST_LOCKBKL:
+               if (td->bkl)
+                       return 0;
+               td->bkl = 1;
+               lock_kernel();
+               td->bkl = 4;
+               return 0;
+
+       case RTTEST_UNLOCKBKL:
+               if (td->bkl != 4)
+                       break;
+               unlock_kernel();
+               td->bkl = 0;
+               return 0;
+
+       default:
+               break;
+       }
+       return ret;
+}
+
+/*
+ * Schedule replacement for rtsem_down(). Only called for threads with
+ * PF_MUTEX_TESTER set.
+ *
+ * This allows us to have finegrained control over the event flow.
+ *
+ */
+void schedule_rt_mutex_test(struct rt_mutex *mutex)
+{
+       int tid, op, dat;
+       struct test_thread_data *td;
+
+       /* We have to lookup the task */
+       for (tid = 0; tid < MAX_RT_TEST_THREADS; tid++) {
+               if (threads[tid] == current)
+                       break;
+       }
+
+       BUG_ON(tid == MAX_RT_TEST_THREADS);
+
+       td = &thread_data[tid];
+
+       op = td->opcode;
+       dat = td->opdata;
+
+       switch (op) {
+       case RTTEST_LOCK:
+       case RTTEST_LOCKINT:
+       case RTTEST_LOCKNOWAIT:
+       case RTTEST_LOCKINTNOWAIT:
+               if (mutex != &mutexes[dat])
+                       break;
+
+               if (td->mutexes[dat] != 1)
+                       break;
+
+               td->mutexes[dat] = 2;
+               td->event = atomic_add_return(1, &rttest_event);
+               break;
+
+       case RTTEST_LOCKBKL:
+       default:
+               break;
+       }
+
+       schedule();
+
+
+       switch (op) {
+       case RTTEST_LOCK:
+       case RTTEST_LOCKINT:
+               if (mutex != &mutexes[dat])
+                       return;
+
+               if (td->mutexes[dat] != 2)
+                       return;
+
+               td->mutexes[dat] = 3;
+               td->event = atomic_add_return(1, &rttest_event);
+               break;
+
+       case RTTEST_LOCKNOWAIT:
+       case RTTEST_LOCKINTNOWAIT:
+               if (mutex != &mutexes[dat])
+                       return;
+
+               if (td->mutexes[dat] != 2)
+                       return;
+
+               td->mutexes[dat] = 1;
+               td->event = atomic_add_return(1, &rttest_event);
+               return;
+
+       case RTTEST_LOCKBKL:
+               return;
+       default:
+               return;
+       }
+
+       td->opcode = 0;
+
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (td->opcode > 0) {
+                       int ret;
+
+                       set_current_state(TASK_RUNNING);
+                       ret = handle_op(td, 1);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (td->opcode == RTTEST_LOCKCONT)
+                               break;
+                       td->opcode = ret;
+               }
+
+               /* Wait for the next command to be executed */
+               schedule();
+       }
+
+       /* Restore previous command and data */
+       td->opcode = op;
+       td->opdata = dat;
+}
+
+static int test_func(void *data)
+{
+       struct test_thread_data *td = data;
+       int ret;
+
+       current->flags |= PF_MUTEX_TESTER;
+       allow_signal(SIGHUP);
+
+       for(;;) {
+
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (td->opcode > 0) {
+                       set_current_state(TASK_RUNNING);
+                       ret = handle_op(td, 0);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       td->opcode = ret;
+               }
+
+               /* Wait for the next command to be executed */
+               schedule();
+
+               if (signal_pending(current))
+                       flush_signals(current);
+
+               if(kthread_should_stop())
+                       break;
+       }
+       return 0;
+}
+
+/**
+ * sysfs_test_command - interface for test commands
+ * @dev:       thread reference
+ * @buf:       command for actual step
+ * @count:     length of buffer
+ *
+ * command syntax:
+ *
+ * opcode:data
+ */
+static ssize_t sysfs_test_command(struct sys_device *dev, const char *buf,
+                                 size_t count)
+{
+       struct sched_param schedpar;
+       struct test_thread_data *td;
+       char cmdbuf[32];
+       int op, dat, tid, ret;
+
+       td = container_of(dev, struct test_thread_data, sysdev);
+       tid = td->sysdev.id;
+
+       /* strings from sysfs write are not 0 terminated! */
+       if (count >= sizeof(cmdbuf))
+               return -EINVAL;
+
+       /* strip of \n: */
+       if (buf[count-1] == '\n')
+               count--;
+       if (count < 1)
+               return -EINVAL;
+
+       memcpy(cmdbuf, buf, count);
+       cmdbuf[count] = 0;
+
+       if (sscanf(cmdbuf, "%d:%d", &op, &dat) != 2)
+               return -EINVAL;
+
+       switch (op) {
+       case RTTEST_SCHEDOT:
+               schedpar.sched_priority = 0;
+               ret = sched_setscheduler(threads[tid], SCHED_NORMAL, &schedpar);
+               if (ret)
+                       return ret;
+               set_user_nice(current, 0);
+               break;
+
+       case RTTEST_SCHEDRT:
+               schedpar.sched_priority = dat;
+               ret = sched_setscheduler(threads[tid], SCHED_FIFO, &schedpar);
+               if (ret)
+                       return ret;
+               break;
+
+       case RTTEST_SIGNAL:
+               send_sig(SIGHUP, threads[tid], 0);
+               break;
+
+       default:
+               if (td->opcode > 0)
+                       return -EBUSY;
+               td->opdata = dat;
+               td->opcode = op;
+               wake_up_process(threads[tid]);
+       }
+
+       return count;
+}
+
+/**
+ * sysfs_test_status - sysfs interface for rt tester
+ * @dev:       thread to query
+ * @buf:       char buffer to be filled with thread status info
+ */
+static ssize_t sysfs_test_status(struct sys_device *dev, char *buf)
+{
+       struct test_thread_data *td;
+       char *curr = buf;
+       task_t *tsk;
+       int i;
+
+       td = container_of(dev, struct test_thread_data, sysdev);
+       tsk = threads[td->sysdev.id];
+
+       spin_lock(&rttest_lock);
+
+       curr += sprintf(curr,
+               "O: %4d, E:%8d, S: 0x%08lx, P: %4d, N: %4d, B: %p, K: %d, M:",
+               td->opcode, td->event, tsk->state,
+                       (MAX_RT_PRIO - 1) - tsk->prio,
+                       (MAX_RT_PRIO - 1) - tsk->normal_prio,
+               tsk->pi_blocked_on, td->bkl);
+
+       for (i = MAX_RT_TEST_MUTEXES - 1; i >=0 ; i--)
+               curr += sprintf(curr, "%d", td->mutexes[i]);
+
+       spin_unlock(&rttest_lock);
+
+       curr += sprintf(curr, ", T: %p, R: %p\n", tsk,
+                       mutexes[td->sysdev.id].owner);
+
+       return curr - buf;
+}
+
+static SYSDEV_ATTR(status, 0600, sysfs_test_status, NULL);
+static SYSDEV_ATTR(command, 0600, NULL, sysfs_test_command);
+
+static struct sysdev_class rttest_sysclass = {
+       set_kset_name("rttest"),
+};
+
+static int init_test_thread(int id)
+{
+       thread_data[id].sysdev.cls = &rttest_sysclass;
+       thread_data[id].sysdev.id = id;
+
+       threads[id] = kthread_run(test_func, &thread_data[id], "rt-test-%d", id);
+       if (IS_ERR(threads[id]))
+               return PTR_ERR(threads[id]);
+
+       return sysdev_register(&thread_data[id].sysdev);
+}
+
+static int init_rttest(void)
+{
+       int ret, i;
+
+       spin_lock_init(&rttest_lock);
+
+       for (i = 0; i < MAX_RT_TEST_MUTEXES; i++)
+               rt_mutex_init(&mutexes[i]);
+
+       ret = sysdev_class_register(&rttest_sysclass);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < MAX_RT_TEST_THREADS; i++) {
+               ret = init_test_thread(i);
+               if (ret)
+                       break;
+               ret = sysdev_create_file(&thread_data[i].sysdev, &attr_status);
+               if (ret)
+                       break;
+               ret = sysdev_create_file(&thread_data[i].sysdev, &attr_command);
+               if (ret)
+                       break;
+       }
+
+       printk("Initializing RT-Tester: %s\n", ret ? "Failed" : "OK" );
+
+       return ret;
+}
+
+device_initcall(init_rttest);
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
new file mode 100644 (file)
index 0000000..45d6101
--- /dev/null
@@ -0,0 +1,990 @@
+/*
+ * RT-Mutexes: simple blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner.
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2005-2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *  Copyright (C) 2005 Kihon Technologies Inc., Steven Rostedt
+ *  Copyright (C) 2006 Esben Nielsen
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#include "rtmutex_common.h"
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# include "rtmutex-debug.h"
+#else
+# include "rtmutex.h"
+#endif
+
+/*
+ * lock->owner state tracking:
+ *
+ * lock->owner holds the task_struct pointer of the owner. Bit 0 and 1
+ * are used to keep track of the "owner is pending" and "lock has
+ * waiters" state.
+ *
+ * owner       bit1    bit0
+ * NULL                0       0       lock is free (fast acquire possible)
+ * NULL                0       1       invalid state
+ * NULL                1       0       Transitional State*
+ * NULL                1       1       invalid state
+ * taskpointer 0       0       lock is held (fast release possible)
+ * taskpointer 0       1       task is pending owner
+ * taskpointer 1       0       lock is held and has waiters
+ * taskpointer 1       1       task is pending owner and lock has more waiters
+ *
+ * Pending ownership is assigned to the top (highest priority)
+ * waiter of the lock, when the lock is released. The thread is woken
+ * up and can now take the lock. Until the lock is taken (bit 0
+ * cleared) a competing higher priority thread can steal the lock
+ * which puts the woken up thread back on the waiters list.
+ *
+ * The fast atomic compare exchange based acquire and release is only
+ * possible when bit 0 and 1 of lock->owner are 0.
+ *
+ * (*) There's a small time where the owner can be NULL and the
+ * "lock has waiters" bit is set.  This can happen when grabbing the lock.
+ * To prevent a cmpxchg of the owner releasing the lock, we need to set this
+ * bit before looking at the lock, hence the reason this is a transitional
+ * state.
+ */
+
+static void
+rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
+                  unsigned long mask)
+{
+       unsigned long val = (unsigned long)owner | mask;
+
+       if (rt_mutex_has_waiters(lock))
+               val |= RT_MUTEX_HAS_WAITERS;
+
+       lock->owner = (struct task_struct *)val;
+}
+
+static inline void clear_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       lock->owner = (struct task_struct *)
+                       ((unsigned long)lock->owner & ~RT_MUTEX_HAS_WAITERS);
+}
+
+static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       if (!rt_mutex_has_waiters(lock))
+               clear_rt_mutex_waiters(lock);
+}
+
+/*
+ * We can speed up the acquire/release, if the architecture
+ * supports cmpxchg and if there's no debugging state to be set up
+ */
+#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
+# define rt_mutex_cmpxchg(l,c,n)       (cmpxchg(&l->owner, c, n) == c)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       unsigned long owner, *p = (unsigned long *) &lock->owner;
+
+       do {
+               owner = *p;
+       } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
+}
+#else
+# define rt_mutex_cmpxchg(l,c,n)       (0)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       lock->owner = (struct task_struct *)
+                       ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
+}
+#endif
+
+/*
+ * Calculate task priority from the waiter list priority
+ *
+ * Return task->normal_prio when the waiter list is empty or when
+ * the waiter is not allowed to do priority boosting
+ */
+int rt_mutex_getprio(struct task_struct *task)
+{
+       if (likely(!task_has_pi_waiters(task)))
+               return task->normal_prio;
+
+       return min(task_top_pi_waiter(task)->pi_list_entry.prio,
+                  task->normal_prio);
+}
+
+/*
+ * Adjust the priority of a task, after its pi_waiters got modified.
+ *
+ * This can be both boosting and unboosting. task->pi_lock must be held.
+ */
+static void __rt_mutex_adjust_prio(struct task_struct *task)
+{
+       int prio = rt_mutex_getprio(task);
+
+       if (task->prio != prio)
+               rt_mutex_setprio(task, prio);
+}
+
+/*
+ * Adjust task priority (undo boosting). Called from the exit path of
+ * rt_mutex_slowunlock() and rt_mutex_slowlock().
+ *
+ * (Note: We do this outside of the protection of lock->wait_lock to
+ * allow the lock to be taken while or before we readjust the priority
+ * of task. We do not use the spin_xx_mutex() variants here as we are
+ * outside of the debug path.)
+ */
+static void rt_mutex_adjust_prio(struct task_struct *task)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&task->pi_lock, flags);
+       __rt_mutex_adjust_prio(task);
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+}
+
+/*
+ * Max number of times we'll walk the boosting chain:
+ */
+int max_lock_depth = 1024;
+
+/*
+ * Adjust the priority chain. Also used for deadlock detection.
+ * Decreases task's usage by one - may thus free the task.
+ * Returns 0 or -EDEADLK.
+ */
+static int rt_mutex_adjust_prio_chain(task_t *task,
+                                     int deadlock_detect,
+                                     struct rt_mutex *orig_lock,
+                                     struct rt_mutex_waiter *orig_waiter,
+                                     struct task_struct *top_task
+                                     __IP_DECL__)
+{
+       struct rt_mutex *lock;
+       struct rt_mutex_waiter *waiter, *top_waiter = orig_waiter;
+       int detect_deadlock, ret = 0, depth = 0;
+       unsigned long flags;
+
+       detect_deadlock = debug_rt_mutex_detect_deadlock(orig_waiter,
+                                                        deadlock_detect);
+
+       /*
+        * The (de)boosting is a step by step approach with a lot of
+        * pitfalls. We want this to be preemptible and we want hold a
+        * maximum of two locks per step. So we have to check
+        * carefully whether things change under us.
+        */
+ again:
+       if (++depth > max_lock_depth) {
+               static int prev_max;
+
+               /*
+                * Print this only once. If the admin changes the limit,
+                * print a new message when reaching the limit again.
+                */
+               if (prev_max != max_lock_depth) {
+                       prev_max = max_lock_depth;
+                       printk(KERN_WARNING "Maximum lock depth %d reached "
+                              "task: %s (%d)\n", max_lock_depth,
+                              top_task->comm, top_task->pid);
+               }
+               put_task_struct(task);
+
+               return deadlock_detect ? -EDEADLK : 0;
+       }
+ retry:
+       /*
+        * Task can not go away as we did a get_task() before !
+        */
+       spin_lock_irqsave(&task->pi_lock, flags);
+
+       waiter = task->pi_blocked_on;
+       /*
+        * Check whether the end of the boosting chain has been
+        * reached or the state of the chain has changed while we
+        * dropped the locks.
+        */
+       if (!waiter || !waiter->task)
+               goto out_unlock_pi;
+
+       if (top_waiter && (!task_has_pi_waiters(task) ||
+                          top_waiter != task_top_pi_waiter(task)))
+               goto out_unlock_pi;
+
+       /*
+        * When deadlock detection is off then we check, if further
+        * priority adjustment is necessary.
+        */
+       if (!detect_deadlock && waiter->list_entry.prio == task->prio)
+               goto out_unlock_pi;
+
+       lock = waiter->lock;
+       if (!spin_trylock(&lock->wait_lock)) {
+               spin_unlock_irqrestore(&task->pi_lock, flags);
+               cpu_relax();
+               goto retry;
+       }
+
+       /* Deadlock detection */
+       if (lock == orig_lock || rt_mutex_owner(lock) == top_task) {
+               debug_rt_mutex_deadlock(deadlock_detect, orig_waiter, lock);
+               spin_unlock(&lock->wait_lock);
+               ret = deadlock_detect ? -EDEADLK : 0;
+               goto out_unlock_pi;
+       }
+
+       top_waiter = rt_mutex_top_waiter(lock);
+
+       /* Requeue the waiter */
+       plist_del(&waiter->list_entry, &lock->wait_list);
+       waiter->list_entry.prio = task->prio;
+       plist_add(&waiter->list_entry, &lock->wait_list);
+
+       /* Release the task */
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+       put_task_struct(task);
+
+       /* Grab the next task */
+       task = rt_mutex_owner(lock);
+       spin_lock_irqsave(&task->pi_lock, flags);
+
+       if (waiter == rt_mutex_top_waiter(lock)) {
+               /* Boost the owner */
+               plist_del(&top_waiter->pi_list_entry, &task->pi_waiters);
+               waiter->pi_list_entry.prio = waiter->list_entry.prio;
+               plist_add(&waiter->pi_list_entry, &task->pi_waiters);
+               __rt_mutex_adjust_prio(task);
+
+       } else if (top_waiter == waiter) {
+               /* Deboost the owner */
+               plist_del(&waiter->pi_list_entry, &task->pi_waiters);
+               waiter = rt_mutex_top_waiter(lock);
+               waiter->pi_list_entry.prio = waiter->list_entry.prio;
+               plist_add(&waiter->pi_list_entry, &task->pi_waiters);
+               __rt_mutex_adjust_prio(task);
+       }
+
+       get_task_struct(task);
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+
+       top_waiter = rt_mutex_top_waiter(lock);
+       spin_unlock(&lock->wait_lock);
+
+       if (!detect_deadlock && waiter != top_waiter)
+               goto out_put_task;
+
+       goto again;
+
+ out_unlock_pi:
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+ out_put_task:
+       put_task_struct(task);
+       return ret;
+}
+
+/*
+ * Optimization: check if we can steal the lock from the
+ * assigned pending owner [which might not have taken the
+ * lock yet]:
+ */
+static inline int try_to_steal_lock(struct rt_mutex *lock)
+{
+       struct task_struct *pendowner = rt_mutex_owner(lock);
+       struct rt_mutex_waiter *next;
+       unsigned long flags;
+
+       if (!rt_mutex_owner_pending(lock))
+               return 0;
+
+       if (pendowner == current)
+               return 1;
+
+       spin_lock_irqsave(&pendowner->pi_lock, flags);
+       if (current->prio >= pendowner->prio) {
+               spin_unlock_irqrestore(&pendowner->pi_lock, flags);
+               return 0;
+       }
+
+       /*
+        * Check if a waiter is enqueued on the pending owners
+        * pi_waiters list. Remove it and readjust pending owners
+        * priority.
+        */
+       if (likely(!rt_mutex_has_waiters(lock))) {
+               spin_unlock_irqrestore(&pendowner->pi_lock, flags);
+               return 1;
+       }
+
+       /* No chain handling, pending owner is not blocked on anything: */
+       next = rt_mutex_top_waiter(lock);
+       plist_del(&next->pi_list_entry, &pendowner->pi_waiters);
+       __rt_mutex_adjust_prio(pendowner);
+       spin_unlock_irqrestore(&pendowner->pi_lock, flags);
+
+       /*
+        * We are going to steal the lock and a waiter was
+        * enqueued on the pending owners pi_waiters queue. So
+        * we have to enqueue this waiter into
+        * current->pi_waiters list. This covers the case,
+        * where current is boosted because it holds another
+        * lock and gets unboosted because the booster is
+        * interrupted, so we would delay a waiter with higher
+        * priority as current->normal_prio.
+        *
+        * Note: in the rare case of a SCHED_OTHER task changing
+        * its priority and thus stealing the lock, next->task
+        * might be current:
+        */
+       if (likely(next->task != current)) {
+               spin_lock_irqsave(&current->pi_lock, flags);
+               plist_add(&next->pi_list_entry, &current->pi_waiters);
+               __rt_mutex_adjust_prio(current);
+               spin_unlock_irqrestore(&current->pi_lock, flags);
+       }
+       return 1;
+}
+
+/*
+ * Try to take an rt-mutex
+ *
+ * This fails
+ * - when the lock has a real owner
+ * - when a different pending owner exists and has higher priority than current
+ *
+ * Must be called with lock->wait_lock held.
+ */
+static int try_to_take_rt_mutex(struct rt_mutex *lock __IP_DECL__)
+{
+       /*
+        * We have to be careful here if the atomic speedups are
+        * enabled, such that, when
+        *  - no other waiter is on the lock
+        *  - the lock has been released since we did the cmpxchg
+        * the lock can be released or taken while we are doing the
+        * checks and marking the lock with RT_MUTEX_HAS_WAITERS.
+        *
+        * The atomic acquire/release aware variant of
+        * mark_rt_mutex_waiters uses a cmpxchg loop. After setting
+        * the WAITERS bit, the atomic release / acquire can not
+        * happen anymore and lock->wait_lock protects us from the
+        * non-atomic case.
+        *
+        * Note, that this might set lock->owner =
+        * RT_MUTEX_HAS_WAITERS in the case the lock is not contended
+        * any more. This is fixed up when we take the ownership.
+        * This is the transitional state explained at the top of this file.
+        */
+       mark_rt_mutex_waiters(lock);
+
+       if (rt_mutex_owner(lock) && !try_to_steal_lock(lock))
+               return 0;
+
+       /* We got the lock. */
+       debug_rt_mutex_lock(lock __IP__);
+
+       rt_mutex_set_owner(lock, current, 0);
+
+       rt_mutex_deadlock_account_lock(lock, current);
+
+       return 1;
+}
+
+/*
+ * Task blocks on lock.
+ *
+ * Prepare waiter and propagate pi chain
+ *
+ * This must be called with lock->wait_lock held.
+ */
+static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
+                                  struct rt_mutex_waiter *waiter,
+                                  int detect_deadlock
+                                  __IP_DECL__)
+{
+       struct rt_mutex_waiter *top_waiter = waiter;
+       task_t *owner = rt_mutex_owner(lock);
+       int boost = 0, res;
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->pi_lock, flags);
+       __rt_mutex_adjust_prio(current);
+       waiter->task = current;
+       waiter->lock = lock;
+       plist_node_init(&waiter->list_entry, current->prio);
+       plist_node_init(&waiter->pi_list_entry, current->prio);
+
+       /* Get the top priority waiter on the lock */
+       if (rt_mutex_has_waiters(lock))
+               top_waiter = rt_mutex_top_waiter(lock);
+       plist_add(&waiter->list_entry, &lock->wait_list);
+
+       current->pi_blocked_on = waiter;
+
+       spin_unlock_irqrestore(&current->pi_lock, flags);
+
+       if (waiter == rt_mutex_top_waiter(lock)) {
+               spin_lock_irqsave(&owner->pi_lock, flags);
+               plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters);
+               plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
+
+               __rt_mutex_adjust_prio(owner);
+               if (owner->pi_blocked_on) {
+                       boost = 1;
+                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+                       get_task_struct(owner);
+               }
+               spin_unlock_irqrestore(&owner->pi_lock, flags);
+       }
+       else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) {
+               spin_lock_irqsave(&owner->pi_lock, flags);
+               if (owner->pi_blocked_on) {
+                       boost = 1;
+                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+                       get_task_struct(owner);
+               }
+               spin_unlock_irqrestore(&owner->pi_lock, flags);
+       }
+       if (!boost)
+               return 0;
+
+       spin_unlock(&lock->wait_lock);
+
+       res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter,
+                                        current __IP__);
+
+       spin_lock(&lock->wait_lock);
+
+       return res;
+}
+
+/*
+ * Wake up the next waiter on the lock.
+ *
+ * Remove the top waiter from the current tasks waiter list and from
+ * the lock waiter list. Set it as pending owner. Then wake it up.
+ *
+ * Called with lock->wait_lock held.
+ */
+static void wakeup_next_waiter(struct rt_mutex *lock)
+{
+       struct rt_mutex_waiter *waiter;
+       struct task_struct *pendowner;
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->pi_lock, flags);
+
+       waiter = rt_mutex_top_waiter(lock);
+       plist_del(&waiter->list_entry, &lock->wait_list);
+
+       /*
+        * Remove it from current->pi_waiters. We do not adjust a
+        * possible priority boost right now. We execute wakeup in the
+        * boosted mode and go back to normal after releasing
+        * lock->wait_lock.
+        */
+       plist_del(&waiter->pi_list_entry, &current->pi_waiters);
+       pendowner = waiter->task;
+       waiter->task = NULL;
+
+       rt_mutex_set_owner(lock, pendowner, RT_MUTEX_OWNER_PENDING);
+
+       spin_unlock_irqrestore(&current->pi_lock, flags);
+
+       /*
+        * Clear the pi_blocked_on variable and enqueue a possible
+        * waiter into the pi_waiters list of the pending owner. This
+        * prevents that in case the pending owner gets unboosted a
+        * waiter with higher priority than pending-owner->normal_prio
+        * is blocked on the unboosted (pending) owner.
+        */
+       spin_lock_irqsave(&pendowner->pi_lock, flags);
+
+       WARN_ON(!pendowner->pi_blocked_on);
+       WARN_ON(pendowner->pi_blocked_on != waiter);
+       WARN_ON(pendowner->pi_blocked_on->lock != lock);
+
+       pendowner->pi_blocked_on = NULL;
+
+       if (rt_mutex_has_waiters(lock)) {
+               struct rt_mutex_waiter *next;
+
+               next = rt_mutex_top_waiter(lock);
+               plist_add(&next->pi_list_entry, &pendowner->pi_waiters);
+       }
+       spin_unlock_irqrestore(&pendowner->pi_lock, flags);
+
+       wake_up_process(pendowner);
+}
+
+/*
+ * Remove a waiter from a lock
+ *
+ * Must be called with lock->wait_lock held
+ */
+static void remove_waiter(struct rt_mutex *lock,
+                         struct rt_mutex_waiter *waiter  __IP_DECL__)
+{
+       int first = (waiter == rt_mutex_top_waiter(lock));
+       int boost = 0;
+       task_t *owner = rt_mutex_owner(lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->pi_lock, flags);
+       plist_del(&waiter->list_entry, &lock->wait_list);
+       waiter->task = NULL;
+       current->pi_blocked_on = NULL;
+       spin_unlock_irqrestore(&current->pi_lock, flags);
+
+       if (first && owner != current) {
+
+               spin_lock_irqsave(&owner->pi_lock, flags);
+
+               plist_del(&waiter->pi_list_entry, &owner->pi_waiters);
+
+               if (rt_mutex_has_waiters(lock)) {
+                       struct rt_mutex_waiter *next;
+
+                       next = rt_mutex_top_waiter(lock);
+                       plist_add(&next->pi_list_entry, &owner->pi_waiters);
+               }
+               __rt_mutex_adjust_prio(owner);
+
+               if (owner->pi_blocked_on) {
+                       boost = 1;
+                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+                       get_task_struct(owner);
+               }
+               spin_unlock_irqrestore(&owner->pi_lock, flags);
+       }
+
+       WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
+
+       if (!boost)
+               return;
+
+       spin_unlock(&lock->wait_lock);
+
+       rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current __IP__);
+
+       spin_lock(&lock->wait_lock);
+}
+
+/*
+ * Recheck the pi chain, in case we got a priority setting
+ *
+ * Called from sched_setscheduler
+ */
+void rt_mutex_adjust_pi(struct task_struct *task)
+{
+       struct rt_mutex_waiter *waiter;
+       unsigned long flags;
+
+       spin_lock_irqsave(&task->pi_lock, flags);
+
+       waiter = task->pi_blocked_on;
+       if (!waiter || waiter->list_entry.prio == task->prio) {
+               spin_unlock_irqrestore(&task->pi_lock, flags);
+               return;
+       }
+
+       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+       get_task_struct(task);
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+
+       rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task __RET_IP__);
+}
+
+/*
+ * Slow path lock function:
+ */
+static int __sched
+rt_mutex_slowlock(struct rt_mutex *lock, int state,
+                 struct hrtimer_sleeper *timeout,
+                 int detect_deadlock __IP_DECL__)
+{
+       struct rt_mutex_waiter waiter;
+       int ret = 0;
+
+       debug_rt_mutex_init_waiter(&waiter);
+       waiter.task = NULL;
+
+       spin_lock(&lock->wait_lock);
+
+       /* Try to acquire the lock again: */
+       if (try_to_take_rt_mutex(lock __IP__)) {
+               spin_unlock(&lock->wait_lock);
+               return 0;
+       }
+
+       set_current_state(state);
+
+       /* Setup the timer, when timeout != NULL */
+       if (unlikely(timeout))
+               hrtimer_start(&timeout->timer, timeout->timer.expires,
+                             HRTIMER_ABS);
+
+       for (;;) {
+               /* Try to acquire the lock: */
+               if (try_to_take_rt_mutex(lock __IP__))
+                       break;
+
+               /*
+                * TASK_INTERRUPTIBLE checks for signals and
+                * timeout. Ignored otherwise.
+                */
+               if (unlikely(state == TASK_INTERRUPTIBLE)) {
+                       /* Signal pending? */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       if (timeout && !timeout->task)
+                               ret = -ETIMEDOUT;
+                       if (ret)
+                               break;
+               }
+
+               /*
+                * waiter.task is NULL the first time we come here and
+                * when we have been woken up by the previous owner
+                * but the lock got stolen by a higher prio task.
+                */
+               if (!waiter.task) {
+                       ret = task_blocks_on_rt_mutex(lock, &waiter,
+                                                     detect_deadlock __IP__);
+                       /*
+                        * If we got woken up by the owner then start loop
+                        * all over without going into schedule to try
+                        * to get the lock now:
+                        */
+                       if (unlikely(!waiter.task))
+                               continue;
+
+                       if (unlikely(ret))
+                               break;
+               }
+
+               spin_unlock(&lock->wait_lock);
+
+               debug_rt_mutex_print_deadlock(&waiter);
+
+               if (waiter.task)
+                       schedule_rt_mutex(lock);
+
+               spin_lock(&lock->wait_lock);
+               set_current_state(state);
+       }
+
+       set_current_state(TASK_RUNNING);
+
+       if (unlikely(waiter.task))
+               remove_waiter(lock, &waiter __IP__);
+
+       /*
+        * try_to_take_rt_mutex() sets the waiter bit
+        * unconditionally. We might have to fix that up.
+        */
+       fixup_rt_mutex_waiters(lock);
+
+       spin_unlock(&lock->wait_lock);
+
+       /* Remove pending timer: */
+       if (unlikely(timeout))
+               hrtimer_cancel(&timeout->timer);
+
+       /*
+        * Readjust priority, when we did not get the lock. We might
+        * have been the pending owner and boosted. Since we did not
+        * take the lock, the PI boost has to go.
+        */
+       if (unlikely(ret))
+               rt_mutex_adjust_prio(current);
+
+       debug_rt_mutex_free_waiter(&waiter);
+
+       return ret;
+}
+
+/*
+ * Slow path try-lock function:
+ */
+static inline int
+rt_mutex_slowtrylock(struct rt_mutex *lock __IP_DECL__)
+{
+       int ret = 0;
+
+       spin_lock(&lock->wait_lock);
+
+       if (likely(rt_mutex_owner(lock) != current)) {
+
+               ret = try_to_take_rt_mutex(lock __IP__);
+               /*
+                * try_to_take_rt_mutex() sets the lock waiters
+                * bit unconditionally. Clean this up.
+                */
+               fixup_rt_mutex_waiters(lock);
+       }
+
+       spin_unlock(&lock->wait_lock);
+
+       return ret;
+}
+
+/*
+ * Slow path to release a rt-mutex:
+ */
+static void __sched
+rt_mutex_slowunlock(struct rt_mutex *lock)
+{
+       spin_lock(&lock->wait_lock);
+
+       debug_rt_mutex_unlock(lock);
+
+       rt_mutex_deadlock_account_unlock(current);
+
+       if (!rt_mutex_has_waiters(lock)) {
+               lock->owner = NULL;
+               spin_unlock(&lock->wait_lock);
+               return;
+       }
+
+       wakeup_next_waiter(lock);
+
+       spin_unlock(&lock->wait_lock);
+
+       /* Undo pi boosting if necessary: */
+       rt_mutex_adjust_prio(current);
+}
+
+/*
+ * debug aware fast / slowpath lock,trylock,unlock
+ *
+ * The atomic acquire/release ops are compiled away, when either the
+ * architecture does not support cmpxchg or when debugging is enabled.
+ */
+static inline int
+rt_mutex_fastlock(struct rt_mutex *lock, int state,
+                 int detect_deadlock,
+                 int (*slowfn)(struct rt_mutex *lock, int state,
+                               struct hrtimer_sleeper *timeout,
+                               int detect_deadlock __IP_DECL__))
+{
+       if (!detect_deadlock && likely(rt_mutex_cmpxchg(lock, NULL, current))) {
+               rt_mutex_deadlock_account_lock(lock, current);
+               return 0;
+       } else
+               return slowfn(lock, state, NULL, detect_deadlock __RET_IP__);
+}
+
+static inline int
+rt_mutex_timed_fastlock(struct rt_mutex *lock, int state,
+                       struct hrtimer_sleeper *timeout, int detect_deadlock,
+                       int (*slowfn)(struct rt_mutex *lock, int state,
+                                     struct hrtimer_sleeper *timeout,
+                                     int detect_deadlock __IP_DECL__))
+{
+       if (!detect_deadlock && likely(rt_mutex_cmpxchg(lock, NULL, current))) {
+               rt_mutex_deadlock_account_lock(lock, current);
+               return 0;
+       } else
+               return slowfn(lock, state, timeout, detect_deadlock __RET_IP__);
+}
+
+static inline int
+rt_mutex_fasttrylock(struct rt_mutex *lock,
+                    int (*slowfn)(struct rt_mutex *lock __IP_DECL__))
+{
+       if (likely(rt_mutex_cmpxchg(lock, NULL, current))) {
+               rt_mutex_deadlock_account_lock(lock, current);
+               return 1;
+       }
+       return slowfn(lock __RET_IP__);
+}
+
+static inline void
+rt_mutex_fastunlock(struct rt_mutex *lock,
+                   void (*slowfn)(struct rt_mutex *lock))
+{
+       if (likely(rt_mutex_cmpxchg(lock, current, NULL)))
+               rt_mutex_deadlock_account_unlock(current);
+       else
+               slowfn(lock);
+}
+
+/**
+ * rt_mutex_lock - lock a rt_mutex
+ *
+ * @lock: the rt_mutex to be locked
+ */
+void __sched rt_mutex_lock(struct rt_mutex *lock)
+{
+       might_sleep();
+
+       rt_mutex_fastlock(lock, TASK_UNINTERRUPTIBLE, 0, rt_mutex_slowlock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_lock);
+
+/**
+ * rt_mutex_lock_interruptible - lock a rt_mutex interruptible
+ *
+ * @lock:              the rt_mutex to be locked
+ * @detect_deadlock:   deadlock detection on/off
+ *
+ * Returns:
+ *  0          on success
+ * -EINTR      when interrupted by a signal
+ * -EDEADLK    when the lock would deadlock (when deadlock detection is on)
+ */
+int __sched rt_mutex_lock_interruptible(struct rt_mutex *lock,
+                                                int detect_deadlock)
+{
+       might_sleep();
+
+       return rt_mutex_fastlock(lock, TASK_INTERRUPTIBLE,
+                                detect_deadlock, rt_mutex_slowlock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible);
+
+/**
+ * rt_mutex_lock_interruptible_ktime - lock a rt_mutex interruptible
+ *                                    the timeout structure is provided
+ *                                    by the caller
+ *
+ * @lock:              the rt_mutex to be locked
+ * @timeout:           timeout structure or NULL (no timeout)
+ * @detect_deadlock:   deadlock detection on/off
+ *
+ * Returns:
+ *  0          on success
+ * -EINTR      when interrupted by a signal
+ * -ETIMEOUT   when the timeout expired
+ * -EDEADLK    when the lock would deadlock (when deadlock detection is on)
+ */
+int
+rt_mutex_timed_lock(struct rt_mutex *lock, struct hrtimer_sleeper *timeout,
+                   int detect_deadlock)
+{
+       might_sleep();
+
+       return rt_mutex_timed_fastlock(lock, TASK_INTERRUPTIBLE, timeout,
+                                      detect_deadlock, rt_mutex_slowlock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_timed_lock);
+
+/**
+ * rt_mutex_trylock - try to lock a rt_mutex
+ *
+ * @lock:      the rt_mutex to be locked
+ *
+ * Returns 1 on success and 0 on contention
+ */
+int __sched rt_mutex_trylock(struct rt_mutex *lock)
+{
+       return rt_mutex_fasttrylock(lock, rt_mutex_slowtrylock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_trylock);
+
+/**
+ * rt_mutex_unlock - unlock a rt_mutex
+ *
+ * @lock: the rt_mutex to be unlocked
+ */
+void __sched rt_mutex_unlock(struct rt_mutex *lock)
+{
+       rt_mutex_fastunlock(lock, rt_mutex_slowunlock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_unlock);
+
+/***
+ * rt_mutex_destroy - mark a mutex unusable
+ * @lock: the mutex to be destroyed
+ *
+ * This function marks the mutex uninitialized, and any subsequent
+ * use of the mutex is forbidden. The mutex must not be locked when
+ * this function is called.
+ */
+void rt_mutex_destroy(struct rt_mutex *lock)
+{
+       WARN_ON(rt_mutex_is_locked(lock));
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+       lock->magic = NULL;
+#endif
+}
+
+EXPORT_SYMBOL_GPL(rt_mutex_destroy);
+
+/**
+ * __rt_mutex_init - initialize the rt lock
+ *
+ * @lock: the rt lock to be initialized
+ *
+ * Initialize the rt lock to unlocked state.
+ *
+ * Initializing of a locked rt lock is not allowed
+ */
+void __rt_mutex_init(struct rt_mutex *lock, const char *name)
+{
+       lock->owner = NULL;
+       spin_lock_init(&lock->wait_lock);
+       plist_head_init(&lock->wait_list, &lock->wait_lock);
+
+       debug_rt_mutex_init(lock, name);
+}
+EXPORT_SYMBOL_GPL(__rt_mutex_init);
+
+/**
+ * rt_mutex_init_proxy_locked - initialize and lock a rt_mutex on behalf of a
+ *                             proxy owner
+ *
+ * @lock:      the rt_mutex to be locked
+ * @proxy_owner:the task to set as owner
+ *
+ * No locking. Caller has to do serializing itself
+ * Special API call for PI-futex support
+ */
+void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
+                               struct task_struct *proxy_owner)
+{
+       __rt_mutex_init(lock, NULL);
+       debug_rt_mutex_proxy_lock(lock, proxy_owner __RET_IP__);
+       rt_mutex_set_owner(lock, proxy_owner, 0);
+       rt_mutex_deadlock_account_lock(lock, proxy_owner);
+}
+
+/**
+ * rt_mutex_proxy_unlock - release a lock on behalf of owner
+ *
+ * @lock:      the rt_mutex to be locked
+ *
+ * No locking. Caller has to do serializing itself
+ * Special API call for PI-futex support
+ */
+void rt_mutex_proxy_unlock(struct rt_mutex *lock,
+                          struct task_struct *proxy_owner)
+{
+       debug_rt_mutex_proxy_unlock(lock);
+       rt_mutex_set_owner(lock, NULL, 0);
+       rt_mutex_deadlock_account_unlock(proxy_owner);
+}
+
+/**
+ * rt_mutex_next_owner - return the next owner of the lock
+ *
+ * @lock: the rt lock query
+ *
+ * Returns the next owner of the lock or NULL
+ *
+ * Caller has to serialize against other accessors to the lock
+ * itself.
+ *
+ * Special API call for PI-futex support
+ */
+struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock)
+{
+       if (!rt_mutex_has_waiters(lock))
+               return NULL;
+
+       return rt_mutex_top_waiter(lock)->task;
+}
diff --git a/kernel/rtmutex.h b/kernel/rtmutex.h
new file mode 100644 (file)
index 0000000..1e0fca1
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * RT-Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This file contains macros used solely by rtmutex.c.
+ * Non-debug version.
+ */
+
+#define __IP_DECL__
+#define __IP__
+#define __RET_IP__
+#define rt_mutex_deadlock_check(l)                     (0)
+#define rt_mutex_deadlock_account_lock(m, t)           do { } while (0)
+#define rt_mutex_deadlock_account_unlock(l)            do { } while (0)
+#define debug_rt_mutex_init_waiter(w)                  do { } while (0)
+#define debug_rt_mutex_free_waiter(w)                  do { } while (0)
+#define debug_rt_mutex_lock(l)                         do { } while (0)
+#define debug_rt_mutex_proxy_lock(l,p)                 do { } while (0)
+#define debug_rt_mutex_proxy_unlock(l)                 do { } while (0)
+#define debug_rt_mutex_unlock(l)                       do { } while (0)
+#define debug_rt_mutex_init(m, n)                      do { } while (0)
+#define debug_rt_mutex_deadlock(d, a ,l)               do { } while (0)
+#define debug_rt_mutex_print_deadlock(w)               do { } while (0)
+#define debug_rt_mutex_detect_deadlock(w,d)            (d)
+#define debug_rt_mutex_reset_waiter(w)                 do { } while (0)
diff --git a/kernel/rtmutex_common.h b/kernel/rtmutex_common.h
new file mode 100644 (file)
index 0000000..9c75856
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * RT Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This file contains the private data structure and API definitions.
+ */
+
+#ifndef __KERNEL_RTMUTEX_COMMON_H
+#define __KERNEL_RTMUTEX_COMMON_H
+
+#include <linux/rtmutex.h>
+
+/*
+ * The rtmutex in kernel tester is independent of rtmutex debugging. We
+ * call schedule_rt_mutex_test() instead of schedule() for the tasks which
+ * belong to the tester. That way we can delay the wakeup path of those
+ * threads to provoke lock stealing and testing of  complex boosting scenarios.
+ */
+#ifdef CONFIG_RT_MUTEX_TESTER
+
+extern void schedule_rt_mutex_test(struct rt_mutex *lock);
+
+#define schedule_rt_mutex(_lock)                               \
+  do {                                                         \
+       if (!(current->flags & PF_MUTEX_TESTER))                \
+               schedule();                                     \
+       else                                                    \
+               schedule_rt_mutex_test(_lock);                  \
+  } while (0)
+
+#else
+# define schedule_rt_mutex(_lock)                      schedule()
+#endif
+
+/*
+ * This is the control structure for tasks blocked on a rt_mutex,
+ * which is allocated on the kernel stack on of the blocked task.
+ *
+ * @list_entry:                pi node to enqueue into the mutex waiters list
+ * @pi_list_entry:     pi node to enqueue into the mutex owner waiters list
+ * @task:              task reference to the blocked task
+ */
+struct rt_mutex_waiter {
+       struct plist_node       list_entry;
+       struct plist_node       pi_list_entry;
+       struct task_struct      *task;
+       struct rt_mutex         *lock;
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+       unsigned long           ip;
+       pid_t                   deadlock_task_pid;
+       struct rt_mutex         *deadlock_lock;
+#endif
+};
+
+/*
+ * Various helpers to access the waiters-plist:
+ */
+static inline int rt_mutex_has_waiters(struct rt_mutex *lock)
+{
+       return !plist_head_empty(&lock->wait_list);
+}
+
+static inline struct rt_mutex_waiter *
+rt_mutex_top_waiter(struct rt_mutex *lock)
+{
+       struct rt_mutex_waiter *w;
+
+       w = plist_first_entry(&lock->wait_list, struct rt_mutex_waiter,
+                              list_entry);
+       BUG_ON(w->lock != lock);
+
+       return w;
+}
+
+static inline int task_has_pi_waiters(struct task_struct *p)
+{
+       return !plist_head_empty(&p->pi_waiters);
+}
+
+static inline struct rt_mutex_waiter *
+task_top_pi_waiter(struct task_struct *p)
+{
+       return plist_first_entry(&p->pi_waiters, struct rt_mutex_waiter,
+                                 pi_list_entry);
+}
+
+/*
+ * lock->owner state tracking:
+ */
+#define RT_MUTEX_OWNER_PENDING 1UL
+#define RT_MUTEX_HAS_WAITERS   2UL
+#define RT_MUTEX_OWNER_MASKALL 3UL
+
+static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock)
+{
+       return (struct task_struct *)
+               ((unsigned long)lock->owner & ~RT_MUTEX_OWNER_MASKALL);
+}
+
+static inline struct task_struct *rt_mutex_real_owner(struct rt_mutex *lock)
+{
+       return (struct task_struct *)
+               ((unsigned long)lock->owner & ~RT_MUTEX_HAS_WAITERS);
+}
+
+static inline unsigned long rt_mutex_owner_pending(struct rt_mutex *lock)
+{
+       return (unsigned long)lock->owner & RT_MUTEX_OWNER_PENDING;
+}
+
+/*
+ * PI-futex support (proxy locking functions, etc.):
+ */
+extern struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock);
+extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
+                                      struct task_struct *proxy_owner);
+extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
+                                 struct task_struct *proxy_owner);
+#endif
index a856040c200a4213bd8b0b2d8b469e25bcc1d57f..2629c1711fd62be84574153e0ae62077895f3b36 100644 (file)
  */
 
 #define SCALE_PRIO(x, prio) \
-       max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)
+       max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
 
-static unsigned int task_timeslice(task_t *p)
+static unsigned int static_prio_timeslice(int static_prio)
 {
-       if (p->static_prio < NICE_TO_PRIO(0))
-               return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);
+       if (static_prio < NICE_TO_PRIO(0))
+               return SCALE_PRIO(DEF_TIMESLICE * 4, static_prio);
        else
-               return SCALE_PRIO(DEF_TIMESLICE, p->static_prio);
+               return SCALE_PRIO(DEF_TIMESLICE, static_prio);
 }
+
+static inline unsigned int task_timeslice(task_t *p)
+{
+       return static_prio_timeslice(p->static_prio);
+}
+
 #define task_hot(p, now, sd) ((long long) ((now) - (p)->last_ran)      \
                                < (long long) (sd)->cache_hot_time)
 
@@ -184,13 +190,11 @@ static unsigned int task_timeslice(task_t *p)
  * These are the runqueue data structures:
  */
 
-#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
-
 typedef struct runqueue runqueue_t;
 
 struct prio_array {
        unsigned int nr_active;
-       unsigned long bitmap[BITMAP_SIZE];
+       DECLARE_BITMAP(bitmap, MAX_PRIO+1); /* include 1 bit for delimiter */
        struct list_head queue[MAX_PRIO];
 };
 
@@ -209,6 +213,7 @@ struct runqueue {
         * remote CPUs use both these fields when doing load calculation.
         */
        unsigned long nr_running;
+       unsigned long raw_weighted_load;
 #ifdef CONFIG_SMP
        unsigned long cpu_load[3];
 #endif
@@ -239,7 +244,6 @@ struct runqueue {
 
        task_t *migration_thread;
        struct list_head migration_queue;
-       int cpu;
 #endif
 
 #ifdef CONFIG_SCHEDSTATS
@@ -350,12 +354,31 @@ static inline void finish_lock_switch(runqueue_t *rq, task_t *prev)
 }
 #endif /* __ARCH_WANT_UNLOCKED_CTXSW */
 
+/*
+ * __task_rq_lock - lock the runqueue a given task resides on.
+ * Must be called interrupts disabled.
+ */
+static inline runqueue_t *__task_rq_lock(task_t *p)
+       __acquires(rq->lock)
+{
+       struct runqueue *rq;
+
+repeat_lock_task:
+       rq = task_rq(p);
+       spin_lock(&rq->lock);
+       if (unlikely(rq != task_rq(p))) {
+               spin_unlock(&rq->lock);
+               goto repeat_lock_task;
+       }
+       return rq;
+}
+
 /*
  * task_rq_lock - lock the runqueue a given task resides on and disable
  * interrupts.  Note the ordering: we can safely lookup the task_rq without
  * explicitly disabling preemption.
  */
-static inline runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
+static runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
        __acquires(rq->lock)
 {
        struct runqueue *rq;
@@ -371,6 +394,12 @@ repeat_lock_task:
        return rq;
 }
 
+static inline void __task_rq_unlock(runqueue_t *rq)
+       __releases(rq->lock)
+{
+       spin_unlock(&rq->lock);
+}
+
 static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags)
        __releases(rq->lock)
 {
@@ -634,7 +663,7 @@ static inline void enqueue_task_head(struct task_struct *p, prio_array_t *array)
 }
 
 /*
- * effective_prio - return the priority that is based on the static
+ * __normal_prio - return the priority that is based on the static
  * priority but is modified by bonuses/penalties.
  *
  * We scale the actual sleep average [0 .... MAX_SLEEP_AVG]
@@ -647,13 +676,11 @@ static inline void enqueue_task_head(struct task_struct *p, prio_array_t *array)
  *
  * Both properties are important to certain workloads.
  */
-static int effective_prio(task_t *p)
+
+static inline int __normal_prio(task_t *p)
 {
        int bonus, prio;
 
-       if (rt_task(p))
-               return p->prio;
-
        bonus = CURRENT_BONUS(p) - MAX_BONUS / 2;
 
        prio = p->static_prio - bonus;
@@ -664,6 +691,106 @@ static int effective_prio(task_t *p)
        return prio;
 }
 
+/*
+ * To aid in avoiding the subversion of "niceness" due to uneven distribution
+ * of tasks with abnormal "nice" values across CPUs the contribution that
+ * each task makes to its run queue's load is weighted according to its
+ * scheduling class and "nice" value.  For SCHED_NORMAL tasks this is just a
+ * scaled version of the new time slice allocation that they receive on time
+ * slice expiry etc.
+ */
+
+/*
+ * Assume: static_prio_timeslice(NICE_TO_PRIO(0)) == DEF_TIMESLICE
+ * If static_prio_timeslice() is ever changed to break this assumption then
+ * this code will need modification
+ */
+#define TIME_SLICE_NICE_ZERO DEF_TIMESLICE
+#define LOAD_WEIGHT(lp) \
+       (((lp) * SCHED_LOAD_SCALE) / TIME_SLICE_NICE_ZERO)
+#define PRIO_TO_LOAD_WEIGHT(prio) \
+       LOAD_WEIGHT(static_prio_timeslice(prio))
+#define RTPRIO_TO_LOAD_WEIGHT(rp) \
+       (PRIO_TO_LOAD_WEIGHT(MAX_RT_PRIO) + LOAD_WEIGHT(rp))
+
+static void set_load_weight(task_t *p)
+{
+       if (has_rt_policy(p)) {
+#ifdef CONFIG_SMP
+               if (p == task_rq(p)->migration_thread)
+                       /*
+                        * The migration thread does the actual balancing.
+                        * Giving its load any weight will skew balancing
+                        * adversely.
+                        */
+                       p->load_weight = 0;
+               else
+#endif
+                       p->load_weight = RTPRIO_TO_LOAD_WEIGHT(p->rt_priority);
+       } else
+               p->load_weight = PRIO_TO_LOAD_WEIGHT(p->static_prio);
+}
+
+static inline void inc_raw_weighted_load(runqueue_t *rq, const task_t *p)
+{
+       rq->raw_weighted_load += p->load_weight;
+}
+
+static inline void dec_raw_weighted_load(runqueue_t *rq, const task_t *p)
+{
+       rq->raw_weighted_load -= p->load_weight;
+}
+
+static inline void inc_nr_running(task_t *p, runqueue_t *rq)
+{
+       rq->nr_running++;
+       inc_raw_weighted_load(rq, p);
+}
+
+static inline void dec_nr_running(task_t *p, runqueue_t *rq)
+{
+       rq->nr_running--;
+       dec_raw_weighted_load(rq, p);
+}
+
+/*
+ * Calculate the expected normal priority: i.e. priority
+ * without taking RT-inheritance into account. Might be
+ * boosted by interactivity modifiers. Changes upon fork,
+ * setprio syscalls, and whenever the interactivity
+ * estimator recalculates.
+ */
+static inline int normal_prio(task_t *p)
+{
+       int prio;
+
+       if (has_rt_policy(p))
+               prio = MAX_RT_PRIO-1 - p->rt_priority;
+       else
+               prio = __normal_prio(p);
+       return prio;
+}
+
+/*
+ * Calculate the current priority, i.e. the priority
+ * taken into account by the scheduler. This value might
+ * be boosted by RT tasks, or might be boosted by
+ * interactivity modifiers. Will be RT if the task got
+ * RT-boosted. If not then it returns p->normal_prio.
+ */
+static int effective_prio(task_t *p)
+{
+       p->normal_prio = normal_prio(p);
+       /*
+        * If we are RT tasks or we were boosted to RT priority,
+        * keep the priority unchanged. Otherwise, update priority
+        * to the normal priority:
+        */
+       if (!rt_prio(p->prio))
+               return p->normal_prio;
+       return p->prio;
+}
+
 /*
  * __activate_task - move a task to the runqueue.
  */
@@ -674,7 +801,7 @@ static void __activate_task(task_t *p, runqueue_t *rq)
        if (batch_task(p))
                target = rq->expired;
        enqueue_task(p, target);
-       rq->nr_running++;
+       inc_nr_running(p, rq);
 }
 
 /*
@@ -683,39 +810,45 @@ static void __activate_task(task_t *p, runqueue_t *rq)
 static inline void __activate_idle_task(task_t *p, runqueue_t *rq)
 {
        enqueue_task_head(p, rq->active);
-       rq->nr_running++;
+       inc_nr_running(p, rq);
 }
 
+/*
+ * Recalculate p->normal_prio and p->prio after having slept,
+ * updating the sleep-average too:
+ */
 static int recalc_task_prio(task_t *p, unsigned long long now)
 {
        /* Caller must always ensure 'now >= p->timestamp' */
-       unsigned long long __sleep_time = now - p->timestamp;
-       unsigned long sleep_time;
+       unsigned long sleep_time = now - p->timestamp;
 
        if (batch_task(p))
                sleep_time = 0;
-       else {
-               if (__sleep_time > NS_MAX_SLEEP_AVG)
-                       sleep_time = NS_MAX_SLEEP_AVG;
-               else
-                       sleep_time = (unsigned long)__sleep_time;
-       }
 
        if (likely(sleep_time > 0)) {
                /*
-                * User tasks that sleep a long time are categorised as
-                * idle. They will only have their sleep_avg increased to a
-                * level that makes them just interactive priority to stay
-                * active yet prevent them suddenly becoming cpu hogs and
-                * starving other processes.
+                * This ceiling is set to the lowest priority that would allow
+                * a task to be reinserted into the active array on timeslice
+                * completion.
                 */
-               if (p->mm && sleep_time > INTERACTIVE_SLEEP(p)) {
-                               unsigned long ceiling;
+               unsigned long ceiling = INTERACTIVE_SLEEP(p);
 
-                               ceiling = JIFFIES_TO_NS(MAX_SLEEP_AVG -
-                                       DEF_TIMESLICE);
-                               if (p->sleep_avg < ceiling)
-                                       p->sleep_avg = ceiling;
+               if (p->mm && sleep_time > ceiling && p->sleep_avg < ceiling) {
+                       /*
+                        * Prevents user tasks from achieving best priority
+                        * with one single large enough sleep.
+                        */
+                       p->sleep_avg = ceiling;
+                       /*
+                        * Using INTERACTIVE_SLEEP() as a ceiling places a
+                        * nice(0) task 1ms sleep away from promotion, and
+                        * gives it 700ms to round-robin with no chance of
+                        * being demoted.  This is more than generous, so
+                        * mark this sleep as non-interactive to prevent the
+                        * on-runqueue bonus logic from intervening should
+                        * this task not receive cpu immediately.
+                        */
+                       p->sleep_type = SLEEP_NONINTERACTIVE;
                } else {
                        /*
                         * Tasks waking from uninterruptible sleep are
@@ -723,12 +856,12 @@ static int recalc_task_prio(task_t *p, unsigned long long now)
                         * are likely to be waiting on I/O
                         */
                        if (p->sleep_type == SLEEP_NONINTERACTIVE && p->mm) {
-                               if (p->sleep_avg >= INTERACTIVE_SLEEP(p))
+                               if (p->sleep_avg >= ceiling)
                                        sleep_time = 0;
                                else if (p->sleep_avg + sleep_time >=
-                                               INTERACTIVE_SLEEP(p)) {
-                                       p->sleep_avg = INTERACTIVE_SLEEP(p);
-                                       sleep_time = 0;
+                                        ceiling) {
+                                               p->sleep_avg = ceiling;
+                                               sleep_time = 0;
                                }
                        }
 
@@ -742,9 +875,9 @@ static int recalc_task_prio(task_t *p, unsigned long long now)
                         */
                        p->sleep_avg += sleep_time;
 
-                       if (p->sleep_avg > NS_MAX_SLEEP_AVG)
-                               p->sleep_avg = NS_MAX_SLEEP_AVG;
                }
+               if (p->sleep_avg > NS_MAX_SLEEP_AVG)
+                       p->sleep_avg = NS_MAX_SLEEP_AVG;
        }
 
        return effective_prio(p);
@@ -805,7 +938,7 @@ static void activate_task(task_t *p, runqueue_t *rq, int local)
  */
 static void deactivate_task(struct task_struct *p, runqueue_t *rq)
 {
-       rq->nr_running--;
+       dec_nr_running(p, rq);
        dequeue_task(p, p->array);
        p->array = NULL;
 }
@@ -860,6 +993,12 @@ inline int task_curr(const task_t *p)
        return cpu_curr(task_cpu(p)) == p;
 }
 
+/* Used instead of source_load when we know the type == 0 */
+unsigned long weighted_cpuload(const int cpu)
+{
+       return cpu_rq(cpu)->raw_weighted_load;
+}
+
 #ifdef CONFIG_SMP
 typedef struct {
        struct list_head list;
@@ -949,7 +1088,8 @@ void kick_process(task_t *p)
 }
 
 /*
- * Return a low guess at the load of a migration-source cpu.
+ * Return a low guess at the load of a migration-source cpu weighted
+ * according to the scheduling class and "nice" value.
  *
  * We want to under-estimate the load of migration sources, to
  * balance conservatively.
@@ -957,24 +1097,36 @@ void kick_process(task_t *p)
 static inline unsigned long source_load(int cpu, int type)
 {
        runqueue_t *rq = cpu_rq(cpu);
-       unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+
        if (type == 0)
-               return load_now;
+               return rq->raw_weighted_load;
 
-       return min(rq->cpu_load[type-1], load_now);
+       return min(rq->cpu_load[type-1], rq->raw_weighted_load);
 }
 
 /*
- * Return a high guess at the load of a migration-target cpu
+ * Return a high guess at the load of a migration-target cpu weighted
+ * according to the scheduling class and "nice" value.
  */
 static inline unsigned long target_load(int cpu, int type)
 {
        runqueue_t *rq = cpu_rq(cpu);
-       unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+
        if (type == 0)
-               return load_now;
+               return rq->raw_weighted_load;
+
+       return max(rq->cpu_load[type-1], rq->raw_weighted_load);
+}
+
+/*
+ * Return the average load per task on the cpu's run queue
+ */
+static inline unsigned long cpu_avg_load_per_task(int cpu)
+{
+       runqueue_t *rq = cpu_rq(cpu);
+       unsigned long n = rq->nr_running;
 
-       return max(rq->cpu_load[type-1], load_now);
+       return n ?  rq->raw_weighted_load / n : SCHED_LOAD_SCALE;
 }
 
 /*
@@ -1047,7 +1199,7 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
        cpus_and(tmp, group->cpumask, p->cpus_allowed);
 
        for_each_cpu_mask(i, tmp) {
-               load = source_load(i, 0);
+               load = weighted_cpuload(i);
 
                if (load < min_load || (load == min_load && i == this_cpu)) {
                        min_load = load;
@@ -1074,9 +1226,15 @@ static int sched_balance_self(int cpu, int flag)
        struct task_struct *t = current;
        struct sched_domain *tmp, *sd = NULL;
 
-       for_each_domain(cpu, tmp)
+       for_each_domain(cpu, tmp) {
+               /*
+                * If power savings logic is enabled for a domain, stop there.
+                */
+               if (tmp->flags & SD_POWERSAVINGS_BALANCE)
+                       break;
                if (tmp->flags & flag)
                        sd = tmp;
+       }
 
        while (sd) {
                cpumask_t span;
@@ -1226,17 +1384,19 @@ static int try_to_wake_up(task_t *p, unsigned int state, int sync)
 
                if (this_sd->flags & SD_WAKE_AFFINE) {
                        unsigned long tl = this_load;
+                       unsigned long tl_per_task = cpu_avg_load_per_task(this_cpu);
+
                        /*
                         * If sync wakeup then subtract the (maximum possible)
                         * effect of the currently running task from the load
                         * of the current CPU:
                         */
                        if (sync)
-                               tl -= SCHED_LOAD_SCALE;
+                               tl -= current->load_weight;
 
                        if ((tl <= load &&
-                               tl + target_load(cpu, idx) <= SCHED_LOAD_SCALE) ||
-                               100*(tl + SCHED_LOAD_SCALE) <= imbalance*load) {
+                               tl + target_load(cpu, idx) <= tl_per_task) ||
+                               100*(tl + p->load_weight) <= imbalance*load) {
                                /*
                                 * This domain has SD_WAKE_AFFINE and
                                 * p is cache cold in this domain, and
@@ -1353,6 +1513,12 @@ void fastcall sched_fork(task_t *p, int clone_flags)
         * event cannot wake it up and insert it on the runqueue either.
         */
        p->state = TASK_RUNNING;
+
+       /*
+        * Make sure we do not leak PI boosting priority to the child:
+        */
+       p->prio = current->normal_prio;
+
        INIT_LIST_HEAD(&p->run_list);
        p->array = NULL;
 #ifdef CONFIG_SCHEDSTATS
@@ -1432,10 +1598,11 @@ void fastcall wake_up_new_task(task_t *p, unsigned long clone_flags)
                                __activate_task(p, rq);
                        else {
                                p->prio = current->prio;
+                               p->normal_prio = current->normal_prio;
                                list_add_tail(&p->run_list, &current->run_list);
                                p->array = current->array;
                                p->array->nr_active++;
-                               rq->nr_running++;
+                               inc_nr_running(p, rq);
                        }
                        set_need_resched();
                } else
@@ -1653,7 +1820,8 @@ unsigned long nr_uninterruptible(void)
 
 unsigned long long nr_context_switches(void)
 {
-       unsigned long long i, sum = 0;
+       int i;
+       unsigned long long sum = 0;
 
        for_each_possible_cpu(i)
                sum += cpu_rq(i)->nr_switches;
@@ -1691,9 +1859,6 @@ unsigned long nr_active(void)
 /*
  * double_rq_lock - safely lock two runqueues
  *
- * We must take them in cpu order to match code in
- * dependent_sleeper and wake_dependent_sleeper.
- *
  * Note this does not disable interrupts like task_rq_lock,
  * you need to do so manually before calling.
  */
@@ -1705,7 +1870,7 @@ static void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
                spin_lock(&rq1->lock);
                __acquire(rq2->lock);   /* Fake it out ;) */
        } else {
-               if (rq1->cpu < rq2->cpu) {
+               if (rq1 < rq2) {
                        spin_lock(&rq1->lock);
                        spin_lock(&rq2->lock);
                } else {
@@ -1741,7 +1906,7 @@ static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest)
        __acquires(this_rq->lock)
 {
        if (unlikely(!spin_trylock(&busiest->lock))) {
-               if (busiest->cpu < this_rq->cpu) {
+               if (busiest < this_rq) {
                        spin_unlock(&this_rq->lock);
                        spin_lock(&busiest->lock);
                        spin_lock(&this_rq->lock);
@@ -1804,9 +1969,9 @@ void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
               runqueue_t *this_rq, prio_array_t *this_array, int this_cpu)
 {
        dequeue_task(p, src_array);
-       src_rq->nr_running--;
+       dec_nr_running(p, src_rq);
        set_task_cpu(p, this_cpu);
-       this_rq->nr_running++;
+       inc_nr_running(p, this_rq);
        enqueue_task(p, this_array);
        p->timestamp = (p->timestamp - src_rq->timestamp_last_tick)
                                + this_rq->timestamp_last_tick;
@@ -1853,26 +2018,42 @@ int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
        return 1;
 }
 
+#define rq_best_prio(rq) min((rq)->curr->prio, (rq)->best_expired_prio)
 /*
- * move_tasks tries to move up to max_nr_move tasks from busiest to this_rq,
- * as part of a balancing operation within "domain". Returns the number of
- * tasks moved.
+ * move_tasks tries to move up to max_nr_move tasks and max_load_move weighted
+ * load from busiest to this_rq, as part of a balancing operation within
+ * "domain". Returns the number of tasks moved.
  *
  * Called with both runqueues locked.
  */
 static int move_tasks(runqueue_t *this_rq, int this_cpu, runqueue_t *busiest,
-                     unsigned long max_nr_move, struct sched_domain *sd,
-                     enum idle_type idle, int *all_pinned)
+                     unsigned long max_nr_move, unsigned long max_load_move,
+                     struct sched_domain *sd, enum idle_type idle,
+                     int *all_pinned)
 {
        prio_array_t *array, *dst_array;
        struct list_head *head, *curr;
-       int idx, pulled = 0, pinned = 0;
+       int idx, pulled = 0, pinned = 0, this_best_prio, busiest_best_prio;
+       int busiest_best_prio_seen;
+       int skip_for_load; /* skip the task based on weighted load issues */
+       long rem_load_move;
        task_t *tmp;
 
-       if (max_nr_move == 0)
+       if (max_nr_move == 0 || max_load_move == 0)
                goto out;
 
+       rem_load_move = max_load_move;
        pinned = 1;
+       this_best_prio = rq_best_prio(this_rq);
+       busiest_best_prio = rq_best_prio(busiest);
+       /*
+        * Enable handling of the case where there is more than one task
+        * with the best priority.   If the current running task is one
+        * of those with prio==busiest_best_prio we know it won't be moved
+        * and therefore it's safe to override the skip (based on load) of
+        * any task we find with that prio.
+        */
+       busiest_best_prio_seen = busiest_best_prio == busiest->curr->prio;
 
        /*
         * We first consider expired tasks. Those will likely not be
@@ -1912,7 +2093,17 @@ skip_queue:
 
        curr = curr->prev;
 
-       if (!can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) {
+       /*
+        * To help distribute high priority tasks accross CPUs we don't
+        * skip a task if it will be the highest priority task (i.e. smallest
+        * prio value) on its new queue regardless of its load weight
+        */
+       skip_for_load = tmp->load_weight > rem_load_move;
+       if (skip_for_load && idx < this_best_prio)
+               skip_for_load = !busiest_best_prio_seen && idx == busiest_best_prio;
+       if (skip_for_load ||
+           !can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) {
+               busiest_best_prio_seen |= idx == busiest_best_prio;
                if (curr != head)
                        goto skip_queue;
                idx++;
@@ -1926,9 +2117,15 @@ skip_queue:
 
        pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
        pulled++;
+       rem_load_move -= tmp->load_weight;
 
-       /* We only want to steal up to the prescribed number of tasks. */
-       if (pulled < max_nr_move) {
+       /*
+        * We only want to steal up to the prescribed number of tasks
+        * and the prescribed amount of weighted load.
+        */
+       if (pulled < max_nr_move && rem_load_move > 0) {
+               if (idx < this_best_prio)
+                       this_best_prio = idx;
                if (curr != head)
                        goto skip_queue;
                idx++;
@@ -1949,7 +2146,7 @@ out:
 
 /*
  * find_busiest_group finds and returns the busiest CPU group within the
- * domain. It calculates and returns the number of tasks which should be
+ * domain. It calculates and returns the amount of weighted load which should be
  * moved to restore balance via the imbalance parameter.
  */
 static struct sched_group *
@@ -1959,9 +2156,19 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
        struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
        unsigned long max_load, avg_load, total_load, this_load, total_pwr;
        unsigned long max_pull;
+       unsigned long busiest_load_per_task, busiest_nr_running;
+       unsigned long this_load_per_task, this_nr_running;
        int load_idx;
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+       int power_savings_balance = 1;
+       unsigned long leader_nr_running = 0, min_load_per_task = 0;
+       unsigned long min_nr_running = ULONG_MAX;
+       struct sched_group *group_min = NULL, *group_leader = NULL;
+#endif
 
        max_load = this_load = total_load = total_pwr = 0;
+       busiest_load_per_task = busiest_nr_running = 0;
+       this_load_per_task = this_nr_running = 0;
        if (idle == NOT_IDLE)
                load_idx = sd->busy_idx;
        else if (idle == NEWLY_IDLE)
@@ -1970,16 +2177,19 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                load_idx = sd->idle_idx;
 
        do {
-               unsigned long load;
+               unsigned long load, group_capacity;
                int local_group;
                int i;
+               unsigned long sum_nr_running, sum_weighted_load;
 
                local_group = cpu_isset(this_cpu, group->cpumask);
 
                /* Tally up the load of all CPUs in the group */
-               avg_load = 0;
+               sum_weighted_load = sum_nr_running = avg_load = 0;
 
                for_each_cpu_mask(i, group->cpumask) {
+                       runqueue_t *rq = cpu_rq(i);
+
                        if (*sd_idle && !idle_cpu(i))
                                *sd_idle = 0;
 
@@ -1990,6 +2200,8 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                                load = source_load(i, load_idx);
 
                        avg_load += load;
+                       sum_nr_running += rq->nr_running;
+                       sum_weighted_load += rq->raw_weighted_load;
                }
 
                total_load += avg_load;
@@ -1998,17 +2210,80 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                /* Adjust by relative CPU power of the group */
                avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
 
+               group_capacity = group->cpu_power / SCHED_LOAD_SCALE;
+
                if (local_group) {
                        this_load = avg_load;
                        this = group;
-               } else if (avg_load > max_load) {
+                       this_nr_running = sum_nr_running;
+                       this_load_per_task = sum_weighted_load;
+               } else if (avg_load > max_load &&
+                          sum_nr_running > group_capacity) {
                        max_load = avg_load;
                        busiest = group;
+                       busiest_nr_running = sum_nr_running;
+                       busiest_load_per_task = sum_weighted_load;
                }
+
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+               /*
+                * Busy processors will not participate in power savings
+                * balance.
+                */
+               if (idle == NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
+                       goto group_next;
+
+               /*
+                * If the local group is idle or completely loaded
+                * no need to do power savings balance at this domain
+                */
+               if (local_group && (this_nr_running >= group_capacity ||
+                                   !this_nr_running))
+                       power_savings_balance = 0;
+
+               /*
+                * If a group is already running at full capacity or idle,
+                * don't include that group in power savings calculations
+                */
+               if (!power_savings_balance || sum_nr_running >= group_capacity
+                   || !sum_nr_running)
+                       goto group_next;
+
+               /*
+                * Calculate the group which has the least non-idle load.
+                * This is the group from where we need to pick up the load
+                * for saving power
+                */
+               if ((sum_nr_running < min_nr_running) ||
+                   (sum_nr_running == min_nr_running &&
+                    first_cpu(group->cpumask) <
+                    first_cpu(group_min->cpumask))) {
+                       group_min = group;
+                       min_nr_running = sum_nr_running;
+                       min_load_per_task = sum_weighted_load /
+                                               sum_nr_running;
+               }
+
+               /*
+                * Calculate the group which is almost near its
+                * capacity but still has some space to pick up some load
+                * from other group and save more power
+                */
+               if (sum_nr_running <= group_capacity - 1)
+                       if (sum_nr_running > leader_nr_running ||
+                           (sum_nr_running == leader_nr_running &&
+                            first_cpu(group->cpumask) >
+                             first_cpu(group_leader->cpumask))) {
+                               group_leader = group;
+                               leader_nr_running = sum_nr_running;
+                       }
+
+group_next:
+#endif
                group = group->next;
        } while (group != sd->groups);
 
-       if (!busiest || this_load >= max_load || max_load <= SCHED_LOAD_SCALE)
+       if (!busiest || this_load >= max_load || busiest_nr_running == 0)
                goto out_balanced;
 
        avg_load = (SCHED_LOAD_SCALE * total_load) / total_pwr;
@@ -2017,6 +2292,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                        100*max_load <= sd->imbalance_pct*this_load)
                goto out_balanced;
 
+       busiest_load_per_task /= busiest_nr_running;
        /*
         * We're trying to get all the cpus to the average_load, so we don't
         * want to push ourselves above the average load, nor do we wish to
@@ -2028,21 +2304,50 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
         * by pulling tasks to us.  Be careful of negative numbers as they'll
         * appear as very large values with unsigned longs.
         */
+       if (max_load <= busiest_load_per_task)
+               goto out_balanced;
+
+       /*
+        * In the presence of smp nice balancing, certain scenarios can have
+        * max load less than avg load(as we skip the groups at or below
+        * its cpu_power, while calculating max_load..)
+        */
+       if (max_load < avg_load) {
+               *imbalance = 0;
+               goto small_imbalance;
+       }
 
        /* Don't want to pull so many tasks that a group would go idle */
-       max_pull = min(max_load - avg_load, max_load - SCHED_LOAD_SCALE);
+       max_pull = min(max_load - avg_load, max_load - busiest_load_per_task);
 
        /* How much load to actually move to equalise the imbalance */
        *imbalance = min(max_pull * busiest->cpu_power,
                                (avg_load - this_load) * this->cpu_power)
                        / SCHED_LOAD_SCALE;
 
-       if (*imbalance < SCHED_LOAD_SCALE) {
-               unsigned long pwr_now = 0, pwr_move = 0;
+       /*
+        * if *imbalance is less than the average load per runnable task
+        * there is no gaurantee that any tasks will be moved so we'll have
+        * a think about bumping its value to force at least one task to be
+        * moved
+        */
+       if (*imbalance < busiest_load_per_task) {
+               unsigned long pwr_now, pwr_move;
                unsigned long tmp;
+               unsigned int imbn;
+
+small_imbalance:
+               pwr_move = pwr_now = 0;
+               imbn = 2;
+               if (this_nr_running) {
+                       this_load_per_task /= this_nr_running;
+                       if (busiest_load_per_task > this_load_per_task)
+                               imbn = 1;
+               } else
+                       this_load_per_task = SCHED_LOAD_SCALE;
 
-               if (max_load - this_load >= SCHED_LOAD_SCALE*2) {
-                       *imbalance = 1;
+               if (max_load - this_load >= busiest_load_per_task * imbn) {
+                       *imbalance = busiest_load_per_task;
                        return busiest;
                }
 
@@ -2052,39 +2357,47 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                 * moving them.
                 */
 
-               pwr_now += busiest->cpu_power*min(SCHED_LOAD_SCALE, max_load);
-               pwr_now += this->cpu_power*min(SCHED_LOAD_SCALE, this_load);
+               pwr_now += busiest->cpu_power *
+                       min(busiest_load_per_task, max_load);
+               pwr_now += this->cpu_power *
+                       min(this_load_per_task, this_load);
                pwr_now /= SCHED_LOAD_SCALE;
 
                /* Amount of load we'd subtract */
-               tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/busiest->cpu_power;
+               tmp = busiest_load_per_task*SCHED_LOAD_SCALE/busiest->cpu_power;
                if (max_load > tmp)
-                       pwr_move += busiest->cpu_power*min(SCHED_LOAD_SCALE,
-                                                       max_load - tmp);
+                       pwr_move += busiest->cpu_power *
+                               min(busiest_load_per_task, max_load - tmp);
 
                /* Amount of load we'd add */
                if (max_load*busiest->cpu_power <
-                               SCHED_LOAD_SCALE*SCHED_LOAD_SCALE)
+                               busiest_load_per_task*SCHED_LOAD_SCALE)
                        tmp = max_load*busiest->cpu_power/this->cpu_power;
                else
-                       tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/this->cpu_power;
-               pwr_move += this->cpu_power*min(SCHED_LOAD_SCALE, this_load + tmp);
+                       tmp = busiest_load_per_task*SCHED_LOAD_SCALE/this->cpu_power;
+               pwr_move += this->cpu_power*min(this_load_per_task, this_load + tmp);
                pwr_move /= SCHED_LOAD_SCALE;
 
                /* Move if we gain throughput */
                if (pwr_move <= pwr_now)
                        goto out_balanced;
 
-               *imbalance = 1;
-               return busiest;
+               *imbalance = busiest_load_per_task;
        }
 
-       /* Get rid of the scaling factor, rounding down as we divide */
-       *imbalance = *imbalance / SCHED_LOAD_SCALE;
        return busiest;
 
 out_balanced:
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+       if (idle == NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
+               goto ret;
 
+       if (this == group_leader && group_leader != group_min) {
+               *imbalance = min_load_per_task;
+               return group_min;
+       }
+ret:
+#endif
        *imbalance = 0;
        return NULL;
 }
@@ -2093,18 +2406,21 @@ out_balanced:
  * find_busiest_queue - find the busiest runqueue among the cpus in group.
  */
 static runqueue_t *find_busiest_queue(struct sched_group *group,
-       enum idle_type idle)
+       enum idle_type idle, unsigned long imbalance)
 {
-       unsigned long load, max_load = 0;
-       runqueue_t *busiest = NULL;
+       unsigned long max_load = 0;
+       runqueue_t *busiest = NULL, *rqi;
        int i;
 
        for_each_cpu_mask(i, group->cpumask) {
-               load = source_load(i, 0);
+               rqi = cpu_rq(i);
+
+               if (rqi->nr_running == 1 && rqi->raw_weighted_load > imbalance)
+                       continue;
 
-               if (load > max_load) {
-                       max_load = load;
-                       busiest = cpu_rq(i);
+               if (rqi->raw_weighted_load > max_load) {
+                       max_load = rqi->raw_weighted_load;
+                       busiest = rqi;
                }
        }
 
@@ -2117,6 +2433,7 @@ static runqueue_t *find_busiest_queue(struct sched_group *group,
  */
 #define MAX_PINNED_INTERVAL    512
 
+#define minus_1_or_zero(n) ((n) > 0 ? (n) - 1 : 0)
 /*
  * Check this_cpu to ensure it is balanced within domain. Attempt to move
  * tasks if there is an imbalance.
@@ -2133,7 +2450,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
        int active_balance = 0;
        int sd_idle = 0;
 
-       if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER)
+       if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER &&
+           !sched_smt_power_savings)
                sd_idle = 1;
 
        schedstat_inc(sd, lb_cnt[idle]);
@@ -2144,7 +2462,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(group, idle);
+       busiest = find_busiest_queue(group, idle, imbalance);
        if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[idle]);
                goto out_balanced;
@@ -2164,6 +2482,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                 */
                double_rq_lock(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
+                                       minus_1_or_zero(busiest->nr_running),
                                        imbalance, sd, idle, &all_pinned);
                double_rq_unlock(this_rq, busiest);
 
@@ -2221,7 +2540,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                        sd->balance_interval *= 2;
        }
 
-       if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER)
+       if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
+           !sched_smt_power_savings)
                return -1;
        return nr_moved;
 
@@ -2236,7 +2556,7 @@ out_one_pinned:
                        (sd->balance_interval < sd->max_interval))
                sd->balance_interval *= 2;
 
-       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER)
+       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings)
                return -1;
        return 0;
 }
@@ -2257,7 +2577,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
        int nr_moved = 0;
        int sd_idle = 0;
 
-       if (sd->flags & SD_SHARE_CPUPOWER)
+       if (sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings)
                sd_idle = 1;
 
        schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
@@ -2267,7 +2587,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(group, NEWLY_IDLE);
+       busiest = find_busiest_queue(group, NEWLY_IDLE, imbalance);
        if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
                goto out_balanced;
@@ -2282,6 +2602,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
                /* Attempt to move tasks */
                double_lock_balance(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
+                                       minus_1_or_zero(busiest->nr_running),
                                        imbalance, sd, NEWLY_IDLE, NULL);
                spin_unlock(&busiest->lock);
        }
@@ -2297,7 +2618,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
 
 out_balanced:
        schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
-       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER)
+       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings)
                return -1;
        sd->nr_balance_failed = 0;
        return 0;
@@ -2352,17 +2673,19 @@ static void active_load_balance(runqueue_t *busiest_rq, int busiest_cpu)
        double_lock_balance(busiest_rq, target_rq);
 
        /* Search for an sd spanning us and the target CPU. */
-       for_each_domain(target_cpu, sd)
+       for_each_domain(target_cpu, sd) {
                if ((sd->flags & SD_LOAD_BALANCE) &&
                        cpu_isset(busiest_cpu, sd->span))
                                break;
+       }
 
        if (unlikely(sd == NULL))
                goto out;
 
        schedstat_inc(sd, alb_cnt);
 
-       if (move_tasks(target_rq, target_cpu, busiest_rq, 1, sd, SCHED_IDLE, NULL))
+       if (move_tasks(target_rq, target_cpu, busiest_rq, 1,
+                       RTPRIO_TO_LOAD_WEIGHT(100), sd, SCHED_IDLE, NULL))
                schedstat_inc(sd, alb_pushed);
        else
                schedstat_inc(sd, alb_failed);
@@ -2390,7 +2713,7 @@ static void rebalance_tick(int this_cpu, runqueue_t *this_rq,
        struct sched_domain *sd;
        int i;
 
-       this_load = this_rq->nr_running * SCHED_LOAD_SCALE;
+       this_load = this_rq->raw_weighted_load;
        /* Update our load */
        for (i = 0; i < 3; i++) {
                unsigned long new_load = this_load;
@@ -2691,48 +3014,35 @@ static inline void wakeup_busy_runqueue(runqueue_t *rq)
                resched_task(rq->idle);
 }
 
-static void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
+/*
+ * Called with interrupt disabled and this_rq's runqueue locked.
+ */
+static void wake_sleeping_dependent(int this_cpu)
 {
        struct sched_domain *tmp, *sd = NULL;
-       cpumask_t sibling_map;
        int i;
 
-       for_each_domain(this_cpu, tmp)
-               if (tmp->flags & SD_SHARE_CPUPOWER)
+       for_each_domain(this_cpu, tmp) {
+               if (tmp->flags & SD_SHARE_CPUPOWER) {
                        sd = tmp;
+                       break;
+               }
+       }
 
        if (!sd)
                return;
 
-       /*
-        * Unlock the current runqueue because we have to lock in
-        * CPU order to avoid deadlocks. Caller knows that we might
-        * unlock. We keep IRQs disabled.
-        */
-       spin_unlock(&this_rq->lock);
-
-       sibling_map = sd->span;
-
-       for_each_cpu_mask(i, sibling_map)
-               spin_lock(&cpu_rq(i)->lock);
-       /*
-        * We clear this CPU from the mask. This both simplifies the
-        * inner loop and keps this_rq locked when we exit:
-        */
-       cpu_clear(this_cpu, sibling_map);
-
-       for_each_cpu_mask(i, sibling_map) {
+       for_each_cpu_mask(i, sd->span) {
                runqueue_t *smt_rq = cpu_rq(i);
 
+               if (i == this_cpu)
+                       continue;
+               if (unlikely(!spin_trylock(&smt_rq->lock)))
+                       continue;
+
                wakeup_busy_runqueue(smt_rq);
+               spin_unlock(&smt_rq->lock);
        }
-
-       for_each_cpu_mask(i, sibling_map)
-               spin_unlock(&cpu_rq(i)->lock);
-       /*
-        * We exit with this_cpu's rq still held and IRQs
-        * still disabled:
-        */
 }
 
 /*
@@ -2745,52 +3055,46 @@ static inline unsigned long smt_slice(task_t *p, struct sched_domain *sd)
        return p->time_slice * (100 - sd->per_cpu_gain) / 100;
 }
 
-static int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
+/*
+ * To minimise lock contention and not have to drop this_rq's runlock we only
+ * trylock the sibling runqueues and bypass those runqueues if we fail to
+ * acquire their lock. As we only trylock the normal locking order does not
+ * need to be obeyed.
+ */
+static int dependent_sleeper(int this_cpu, runqueue_t *this_rq, task_t *p)
 {
        struct sched_domain *tmp, *sd = NULL;
-       cpumask_t sibling_map;
-       prio_array_t *array;
        int ret = 0, i;
-       task_t *p;
 
-       for_each_domain(this_cpu, tmp)
-               if (tmp->flags & SD_SHARE_CPUPOWER)
+       /* kernel/rt threads do not participate in dependent sleeping */
+       if (!p->mm || rt_task(p))
+               return 0;
+
+       for_each_domain(this_cpu, tmp) {
+               if (tmp->flags & SD_SHARE_CPUPOWER) {
                        sd = tmp;
+                       break;
+               }
+       }
 
        if (!sd)
                return 0;
 
-       /*
-        * The same locking rules and details apply as for
-        * wake_sleeping_dependent():
-        */
-       spin_unlock(&this_rq->lock);
-       sibling_map = sd->span;
-       for_each_cpu_mask(i, sibling_map)
-               spin_lock(&cpu_rq(i)->lock);
-       cpu_clear(this_cpu, sibling_map);
+       for_each_cpu_mask(i, sd->span) {
+               runqueue_t *smt_rq;
+               task_t *smt_curr;
 
-       /*
-        * Establish next task to be run - it might have gone away because
-        * we released the runqueue lock above:
-        */
-       if (!this_rq->nr_running)
-               goto out_unlock;
-       array = this_rq->active;
-       if (!array->nr_active)
-               array = this_rq->expired;
-       BUG_ON(!array->nr_active);
+               if (i == this_cpu)
+                       continue;
 
-       p = list_entry(array->queue[sched_find_first_bit(array->bitmap)].next,
-               task_t, run_list);
+               smt_rq = cpu_rq(i);
+               if (unlikely(!spin_trylock(&smt_rq->lock)))
+                       continue;
 
-       for_each_cpu_mask(i, sibling_map) {
-               runqueue_t *smt_rq = cpu_rq(i);
-               task_t *smt_curr = smt_rq->curr;
+               smt_curr = smt_rq->curr;
 
-               /* Kernel threads do not participate in dependent sleeping */
-               if (!p->mm || !smt_curr->mm || rt_task(p))
-                       goto check_smt_task;
+               if (!smt_curr->mm)
+                       goto unlock;
 
                /*
                 * If a user task with lower static priority than the
@@ -2808,49 +3112,24 @@ static int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
                        if ((jiffies % DEF_TIMESLICE) >
                                (sd->per_cpu_gain * DEF_TIMESLICE / 100))
                                        ret = 1;
-               } else
+               } else {
                        if (smt_curr->static_prio < p->static_prio &&
                                !TASK_PREEMPTS_CURR(p, smt_rq) &&
                                smt_slice(smt_curr, sd) > task_timeslice(p))
                                        ret = 1;
-
-check_smt_task:
-               if ((!smt_curr->mm && smt_curr != smt_rq->idle) ||
-                       rt_task(smt_curr))
-                               continue;
-               if (!p->mm) {
-                       wakeup_busy_runqueue(smt_rq);
-                       continue;
-               }
-
-               /*
-                * Reschedule a lower priority task on the SMT sibling for
-                * it to be put to sleep, or wake it up if it has been put to
-                * sleep for priority reasons to see if it should run now.
-                */
-               if (rt_task(p)) {
-                       if ((jiffies % DEF_TIMESLICE) >
-                               (sd->per_cpu_gain * DEF_TIMESLICE / 100))
-                                       resched_task(smt_curr);
-               } else {
-                       if (TASK_PREEMPTS_CURR(p, smt_rq) &&
-                               smt_slice(p, sd) > task_timeslice(smt_curr))
-                                       resched_task(smt_curr);
-                       else
-                               wakeup_busy_runqueue(smt_rq);
                }
+unlock:
+               spin_unlock(&smt_rq->lock);
        }
-out_unlock:
-       for_each_cpu_mask(i, sibling_map)
-               spin_unlock(&cpu_rq(i)->lock);
        return ret;
 }
 #else
-static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
+static inline void wake_sleeping_dependent(int this_cpu)
 {
 }
 
-static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
+static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq,
+                                       task_t *p)
 {
        return 0;
 }
@@ -2972,32 +3251,13 @@ need_resched_nonpreemptible:
 
        cpu = smp_processor_id();
        if (unlikely(!rq->nr_running)) {
-go_idle:
                idle_balance(cpu, rq);
                if (!rq->nr_running) {
                        next = rq->idle;
                        rq->expired_timestamp = 0;
-                       wake_sleeping_dependent(cpu, rq);
-                       /*
-                        * wake_sleeping_dependent() might have released
-                        * the runqueue, so break out if we got new
-                        * tasks meanwhile:
-                        */
-                       if (!rq->nr_running)
-                               goto switch_tasks;
-               }
-       } else {
-               if (dependent_sleeper(cpu, rq)) {
-                       next = rq->idle;
+                       wake_sleeping_dependent(cpu);
                        goto switch_tasks;
                }
-               /*
-                * dependent_sleeper() releases and reacquires the runqueue
-                * lock, hence go into the idle loop if the rq went
-                * empty meanwhile:
-                */
-               if (unlikely(!rq->nr_running))
-                       goto go_idle;
        }
 
        array = rq->active;
@@ -3035,6 +3295,8 @@ go_idle:
                }
        }
        next->sleep_type = SLEEP_NORMAL;
+       if (dependent_sleeper(cpu, rq, next))
+               next = rq->idle;
 switch_tasks:
        if (next == rq->idle)
                schedstat_inc(rq, sched_goidle);
@@ -3478,12 +3740,65 @@ long fastcall __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
 
 EXPORT_SYMBOL(sleep_on_timeout);
 
+#ifdef CONFIG_RT_MUTEXES
+
+/*
+ * rt_mutex_setprio - set the current priority of a task
+ * @p: task
+ * @prio: prio value (kernel-internal form)
+ *
+ * This function changes the 'effective' priority of a task. It does
+ * not touch ->normal_prio like __setscheduler().
+ *
+ * Used by the rt_mutex code to implement priority inheritance logic.
+ */
+void rt_mutex_setprio(task_t *p, int prio)
+{
+       unsigned long flags;
+       prio_array_t *array;
+       runqueue_t *rq;
+       int oldprio;
+
+       BUG_ON(prio < 0 || prio > MAX_PRIO);
+
+       rq = task_rq_lock(p, &flags);
+
+       oldprio = p->prio;
+       array = p->array;
+       if (array)
+               dequeue_task(p, array);
+       p->prio = prio;
+
+       if (array) {
+               /*
+                * If changing to an RT priority then queue it
+                * in the active array!
+                */
+               if (rt_task(p))
+                       array = rq->active;
+               enqueue_task(p, array);
+               /*
+                * Reschedule if we are currently running on this runqueue and
+                * our priority decreased, or if we are not currently running on
+                * this runqueue and our priority is higher than the current's
+                */
+               if (task_running(rq, p)) {
+                       if (p->prio > oldprio)
+                               resched_task(rq->curr);
+               } else if (TASK_PREEMPTS_CURR(p, rq))
+                       resched_task(rq->curr);
+       }
+       task_rq_unlock(rq, &flags);
+}
+
+#endif
+
 void set_user_nice(task_t *p, long nice)
 {
        unsigned long flags;
        prio_array_t *array;
        runqueue_t *rq;
-       int old_prio, new_prio, delta;
+       int old_prio, delta;
 
        if (TASK_NICE(p) == nice || nice < -20 || nice > 19)
                return;
@@ -3498,22 +3813,25 @@ void set_user_nice(task_t *p, long nice)
         * it wont have any effect on scheduling until the task is
         * not SCHED_NORMAL/SCHED_BATCH:
         */
-       if (rt_task(p)) {
+       if (has_rt_policy(p)) {
                p->static_prio = NICE_TO_PRIO(nice);
                goto out_unlock;
        }
        array = p->array;
-       if (array)
+       if (array) {
                dequeue_task(p, array);
+               dec_raw_weighted_load(rq, p);
+       }
 
-       old_prio = p->prio;
-       new_prio = NICE_TO_PRIO(nice);
-       delta = new_prio - old_prio;
        p->static_prio = NICE_TO_PRIO(nice);
-       p->prio += delta;
+       set_load_weight(p);
+       old_prio = p->prio;
+       p->prio = effective_prio(p);
+       delta = p->prio - old_prio;
 
        if (array) {
                enqueue_task(p, array);
+               inc_raw_weighted_load(rq, p);
                /*
                 * If the task increased its priority or is running and
                 * lowered its priority, then reschedule its CPU:
@@ -3524,7 +3842,6 @@ void set_user_nice(task_t *p, long nice)
 out_unlock:
        task_rq_unlock(rq, &flags);
 }
-
 EXPORT_SYMBOL(set_user_nice);
 
 /*
@@ -3639,16 +3956,15 @@ static void __setscheduler(struct task_struct *p, int policy, int prio)
        BUG_ON(p->array);
        p->policy = policy;
        p->rt_priority = prio;
-       if (policy != SCHED_NORMAL && policy != SCHED_BATCH) {
-               p->prio = MAX_RT_PRIO-1 - p->rt_priority;
-       } else {
-               p->prio = p->static_prio;
-               /*
-                * SCHED_BATCH tasks are treated as perpetual CPU hogs:
-                */
-               if (policy == SCHED_BATCH)
-                       p->sleep_avg = 0;
-       }
+       p->normal_prio = normal_prio(p);
+       /* we are holding p->pi_lock already */
+       p->prio = rt_mutex_getprio(p);
+       /*
+        * SCHED_BATCH tasks are treated as perpetual CPU hogs:
+        */
+       if (policy == SCHED_BATCH)
+               p->sleep_avg = 0;
+       set_load_weight(p);
 }
 
 /**
@@ -3667,6 +3983,8 @@ int sched_setscheduler(struct task_struct *p, int policy,
        unsigned long flags;
        runqueue_t *rq;
 
+       /* may grab non-irq protected spin_locks */
+       BUG_ON(in_interrupt());
 recheck:
        /* double check policy once rq lock held */
        if (policy < 0)
@@ -3714,15 +4032,21 @@ recheck:
        retval = security_task_setscheduler(p, policy, param);
        if (retval)
                return retval;
+       /*
+        * make sure no PI-waiters arrive (or leave) while we are
+        * changing the priority of the task:
+        */
+       spin_lock_irqsave(&p->pi_lock, flags);
        /*
         * To be able to change p->policy safely, the apropriate
         * runqueue lock must be held.
         */
-       rq = task_rq_lock(p, &flags);
+       rq = __task_rq_lock(p);
        /* recheck policy now with rq lock held */
        if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) {
                policy = oldpolicy = -1;
-               task_rq_unlock(rq, &flags);
+               __task_rq_unlock(rq);
+               spin_unlock_irqrestore(&p->pi_lock, flags);
                goto recheck;
        }
        array = p->array;
@@ -3743,7 +4067,11 @@ recheck:
                } else if (TASK_PREEMPTS_CURR(p, rq))
                        resched_task(rq->curr);
        }
-       task_rq_unlock(rq, &flags);
+       __task_rq_unlock(rq);
+       spin_unlock_irqrestore(&p->pi_lock, flags);
+
+       rt_mutex_adjust_pi(p);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(sched_setscheduler);
@@ -3765,8 +4093,10 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
                read_unlock_irq(&tasklist_lock);
                return -ESRCH;
        }
-       retval = sched_setscheduler(p, policy, &lparam);
+       get_task_struct(p);
        read_unlock_irq(&tasklist_lock);
+       retval = sched_setscheduler(p, policy, &lparam);
+       put_task_struct(p);
        return retval;
 }
 
@@ -4378,7 +4708,7 @@ void __devinit init_idle(task_t *idle, int cpu)
        idle->timestamp = sched_clock();
        idle->sleep_avg = 0;
        idle->array = NULL;
-       idle->prio = MAX_PRIO;
+       idle->prio = idle->normal_prio = MAX_PRIO;
        idle->state = TASK_RUNNING;
        idle->cpus_allowed = cpumask_of_cpu(cpu);
        set_task_cpu(idle, cpu);
@@ -4474,13 +4804,16 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed);
  *
  * So we race with normal scheduler movements, but that's OK, as long
  * as the task is no longer on this CPU.
+ *
+ * Returns non-zero if task was successfully migrated.
  */
-static void __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
+static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
 {
        runqueue_t *rq_dest, *rq_src;
+       int ret = 0;
 
        if (unlikely(cpu_is_offline(dest_cpu)))
-               return;
+               return ret;
 
        rq_src = cpu_rq(src_cpu);
        rq_dest = cpu_rq(dest_cpu);
@@ -4508,9 +4841,10 @@ static void __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
                if (TASK_PREEMPTS_CURR(p, rq_dest))
                        resched_task(rq_dest->curr);
        }
-
+       ret = 1;
 out:
        double_rq_unlock(rq_src, rq_dest);
+       return ret;
 }
 
 /*
@@ -4580,9 +4914,12 @@ wait_to_die:
 /* Figure out where task on dead CPU should go, use force if neccessary. */
 static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
 {
+       runqueue_t *rq;
+       unsigned long flags;
        int dest_cpu;
        cpumask_t mask;
 
+restart:
        /* On same node? */
        mask = node_to_cpumask(cpu_to_node(dead_cpu));
        cpus_and(mask, mask, tsk->cpus_allowed);
@@ -4594,8 +4931,10 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
 
        /* No more Mr. Nice Guy. */
        if (dest_cpu == NR_CPUS) {
+               rq = task_rq_lock(tsk, &flags);
                cpus_setall(tsk->cpus_allowed);
                dest_cpu = any_online_cpu(tsk->cpus_allowed);
+               task_rq_unlock(rq, &flags);
 
                /*
                 * Don't tell them about moving exiting tasks or
@@ -4607,7 +4946,8 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
                               "longer affine to cpu%d\n",
                               tsk->pid, tsk->comm, dead_cpu);
        }
-       __migrate_task(tsk, dead_cpu, dest_cpu);
+       if (!__migrate_task(tsk, dead_cpu, dest_cpu))
+               goto restart;
 }
 
 /*
@@ -4734,8 +5074,9 @@ static void migrate_dead_tasks(unsigned int dead_cpu)
  * migration_call - callback that gets triggered when a CPU is added.
  * Here we can start up the necessary migration thread for the new CPU.
  */
-static int migration_call(struct notifier_block *nfb, unsigned long action,
-                         void *hcpu)
+static int __cpuinit migration_call(struct notifier_block *nfb,
+                       unsigned long action,
+                       void *hcpu)
 {
        int cpu = (long)hcpu;
        struct task_struct *p;
@@ -4805,7 +5146,7 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
 /* Register at highest priority so that task migration (migrate_all_tasks)
  * happens before everything else.
  */
-static struct notifier_block migration_notifier = {
+static struct notifier_block __cpuinitdata migration_notifier = {
        .notifier_call = migration_call,
        .priority = 10
 };
@@ -5606,6 +5947,7 @@ static cpumask_t sched_domain_node_span(int node)
 }
 #endif
 
+int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
 /*
  * At the moment, CONFIG_SCHED_SMT is never defined, but leave it in so we
  * can switch it on easily if needed.
@@ -5621,7 +5963,7 @@ static int cpu_to_cpu_group(int cpu)
 
 #ifdef CONFIG_SCHED_MC
 static DEFINE_PER_CPU(struct sched_domain, core_domains);
-static struct sched_group sched_group_core[NR_CPUS];
+static struct sched_group *sched_group_core_bycpu[NR_CPUS];
 #endif
 
 #if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT)
@@ -5637,7 +5979,7 @@ static int cpu_to_core_group(int cpu)
 #endif
 
 static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static struct sched_group sched_group_phys[NR_CPUS];
+static struct sched_group *sched_group_phys_bycpu[NR_CPUS];
 static int cpu_to_phys_group(int cpu)
 {
 #if defined(CONFIG_SCHED_MC)
@@ -5694,13 +6036,74 @@ next_sg:
 }
 #endif
 
+/* Free memory allocated for various sched_group structures */
+static void free_sched_groups(const cpumask_t *cpu_map)
+{
+       int cpu;
+#ifdef CONFIG_NUMA
+       int i;
+
+       for_each_cpu_mask(cpu, *cpu_map) {
+               struct sched_group *sched_group_allnodes
+                       = sched_group_allnodes_bycpu[cpu];
+               struct sched_group **sched_group_nodes
+                       = sched_group_nodes_bycpu[cpu];
+
+               if (sched_group_allnodes) {
+                       kfree(sched_group_allnodes);
+                       sched_group_allnodes_bycpu[cpu] = NULL;
+               }
+
+               if (!sched_group_nodes)
+                       continue;
+
+               for (i = 0; i < MAX_NUMNODES; i++) {
+                       cpumask_t nodemask = node_to_cpumask(i);
+                       struct sched_group *oldsg, *sg = sched_group_nodes[i];
+
+                       cpus_and(nodemask, nodemask, *cpu_map);
+                       if (cpus_empty(nodemask))
+                               continue;
+
+                       if (sg == NULL)
+                               continue;
+                       sg = sg->next;
+next_sg:
+                       oldsg = sg;
+                       sg = sg->next;
+                       kfree(oldsg);
+                       if (oldsg != sched_group_nodes[i])
+                               goto next_sg;
+               }
+               kfree(sched_group_nodes);
+               sched_group_nodes_bycpu[cpu] = NULL;
+       }
+#endif
+       for_each_cpu_mask(cpu, *cpu_map) {
+               if (sched_group_phys_bycpu[cpu]) {
+                       kfree(sched_group_phys_bycpu[cpu]);
+                       sched_group_phys_bycpu[cpu] = NULL;
+               }
+#ifdef CONFIG_SCHED_MC
+               if (sched_group_core_bycpu[cpu]) {
+                       kfree(sched_group_core_bycpu[cpu]);
+                       sched_group_core_bycpu[cpu] = NULL;
+               }
+#endif
+       }
+}
+
 /*
  * Build sched domains for a given set of cpus and attach the sched domains
  * to the individual cpus
  */
-void build_sched_domains(const cpumask_t *cpu_map)
+static int build_sched_domains(const cpumask_t *cpu_map)
 {
        int i;
+       struct sched_group *sched_group_phys = NULL;
+#ifdef CONFIG_SCHED_MC
+       struct sched_group *sched_group_core = NULL;
+#endif
 #ifdef CONFIG_NUMA
        struct sched_group **sched_group_nodes = NULL;
        struct sched_group *sched_group_allnodes = NULL;
@@ -5708,11 +6111,11 @@ void build_sched_domains(const cpumask_t *cpu_map)
        /*
         * Allocate the per-node list of sched groups
         */
-       sched_group_nodes = kmalloc(sizeof(struct sched_group*)*MAX_NUMNODES,
-                                          GFP_ATOMIC);
+       sched_group_nodes = kzalloc(sizeof(struct sched_group*)*MAX_NUMNODES,
+                                          GFP_KERNEL);
        if (!sched_group_nodes) {
                printk(KERN_WARNING "Can not alloc sched group node list\n");
-               return;
+               return -ENOMEM;
        }
        sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes;
 #endif
@@ -5738,7 +6141,7 @@ void build_sched_domains(const cpumask_t *cpu_map)
                                if (!sched_group_allnodes) {
                                        printk(KERN_WARNING
                                        "Can not alloc allnodes sched group\n");
-                                       break;
+                                       goto error;
                                }
                                sched_group_allnodes_bycpu[i]
                                                = sched_group_allnodes;
@@ -5759,6 +6162,18 @@ void build_sched_domains(const cpumask_t *cpu_map)
                cpus_and(sd->span, sd->span, *cpu_map);
 #endif
 
+               if (!sched_group_phys) {
+                       sched_group_phys
+                               = kmalloc(sizeof(struct sched_group) * NR_CPUS,
+                                         GFP_KERNEL);
+                       if (!sched_group_phys) {
+                               printk (KERN_WARNING "Can not alloc phys sched"
+                                                    "group\n");
+                               goto error;
+                       }
+                       sched_group_phys_bycpu[i] = sched_group_phys;
+               }
+
                p = sd;
                sd = &per_cpu(phys_domains, i);
                group = cpu_to_phys_group(i);
@@ -5768,6 +6183,18 @@ void build_sched_domains(const cpumask_t *cpu_map)
                sd->groups = &sched_group_phys[group];
 
 #ifdef CONFIG_SCHED_MC
+               if (!sched_group_core) {
+                       sched_group_core
+                               = kmalloc(sizeof(struct sched_group) * NR_CPUS,
+                                         GFP_KERNEL);
+                       if (!sched_group_core) {
+                               printk (KERN_WARNING "Can not alloc core sched"
+                                                    "group\n");
+                               goto error;
+                       }
+                       sched_group_core_bycpu[i] = sched_group_core;
+               }
+
                p = sd;
                sd = &per_cpu(core_domains, i);
                group = cpu_to_core_group(i);
@@ -5851,24 +6278,21 @@ void build_sched_domains(const cpumask_t *cpu_map)
                domainspan = sched_domain_node_span(i);
                cpus_and(domainspan, domainspan, *cpu_map);
 
-               sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+               sg = kmalloc_node(sizeof(struct sched_group), GFP_KERNEL, i);
+               if (!sg) {
+                       printk(KERN_WARNING "Can not alloc domain group for "
+                               "node %d\n", i);
+                       goto error;
+               }
                sched_group_nodes[i] = sg;
                for_each_cpu_mask(j, nodemask) {
                        struct sched_domain *sd;
                        sd = &per_cpu(node_domains, j);
                        sd->groups = sg;
-                       if (sd->groups == NULL) {
-                               /* Turn off balancing if we have no groups */
-                               sd->flags = 0;
-                       }
-               }
-               if (!sg) {
-                       printk(KERN_WARNING
-                       "Can not alloc domain group for node %d\n", i);
-                       continue;
                }
                sg->cpu_power = 0;
                sg->cpumask = nodemask;
+               sg->next = sg;
                cpus_or(covered, covered, nodemask);
                prev = sg;
 
@@ -5887,54 +6311,90 @@ void build_sched_domains(const cpumask_t *cpu_map)
                        if (cpus_empty(tmp))
                                continue;
 
-                       sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+                       sg = kmalloc_node(sizeof(struct sched_group),
+                                         GFP_KERNEL, i);
                        if (!sg) {
                                printk(KERN_WARNING
                                "Can not alloc domain group for node %d\n", j);
-                               break;
+                               goto error;
                        }
                        sg->cpu_power = 0;
                        sg->cpumask = tmp;
+                       sg->next = prev->next;
                        cpus_or(covered, covered, tmp);
                        prev->next = sg;
                        prev = sg;
                }
-               prev->next = sched_group_nodes[i];
        }
 #endif
 
        /* Calculate CPU power for physical packages and nodes */
+#ifdef CONFIG_SCHED_SMT
        for_each_cpu_mask(i, *cpu_map) {
-               int power;
                struct sched_domain *sd;
-#ifdef CONFIG_SCHED_SMT
                sd = &per_cpu(cpu_domains, i);
-               power = SCHED_LOAD_SCALE;
-               sd->groups->cpu_power = power;
+               sd->groups->cpu_power = SCHED_LOAD_SCALE;
+       }
 #endif
 #ifdef CONFIG_SCHED_MC
+       for_each_cpu_mask(i, *cpu_map) {
+               int power;
+               struct sched_domain *sd;
                sd = &per_cpu(core_domains, i);
-               power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1)
+               if (sched_smt_power_savings)
+                       power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask);
+               else
+                       power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1)
                                            * SCHED_LOAD_SCALE / 10;
                sd->groups->cpu_power = power;
+       }
+#endif
 
+       for_each_cpu_mask(i, *cpu_map) {
+               struct sched_domain *sd;
+#ifdef CONFIG_SCHED_MC
                sd = &per_cpu(phys_domains, i);
+               if (i != first_cpu(sd->groups->cpumask))
+                       continue;
 
-               /*
-                * This has to be < 2 * SCHED_LOAD_SCALE
-                * Lets keep it SCHED_LOAD_SCALE, so that
-                * while calculating NUMA group's cpu_power
-                * we can simply do
-                *  numa_group->cpu_power += phys_group->cpu_power;
-                *
-                * See "only add power once for each physical pkg"
-                * comment below
-                */
-               sd->groups->cpu_power = SCHED_LOAD_SCALE;
+               sd->groups->cpu_power = 0;
+               if (sched_mc_power_savings || sched_smt_power_savings) {
+                       int j;
+
+                       for_each_cpu_mask(j, sd->groups->cpumask) {
+                               struct sched_domain *sd1;
+                               sd1 = &per_cpu(core_domains, j);
+                               /*
+                                * for each core we will add once
+                                * to the group in physical domain
+                                */
+                               if (j != first_cpu(sd1->groups->cpumask))
+                                       continue;
+
+                               if (sched_smt_power_savings)
+                                       sd->groups->cpu_power += sd1->groups->cpu_power;
+                               else
+                                       sd->groups->cpu_power += SCHED_LOAD_SCALE;
+                       }
+               } else
+                       /*
+                        * This has to be < 2 * SCHED_LOAD_SCALE
+                        * Lets keep it SCHED_LOAD_SCALE, so that
+                        * while calculating NUMA group's cpu_power
+                        * we can simply do
+                        *  numa_group->cpu_power += phys_group->cpu_power;
+                        *
+                        * See "only add power once for each physical pkg"
+                        * comment below
+                        */
+                       sd->groups->cpu_power = SCHED_LOAD_SCALE;
 #else
+               int power;
                sd = &per_cpu(phys_domains, i);
-               power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
-                               (cpus_weight(sd->groups->cpumask)-1) / 10;
+               if (sched_smt_power_savings)
+                       power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask);
+               else
+                       power = SCHED_LOAD_SCALE;
                sd->groups->cpu_power = power;
 #endif
        }
@@ -5962,13 +6422,20 @@ void build_sched_domains(const cpumask_t *cpu_map)
         * Tune cache-hot values:
         */
        calibrate_migration_costs(cpu_map);
+
+       return 0;
+
+error:
+       free_sched_groups(cpu_map);
+       return -ENOMEM;
 }
 /*
  * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
  */
-static void arch_init_sched_domains(const cpumask_t *cpu_map)
+static int arch_init_sched_domains(const cpumask_t *cpu_map)
 {
        cpumask_t cpu_default_map;
+       int err;
 
        /*
         * Setup mask for cpus without special case scheduling requirements.
@@ -5977,51 +6444,14 @@ static void arch_init_sched_domains(const cpumask_t *cpu_map)
         */
        cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
 
-       build_sched_domains(&cpu_default_map);
+       err = build_sched_domains(&cpu_default_map);
+
+       return err;
 }
 
 static void arch_destroy_sched_domains(const cpumask_t *cpu_map)
 {
-#ifdef CONFIG_NUMA
-       int i;
-       int cpu;
-
-       for_each_cpu_mask(cpu, *cpu_map) {
-               struct sched_group *sched_group_allnodes
-                       = sched_group_allnodes_bycpu[cpu];
-               struct sched_group **sched_group_nodes
-                       = sched_group_nodes_bycpu[cpu];
-
-               if (sched_group_allnodes) {
-                       kfree(sched_group_allnodes);
-                       sched_group_allnodes_bycpu[cpu] = NULL;
-               }
-
-               if (!sched_group_nodes)
-                       continue;
-
-               for (i = 0; i < MAX_NUMNODES; i++) {
-                       cpumask_t nodemask = node_to_cpumask(i);
-                       struct sched_group *oldsg, *sg = sched_group_nodes[i];
-
-                       cpus_and(nodemask, nodemask, *cpu_map);
-                       if (cpus_empty(nodemask))
-                               continue;
-
-                       if (sg == NULL)
-                               continue;
-                       sg = sg->next;
-next_sg:
-                       oldsg = sg;
-                       sg = sg->next;
-                       kfree(oldsg);
-                       if (oldsg != sched_group_nodes[i])
-                               goto next_sg;
-               }
-               kfree(sched_group_nodes);
-               sched_group_nodes_bycpu[cpu] = NULL;
-       }
-#endif
+       free_sched_groups(cpu_map);
 }
 
 /*
@@ -6046,9 +6476,10 @@ static void detach_destroy_domains(const cpumask_t *cpu_map)
  * correct sched domains
  * Call with hotplug lock held
  */
-void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
+int partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
 {
        cpumask_t change_map;
+       int err = 0;
 
        cpus_and(*partition1, *partition1, cpu_online_map);
        cpus_and(*partition2, *partition2, cpu_online_map);
@@ -6057,10 +6488,86 @@ void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
        /* Detach sched domains from all of the affected cpus */
        detach_destroy_domains(&change_map);
        if (!cpus_empty(*partition1))
-               build_sched_domains(partition1);
-       if (!cpus_empty(*partition2))
-               build_sched_domains(partition2);
+               err = build_sched_domains(partition1);
+       if (!err && !cpus_empty(*partition2))
+               err = build_sched_domains(partition2);
+
+       return err;
+}
+
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+int arch_reinit_sched_domains(void)
+{
+       int err;
+
+       lock_cpu_hotplug();
+       detach_destroy_domains(&cpu_online_map);
+       err = arch_init_sched_domains(&cpu_online_map);
+       unlock_cpu_hotplug();
+
+       return err;
+}
+
+static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt)
+{
+       int ret;
+
+       if (buf[0] != '0' && buf[0] != '1')
+               return -EINVAL;
+
+       if (smt)
+               sched_smt_power_savings = (buf[0] == '1');
+       else
+               sched_mc_power_savings = (buf[0] == '1');
+
+       ret = arch_reinit_sched_domains();
+
+       return ret ? ret : count;
+}
+
+int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls)
+{
+       int err = 0;
+#ifdef CONFIG_SCHED_SMT
+       if (smt_capable())
+               err = sysfs_create_file(&cls->kset.kobj,
+                                       &attr_sched_smt_power_savings.attr);
+#endif
+#ifdef CONFIG_SCHED_MC
+       if (!err && mc_capable())
+               err = sysfs_create_file(&cls->kset.kobj,
+                                       &attr_sched_mc_power_savings.attr);
+#endif
+       return err;
+}
+#endif
+
+#ifdef CONFIG_SCHED_MC
+static ssize_t sched_mc_power_savings_show(struct sys_device *dev, char *page)
+{
+       return sprintf(page, "%u\n", sched_mc_power_savings);
+}
+static ssize_t sched_mc_power_savings_store(struct sys_device *dev, const char *buf, size_t count)
+{
+       return sched_power_savings_store(buf, count, 0);
+}
+SYSDEV_ATTR(sched_mc_power_savings, 0644, sched_mc_power_savings_show,
+           sched_mc_power_savings_store);
+#endif
+
+#ifdef CONFIG_SCHED_SMT
+static ssize_t sched_smt_power_savings_show(struct sys_device *dev, char *page)
+{
+       return sprintf(page, "%u\n", sched_smt_power_savings);
+}
+static ssize_t sched_smt_power_savings_store(struct sys_device *dev, const char *buf, size_t count)
+{
+       return sched_power_savings_store(buf, count, 1);
 }
+SYSDEV_ATTR(sched_smt_power_savings, 0644, sched_smt_power_savings_show,
+           sched_smt_power_savings_store);
+#endif
+
 
 #ifdef CONFIG_HOTPLUG_CPU
 /*
@@ -6143,7 +6650,6 @@ void __init sched_init(void)
                rq->push_cpu = 0;
                rq->migration_thread = NULL;
                INIT_LIST_HEAD(&rq->migration_queue);
-               rq->cpu = i;
 #endif
                atomic_set(&rq->nr_iowait, 0);
 
@@ -6158,6 +6664,7 @@ void __init sched_init(void)
                }
        }
 
+       set_load_weight(&init_task);
        /*
         * The boot idle thread does lazy MMU switching as well:
         */
@@ -6204,11 +6711,12 @@ void normalize_rt_tasks(void)
        runqueue_t *rq;
 
        read_lock_irq(&tasklist_lock);
-       for_each_process (p) {
+       for_each_process(p) {
                if (!rt_task(p))
                        continue;
 
-               rq = task_rq_lock(p, &flags);
+               spin_lock_irqsave(&p->pi_lock, flags);
+               rq = __task_rq_lock(p);
 
                array = p->array;
                if (array)
@@ -6219,7 +6727,8 @@ void normalize_rt_tasks(void)
                        resched_task(rq->curr);
                }
 
-               task_rq_unlock(rq, &flags);
+               __task_rq_unlock(rq);
+               spin_unlock_irqrestore(&p->pi_lock, flags);
        }
        read_unlock_irq(&tasklist_lock);
 }
index 9e2f1c6e73d7b341958c74baa8af54169c88c119..8f03e3b89b5540a0e21b1bab99dcb455bb74ffd5 100644 (file)
@@ -446,7 +446,7 @@ static void takeover_tasklets(unsigned int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int cpu_callback(struct notifier_block *nfb,
+static int __devinit cpu_callback(struct notifier_block *nfb,
                                  unsigned long action,
                                  void *hcpu)
 {
@@ -486,7 +486,7 @@ static int cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpu_nfb = {
+static struct notifier_block __devinitdata cpu_nfb = {
        .notifier_call = cpu_callback
 };
 
index b5c3b94e01ce7408a9f3d0dae310cff0a6939a36..6b76caa229818811f61aaacf16afd9c2b6da5dc5 100644 (file)
@@ -104,7 +104,7 @@ static int watchdog(void * __bind_cpu)
 /*
  * Create/destroy watchdog threads as CPUs come and go:
  */
-static int
+static int __devinit
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
@@ -142,7 +142,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpu_nfb = {
+static struct notifier_block __devinitdata cpu_nfb = {
        .notifier_call = cpu_callback
 };
 
index f1a4eb1a655e31a8a44800f5e6a8ecdd87065071..93a2c53986488f5c29cf05318db80241118bda74 100644 (file)
@@ -133,6 +133,10 @@ extern int acct_parm[];
 extern int no_unaligned_warning;
 #endif
 
+#ifdef CONFIG_RT_MUTEXES
+extern int max_lock_depth;
+#endif
+
 static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t,
                       ctl_table *, void **);
 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
@@ -688,6 +692,17 @@ static ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
+#ifdef CONFIG_RT_MUTEXES
+       {
+               .ctl_name       = KERN_MAX_LOCK_DEPTH,
+               .procname       = "max_lock_depth",
+               .data           = &max_lock_depth,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
+
        { .ctl_name = 0 }
 };
 
@@ -927,6 +942,18 @@ static ctl_table vm_table[] = {
                .proc_handler   = &proc_dointvec_jiffies,
                .strategy       = &sysctl_jiffies,
        },
+#endif
+#ifdef CONFIG_X86_32
+       {
+               .ctl_name       = VM_VDSO_ENABLED,
+               .procname       = "vdso_enabled",
+               .data           = &vdso_enabled,
+               .maxlen         = sizeof(vdso_enabled),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+       },
 #endif
        { .ctl_name = 0 }
 };
index 5bb6b7976eecf6c215b561b42b4d79c4197507eb..5a8960253063d00495366a48d92e06e5eb4133fa 100644 (file)
@@ -1652,7 +1652,7 @@ static void __devinit migrate_timers(int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int timer_cpu_notify(struct notifier_block *self,
+static int __devinit timer_cpu_notify(struct notifier_block *self,
                                unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
@@ -1672,7 +1672,7 @@ static int timer_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block timers_nb = {
+static struct notifier_block __devinitdata timers_nb = {
        .notifier_call  = timer_cpu_notify,
 };
 
index 565cf7a1febda94b88582c6e9326d782fb29f96c..59f0b42bd89e0e819a1a67145f48a11f2898bbd2 100644 (file)
@@ -559,7 +559,7 @@ static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
 }
 
 /* We're holding the cpucontrol mutex here */
-static int workqueue_cpu_callback(struct notifier_block *nfb,
+static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
                                  unsigned long action,
                                  void *hcpu)
 {
index 3de93357f5ab1e05c370164e5e390eb7d0595f9f..f6299342b882d86f56b70655879b5c8ba792f3d4 100644 (file)
@@ -86,4 +86,10 @@ config TEXTSEARCH_BM
 config TEXTSEARCH_FSM
        tristate
 
+#
+# plist support is select#ed if needed
+#
+config PLIST
+       boolean
+
 endmenu
index 8bab0102ac739d181bbddc7fc5a14f2d562353c3..e4fcbd12cf6ef75b75d7eebc40d1b45de3a22236 100644 (file)
@@ -23,6 +23,22 @@ config MAGIC_SYSRQ
          keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
          unless you really know what this hack does.
 
+config UNUSED_SYMBOLS
+       bool "Enable unused/obsolete exported symbols"
+       default y if X86
+       help
+         Unused but exported symbols make the kernel needlessly bigger.  For
+         that reason most of these unused exports will soon be removed.  This
+         option is provided temporarily to provide a transition period in case
+         some external kernel module needs one of these symbols anyway. If you
+         encounter such a case in your module, consider if you are actually
+         using the right API.  (rationale: since nobody in the kernel is using
+         this in a module, there is a pretty good chance it's actually the
+         wrong interface to use).  If you really need the symbol, please send a
+         mail to the linux kernel mailing list mentioning the symbol and why
+         you really need it, and what the merge plan to the mainline kernel for
+         your module is.
+
 config DEBUG_KERNEL
        bool "Kernel debugging"
        help
@@ -107,6 +123,24 @@ config DEBUG_MUTEXES
         This allows mutex semantics violations and mutex related deadlocks
         (lockups) to be detected and reported automatically.
 
+config DEBUG_RT_MUTEXES
+       bool "RT Mutex debugging, deadlock detection"
+       depends on DEBUG_KERNEL && RT_MUTEXES
+       help
+        This allows rt mutex semantics violations and rt mutex related
+        deadlocks (lockups) to be detected and reported automatically.
+
+config DEBUG_PI_LIST
+       bool
+       default y
+       depends on DEBUG_RT_MUTEXES
+
+config RT_MUTEX_TESTER
+       bool "Built-in scriptable tester for rt-mutexes"
+       depends on DEBUG_KERNEL && RT_MUTEXES
+       help
+         This option enables a rt-mutex tester.
+
 config DEBUG_SPINLOCK
        bool "Spinlock debugging"
        depends on DEBUG_KERNEL
index 79358ad1f11353d3ada95577e41a9a857f0f3805..10c13c9d7824d21aa6425001b3a1d0c0403edfa5 100644 (file)
@@ -25,6 +25,7 @@ lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
+obj-$(CONFIG_PLIST) += plist.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 
 ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
diff --git a/lib/plist.c b/lib/plist.c
new file mode 100644 (file)
index 0000000..3074a02
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * lib/plist.c
+ *
+ * Descending-priority-sorted double-linked list
+ *
+ * (C) 2002-2003 Intel Corp
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
+ *
+ * 2001-2005 (c) MontaVista Software, Inc.
+ * Daniel Walker <dwalker@mvista.com>
+ *
+ * (C) 2005 Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Simplifications of the original code by
+ * Oleg Nesterov <oleg@tv-sign.ru>
+ *
+ * Licensed under the FSF's GNU Public License v2 or later.
+ *
+ * Based on simple lists (include/linux/list.h).
+ *
+ * This file contains the add / del functions which are considered to
+ * be too large to inline. See include/linux/plist.h for further
+ * information.
+ */
+
+#include <linux/plist.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_DEBUG_PI_LIST
+
+static void plist_check_prev_next(struct list_head *t, struct list_head *p,
+                                 struct list_head *n)
+{
+       if (n->prev != p || p->next != n) {
+               printk("top: %p, n: %p, p: %p\n", t, t->next, t->prev);
+               printk("prev: %p, n: %p, p: %p\n", p, p->next, p->prev);
+               printk("next: %p, n: %p, p: %p\n", n, n->next, n->prev);
+               WARN_ON(1);
+       }
+}
+
+static void plist_check_list(struct list_head *top)
+{
+       struct list_head *prev = top, *next = top->next;
+
+       plist_check_prev_next(top, prev, next);
+       while (next != top) {
+               prev = next;
+               next = prev->next;
+               plist_check_prev_next(top, prev, next);
+       }
+}
+
+static void plist_check_head(struct plist_head *head)
+{
+       WARN_ON(!head->lock);
+       if (head->lock)
+               WARN_ON_SMP(!spin_is_locked(head->lock));
+       plist_check_list(&head->prio_list);
+       plist_check_list(&head->node_list);
+}
+
+#else
+# define plist_check_head(h)   do { } while (0)
+#endif
+
+/**
+ * plist_add - add @node to @head
+ *
+ * @node:      &struct plist_node pointer
+ * @head:      &struct plist_head pointer
+ */
+void plist_add(struct plist_node *node, struct plist_head *head)
+{
+       struct plist_node *iter;
+
+       plist_check_head(head);
+       WARN_ON(!plist_node_empty(node));
+
+       list_for_each_entry(iter, &head->prio_list, plist.prio_list) {
+               if (node->prio < iter->prio)
+                       goto lt_prio;
+               else if (node->prio == iter->prio) {
+                       iter = list_entry(iter->plist.prio_list.next,
+                                       struct plist_node, plist.prio_list);
+                       goto eq_prio;
+               }
+       }
+
+lt_prio:
+       list_add_tail(&node->plist.prio_list, &iter->plist.prio_list);
+eq_prio:
+       list_add_tail(&node->plist.node_list, &iter->plist.node_list);
+
+       plist_check_head(head);
+}
+
+/**
+ * plist_del - Remove a @node from plist.
+ *
+ * @node:      &struct plist_node pointer - entry to be removed
+ * @head:      &struct plist_head pointer - list head
+ */
+void plist_del(struct plist_node *node, struct plist_head *head)
+{
+       plist_check_head(head);
+
+       if (!list_empty(&node->plist.prio_list)) {
+               struct plist_node *next = plist_first(&node->plist);
+
+               list_move_tail(&next->plist.prio_list, &node->plist.prio_list);
+               list_del_init(&node->plist.prio_list);
+       }
+
+       list_del_init(&node->plist.node_list);
+
+       plist_check_head(head);
+}
index 797428afd1114f3dc1ad3c239917b9f04ceccd55..bed7229378f2da073be0c25eda0a30bf07146380 100644 (file)
@@ -489,7 +489,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                if (str < end)
                        *str = '\0';
                else
-                       *end = '\0';
+                       end[-1] = '\0';
        }
        /* the trailing null byte doesn't count towards the total */
        return str-buf;
index 02a16eacb72dabb50861193db448004b175bd3dc..d84560c076d83cfca8a0d2d19b6214ed1cac23ca 100644 (file)
       bytes, which is the maximum length that can be coded.  inflate_fast()
       requires strm->avail_out >= 258 for each loop to avoid checking for
       output space.
+
+    - @start:  inflate()'s starting value for strm->avail_out
  */
-void inflate_fast(strm, start)
-z_streamp strm;
-unsigned start;         /* inflate()'s starting value for strm->avail_out */
+void inflate_fast(z_streamp strm, unsigned start)
 {
     struct inflate_state *state;
     unsigned char *in;      /* local strm->next_in */
index da665fbb16aaf4e6b9fdf8f69c25b46bc4785f3e..3fe6ce5b53e51999b0ad15f97843b93c313cb60f 100644 (file)
    table index bits.  It will differ if the request is greater than the
    longest code or if it is less than the shortest code.
  */
-int zlib_inflate_table(type, lens, codes, table, bits, work)
-codetype type;
-unsigned short *lens;
-unsigned codes;
-code **table;
-unsigned *bits;
-unsigned short *work;
+int zlib_inflate_table(codetype type, unsigned short *lens, unsigned codes,
+                       code **table, unsigned *bits, unsigned short *work)
 {
     unsigned len;               /* a code's length in bits */
     unsigned sym;               /* index of code symbols */
index 66e65ab3942651e86f2fbbadcf914fd600e41600..8f5b45615f7bf1b43c35253b8f28f1ef4871818e 100644 (file)
@@ -115,7 +115,8 @@ config SPARSEMEM_EXTREME
 # eventually, we can have this option just 'select SPARSEMEM'
 config MEMORY_HOTPLUG
        bool "Allow for memory hot-add"
-       depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND
+       depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
+       depends on (IA64 || X86 || PPC64)
 
 comment "Memory hotplug is currently incompatible with Software Suspend"
        depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND
@@ -145,3 +146,9 @@ config MIGRATION
          while the virtual addresses are not changed. This is useful for
          example on NUMA systems to put pages nearer to the processors accessing
          the page.
+
+config RESOURCES_64BIT
+       bool "64 bit Memory and IO resources (EXPERIMENTAL)" if (!64BIT && EXPERIMENTAL)
+       default 64BIT
+       help
+         This option allows memory and IO resources to be 64 bit.
index 9c7334bafda8da5150f4a9f0a7556bda113b8a19..648f2c0c8e18896b1f979f2f31a848986cc6492b 100644 (file)
@@ -2069,7 +2069,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
 {
        struct file *file = iocb->ki_filp;
        struct address_space * mapping = file->f_mapping;
-       struct address_space_operations *a_ops = mapping->a_ops;
+       const struct address_space_operations *a_ops = mapping->a_ops;
        struct inode    *inode = mapping->host;
        long            status = 0;
        struct page     *page;
@@ -2095,14 +2095,21 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
        do {
                unsigned long index;
                unsigned long offset;
-               unsigned long maxlen;
                size_t copied;
 
                offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
                index = pos >> PAGE_CACHE_SHIFT;
                bytes = PAGE_CACHE_SIZE - offset;
-               if (bytes > count)
-                       bytes = count;
+
+               /* Limit the size of the copy to the caller's write size */
+               bytes = min(bytes, count);
+
+               /*
+                * Limit the size of the copy to that of the current segment,
+                * because fault_in_pages_readable() doesn't know how to walk
+                * segments.
+                */
+               bytes = min(bytes, cur_iov->iov_len - iov_base);
 
                /*
                 * Bring in the user page that we will copy from _first_.
@@ -2110,10 +2117,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                 * same page as we're writing to, without it being marked
                 * up-to-date.
                 */
-               maxlen = cur_iov->iov_len - iov_base;
-               if (maxlen > bytes)
-                       maxlen = bytes;
-               fault_in_pages_readable(buf, maxlen);
+               fault_in_pages_readable(buf, bytes);
 
                page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);
                if (!page) {
@@ -2121,6 +2125,12 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                        break;
                }
 
+               if (unlikely(bytes == 0)) {
+                       status = 0;
+                       copied = 0;
+                       goto zero_length_segment;
+               }
+
                status = a_ops->prepare_write(file, page, offset, offset+bytes);
                if (unlikely(status)) {
                        loff_t isize = i_size_read(inode);
@@ -2150,7 +2160,8 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                        page_cache_release(page);
                        continue;
                }
-               if (likely(copied > 0)) {
+zero_length_segment:
+               if (likely(copied >= 0)) {
                        if (!status)
                                status = copied;
 
@@ -2215,7 +2226,7 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t *ppos)
 {
        struct file *file = iocb->ki_filp;
-       struct address_space * mapping = file->f_mapping;
+       const struct address_space * mapping = file->f_mapping;
        size_t ocount;          /* original count */
        size_t count;           /* after file limit checks */
        struct inode    *inode = mapping->host;
index 536979fb4ba717443be39b9e0e8a95dfd012200c..3f2a343c6015f2b4b9564307bb557a0dbdddb8f5 100644 (file)
@@ -88,7 +88,7 @@ filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
        const struct iovec *iov = *iovp;
        size_t base = *basep;
 
-       while (bytes) {
+       do {
                int copy = min(bytes, iov->iov_len - base);
 
                bytes -= copy;
@@ -97,7 +97,7 @@ filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
                        iov++;
                        base = 0;
                }
-       }
+       } while (bytes);
        *iovp = iov;
        *basep = base;
 }
index b960ac8e5918dcb33e64b9b4f822f25540ddb4b4..b4fd0d7c9bfb23e08e2380d9b06bca14de4a95e7 100644 (file)
@@ -273,7 +273,7 @@ __xip_file_write(struct file *filp, const char __user *buf,
                  size_t count, loff_t pos, loff_t *ppos)
 {
        struct address_space * mapping = filp->f_mapping;
-       struct address_space_operations *a_ops = mapping->a_ops;
+       const struct address_space_operations *a_ops = mapping->a_ops;
        struct inode    *inode = mapping->host;
        long            status = 0;
        struct page     *page;
index 841a077d5aeb0d3423ecba8ed5d81efdd72c2442..ea4038838b0a2b4c95a46cc3d4f1eaad25556f5f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/memory_hotplug.h>
 #include <linux/highmem.h>
 #include <linux/vmalloc.h>
+#include <linux/ioport.h>
 
 #include <asm/tlbflush.h>
 
@@ -126,6 +127,9 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        unsigned long i;
        unsigned long flags;
        unsigned long onlined_pages = 0;
+       struct resource res;
+       u64 section_end;
+       unsigned long start_pfn;
        struct zone *zone;
        int need_zonelists_rebuild = 0;
 
@@ -148,10 +152,27 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        if (!populated_zone(zone))
                need_zonelists_rebuild = 1;
 
-       for (i = 0; i < nr_pages; i++) {
-               struct page *page = pfn_to_page(pfn + i);
-               online_page(page);
-               onlined_pages++;
+       res.start = (u64)pfn << PAGE_SHIFT;
+       res.end = res.start + ((u64)nr_pages << PAGE_SHIFT) - 1;
+       res.flags = IORESOURCE_MEM; /* we just need system ram */
+       section_end = res.end;
+
+       while (find_next_system_ram(&res) >= 0) {
+               start_pfn = (unsigned long)(res.start >> PAGE_SHIFT);
+               nr_pages = (unsigned long)
+                           ((res.end + 1 - res.start) >> PAGE_SHIFT);
+
+               if (PageReserved(pfn_to_page(start_pfn))) {
+                       /* this region's page is not onlined now */
+                       for (i = 0; i < nr_pages; i++) {
+                               struct page *page = pfn_to_page(start_pfn + i);
+                               online_page(page);
+                               onlined_pages++;
+                       }
+               }
+
+               res.start = res.end + 1;
+               res.end = section_end;
        }
        zone->present_pages += onlined_pages;
        zone->zone_pgdat->node_present_pages += onlined_pages;
@@ -163,3 +184,100 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        vm_total_pages = nr_free_pagecache_pages();
        return 0;
 }
+
+static pg_data_t *hotadd_new_pgdat(int nid, u64 start)
+{
+       struct pglist_data *pgdat;
+       unsigned long zones_size[MAX_NR_ZONES] = {0};
+       unsigned long zholes_size[MAX_NR_ZONES] = {0};
+       unsigned long start_pfn = start >> PAGE_SHIFT;
+
+       pgdat = arch_alloc_nodedata(nid);
+       if (!pgdat)
+               return NULL;
+
+       arch_refresh_nodedata(nid, pgdat);
+
+       /* we can use NODE_DATA(nid) from here */
+
+       /* init node's zones as empty zones, we don't have any present pages.*/
+       free_area_init_node(nid, pgdat, zones_size, start_pfn, zholes_size);
+
+       return pgdat;
+}
+
+static void rollback_node_hotadd(int nid, pg_data_t *pgdat)
+{
+       arch_refresh_nodedata(nid, NULL);
+       arch_free_nodedata(pgdat);
+       return;
+}
+
+/* add this memory to iomem resource */
+static void register_memory_resource(u64 start, u64 size)
+{
+       struct resource *res;
+
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(!res);
+
+       res->name = "System RAM";
+       res->start = start;
+       res->end = start + size - 1;
+       res->flags = IORESOURCE_MEM;
+       if (request_resource(&iomem_resource, res) < 0) {
+               printk("System RAM resource %llx - %llx cannot be added\n",
+               (unsigned long long)res->start, (unsigned long long)res->end);
+               kfree(res);
+       }
+}
+
+
+
+int add_memory(int nid, u64 start, u64 size)
+{
+       pg_data_t *pgdat = NULL;
+       int new_pgdat = 0;
+       int ret;
+
+       if (!node_online(nid)) {
+               pgdat = hotadd_new_pgdat(nid, start);
+               if (!pgdat)
+                       return -ENOMEM;
+               new_pgdat = 1;
+               ret = kswapd_run(nid);
+               if (ret)
+                       goto error;
+       }
+
+       /* call arch's memory hotadd */
+       ret = arch_add_memory(nid, start, size);
+
+       if (ret < 0)
+               goto error;
+
+       /* we online node here. we can't roll back from here. */
+       node_set_online(nid);
+
+       if (new_pgdat) {
+               ret = register_one_node(nid);
+               /*
+                * If sysfs file of new node can't create, cpu on the node
+                * can't be hot-added. There is no rollback way now.
+                * So, check by BUG_ON() to catch it reluctantly..
+                */
+               BUG_ON(ret);
+       }
+
+       /* register this memory as resource */
+       register_memory_resource(start, size);
+
+       return ret;
+error:
+       /* rollback pgdat allocation and others */
+       if (new_pgdat)
+               rollback_node_hotadd(nid, pgdat);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(add_memory);
index 8ccf6f1b1473c1e26e0da73e5f8f95c4b041def9..4ec7026c7bab14e1f4a9e512742e318a6630607f 100644 (file)
@@ -516,14 +516,14 @@ static void set_ratelimit(void)
                ratelimit_pages = (4096 * 1024) / PAGE_CACHE_SIZE;
 }
 
-static int
+static int __cpuinit
 ratelimit_handler(struct notifier_block *self, unsigned long u, void *v)
 {
        set_ratelimit();
        return 0;
 }
 
-static struct notifier_block ratelimit_nb = {
+static struct notifier_block __cpuinitdata ratelimit_nb = {
        .notifier_call  = ratelimit_handler,
        .next           = NULL,
 };
index 9f86191bb632955a224d94ddf6c53980c64e9244..084a2de7e52a8c8b4ceaa3c78997199d17f770e5 100644 (file)
@@ -446,8 +446,8 @@ static void __free_pages_ok(struct page *page, unsigned int order)
 
        arch_free_page(page, order);
        if (!PageHighMem(page))
-               mutex_debug_check_no_locks_freed(page_address(page),
-                                                PAGE_SIZE<<order);
+               debug_check_no_locks_freed(page_address(page),
+                                          PAGE_SIZE<<order);
 
        for (i = 0 ; i < (1 << order) ; ++i)
                reserved += free_pages_check(page + i);
@@ -2009,7 +2009,7 @@ static inline void free_zone_pagesets(int cpu)
        }
 }
 
-static int pageset_cpuup_callback(struct notifier_block *nfb,
+static int __cpuinit pageset_cpuup_callback(struct notifier_block *nfb,
                unsigned long action,
                void *hcpu)
 {
@@ -2031,7 +2031,7 @@ static int pageset_cpuup_callback(struct notifier_block *nfb,
        return ret;
 }
 
-static struct notifier_block pageset_notifier =
+static struct notifier_block __cpuinitdata pageset_notifier =
        { &pageset_cpuup_callback, NULL, 0 };
 
 void __init setup_per_cpu_pageset(void)
index 38bc3334f2633a4bfe9ed0e40361d075ec35d8ec..ea64c07cbe72b036c4e58bc37bad35cce892213b 100644 (file)
@@ -174,7 +174,7 @@ static inline void shmem_unacct_blocks(unsigned long flags, long pages)
 }
 
 static struct super_operations shmem_ops;
-static struct address_space_operations shmem_aops;
+static const struct address_space_operations shmem_aops;
 static struct file_operations shmem_file_operations;
 static struct inode_operations shmem_inode_operations;
 static struct inode_operations shmem_dir_inode_operations;
@@ -2162,7 +2162,7 @@ static void destroy_inodecache(void)
                printk(KERN_INFO "shmem_inode_cache: not all structures were freed\n");
 }
 
-static struct address_space_operations shmem_aops = {
+static const struct address_space_operations shmem_aops = {
        .writepage      = shmem_writepage,
        .set_page_dirty = __set_page_dirty_nobuffers,
 #ifdef CONFIG_TMPFS
index 98ac20bc0de9a3ad443ef9f8bd54cb1c58ed5de4..233e39d14caf5ae2966c9df788c9c73dc6a563e3 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -89,6 +89,7 @@
 #include       <linux/config.h>
 #include       <linux/slab.h>
 #include       <linux/mm.h>
+#include       <linux/poison.h>
 #include       <linux/swap.h>
 #include       <linux/cache.h>
 #include       <linux/interrupt.h>
 #include       <linux/nodemask.h>
 #include       <linux/mempolicy.h>
 #include       <linux/mutex.h>
+#include       <linux/rtmutex.h>
 
 #include       <asm/uaccess.h>
 #include       <asm/cacheflush.h>
@@ -492,17 +494,6 @@ struct kmem_cache {
 #endif
 
 #if DEBUG
-/*
- * Magic nums for obj red zoning.
- * Placed in the first word before and the first word after an obj.
- */
-#define        RED_INACTIVE    0x5A2CF071UL    /* when obj is inactive */
-#define        RED_ACTIVE      0x170FC2A5UL    /* when obj is active */
-
-/* ...and for poisoning */
-#define        POISON_INUSE    0x5a    /* for use-uninitialised poisoning */
-#define POISON_FREE    0x6b    /* for use-after-free poisoning */
-#define        POISON_END      0xa5    /* end-byte of poisoning */
 
 /*
  * memory layout of objects:
@@ -1083,7 +1074,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 
 #endif
 
-static int cpuup_callback(struct notifier_block *nfb,
+static int __devinit cpuup_callback(struct notifier_block *nfb,
                                    unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
@@ -1265,7 +1256,9 @@ bad:
        return NOTIFY_BAD;
 }
 
-static struct notifier_block cpucache_notifier = { &cpuup_callback, NULL, 0 };
+static struct notifier_block __cpuinitdata cpucache_notifier = {
+       &cpuup_callback, NULL, 0
+};
 
 /*
  * swap the static kmem_list3 with kmalloced memory
@@ -3405,7 +3398,7 @@ void kfree(const void *objp)
        local_irq_save(flags);
        kfree_debugcheck(objp);
        c = virt_to_cache(objp);
-       mutex_debug_check_no_locks_freed(objp, obj_size(c));
+       debug_check_no_locks_freed(objp, obj_size(c));
        __cache_free(c, (void *)objp);
        local_irq_restore(flags);
 }
index e0a3fe48aa3745bebd710ff80d8cad6215dd244d..c7a2b3a0e46b2961fbc6fe6794e562be66def97e 100644 (file)
@@ -45,7 +45,7 @@ static struct mem_section *sparse_index_alloc(int nid)
 
 static int sparse_index_init(unsigned long section_nr, int nid)
 {
-       static spinlock_t index_init_lock = SPIN_LOCK_UNLOCKED;
+       static DEFINE_SPINLOCK(index_init_lock);
        unsigned long root = SECTION_NR_TO_ROOT(section_nr);
        struct mem_section *section;
        int ret = 0;
index e0e1583f32c26cc2579554a4abcc797a9a671553..7535211bb495c9f54a3ece2e37feaa4c0589162d 100644 (file)
@@ -24,7 +24,7 @@
  * vmscan's shrink_list, to make sync_page look nicer, and to allow
  * future use of radix_tree tags in the swap cache.
  */
-static struct address_space_operations swap_aops = {
+static const struct address_space_operations swap_aops = {
        .writepage      = swap_writepage,
        .sync_page      = block_sync_page,
        .set_page_dirty = __set_page_dirty_nobuffers,
index 72babac71deaba28f9c75a1b6d2ccacb8ba537fa..eeacb0d695c35233e57688e4d20314a149d1d22c 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/notifier.h>
 #include <linux/rwsem.h>
 #include <linux/delay.h>
+#include <linux/kthread.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -1223,7 +1224,6 @@ static int kswapd(void *p)
        };
        cpumask_t cpumask;
 
-       daemonize("kswapd%d", pgdat->node_id);
        cpumask = node_to_cpumask(pgdat->node_id);
        if (!cpus_empty(cpumask))
                set_cpus_allowed(tsk, cpumask);
@@ -1450,7 +1450,7 @@ out:
    not required for correctness.  So if the last cpu in a node goes
    away, we get changed to run anywhere: as the first one comes back,
    restore their cpu bindings. */
-static int cpu_callback(struct notifier_block *nfb,
+static int __devinit cpu_callback(struct notifier_block *nfb,
                                  unsigned long action, void *hcpu)
 {
        pg_data_t *pgdat;
@@ -1468,20 +1468,35 @@ static int cpu_callback(struct notifier_block *nfb,
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
+/*
+ * This kswapd start function will be called by init and node-hot-add.
+ * On node-hot-add, kswapd will moved to proper cpus if cpus are hot-added.
+ */
+int kswapd_run(int nid)
+{
+       pg_data_t *pgdat = NODE_DATA(nid);
+       int ret = 0;
+
+       if (pgdat->kswapd)
+               return 0;
+
+       pgdat->kswapd = kthread_run(kswapd, pgdat, "kswapd%d", nid);
+       if (IS_ERR(pgdat->kswapd)) {
+               /* failure at boot is fatal */
+               BUG_ON(system_state == SYSTEM_BOOTING);
+               printk("Failed to start kswapd on node %d\n",nid);
+               ret = -1;
+       }
+       return ret;
+}
+
 static int __init kswapd_init(void)
 {
-       pg_data_t *pgdat;
+       int nid;
 
        swap_setup();
-       for_each_online_pgdat(pgdat) {
-               pid_t pid;
-
-               pid = kernel_thread(kswapd, pgdat, CLONE_KERNEL);
-               BUG_ON(pid < 0);
-               read_lock(&tasklist_lock);
-               pgdat->kswapd = find_task_by_pid(pid);
-               read_unlock(&tasklist_lock);
-       }
+       for_each_online_node(nid)
+               kswapd_run(nid);
        hotcpu_notifier(cpu_callback, 0);
        return 0;
 }
index 74368f79ee5d084e0645c6af221062567f475e47..b81fad893328663203c6be595df7de9f2895c4e4 100644 (file)
@@ -480,12 +480,8 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
 
        BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
 
-       if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-               tty_buffer_request_room(tty, skb->len);
-               tty_insert_flip_string(tty, skb->data, skb->len);
-               tty_flip_buffer_push(tty);
-       } else
-               tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
+       tty_insert_flip_string(tty, skb->data, skb->len);
+       tty_flip_buffer_push(tty);
 
        kfree_skb(skb);
 }
index 8a777932786d7d4c0975fd6941489039abad3d06..e728980160d2243400ed49cd2124bd7dfec5bb34 100644 (file)
@@ -349,7 +349,7 @@ static struct rt6_info *rt6_select(struct rt6_info **head, int oif,
            (strict & RT6_SELECT_F_REACHABLE) &&
            last && last != rt0) {
                /* no entries matched; do round-robin */
-               static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+               static DEFINE_SPINLOCK(lock);
                spin_lock(&lock);
                *head = rt0->u.next;
                rt0->u.next = last->u.next;
index f43311221a72b9a8b4f56cd177a33e5cd0296b41..2f312164d6d5611559aabab099e37ef8e55f7459 100644 (file)
@@ -70,7 +70,7 @@
 # define RPCDBG_FACILITY        RPCDBG_AUTH
 #endif
 
-spinlock_t krb5_seq_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(krb5_seq_lock);
 
 u32
 gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
index 54128040a1245ad9231ff00db3ebaf12644c273e..1bb75703f3848b8e50bdf57ad561d28f829e8132 100644 (file)
@@ -117,7 +117,7 @@ struct bclink {
 static struct bcbearer *bcbearer = NULL;
 static struct bclink *bclink = NULL;
 static struct link *bcl = NULL;
-static spinlock_t bc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(bc_lock);
 
 char tipc_bclink_name[] = "multicast-link";
 
@@ -796,7 +796,7 @@ int tipc_bclink_init(void)
        memset(bclink, 0, sizeof(struct bclink));
        INIT_LIST_HEAD(&bcl->waiting_ports);
        bcl->next_out_no = 1;
-       bclink->node.lock =  SPIN_LOCK_UNLOCKED;        
+       spin_lock_init(&bclink->node.lock);
        bcl->owner = &bclink->node;
         bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
        tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
index 4fa24b5e8914a559d3cc025731355bb0664e856c..7ef17a449cfdb33d696c19428430ab891c4c316c 100644 (file)
@@ -566,7 +566,7 @@ restart:
                b_ptr->link_req = tipc_disc_init_link_req(b_ptr, &m_ptr->bcast_addr,
                                                          bcast_scope, 2);
        }
-       b_ptr->publ.lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&b_ptr->publ.lock);
        write_unlock_bh(&tipc_net_lock);
        info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
             name, addr_string_fill(addr_string, bcast_scope), priority);
index 3ec502fac8c34b29a0ed66253341e35dfb60a83c..285e1bc2d8808502f53e952eed76a1dd72308534 100644 (file)
@@ -63,7 +63,7 @@ struct manager {
 
 static struct manager mng = { 0};
 
-static spinlock_t config_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(config_lock);
 
 static const void *req_tlv_area;       /* request message TLV area */
 static int req_tlv_space;              /* request message TLV area size */
index 26ef95d5fe38601611e6d95a4d6248276235b4cb..55130655e1edbe306a484f552c2a20080496cb15 100644 (file)
@@ -41,7 +41,7 @@
 #define MAX_STRING 512
 
 static char print_string[MAX_STRING];
-static spinlock_t print_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(print_lock);
 
 static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
 struct print_buf *TIPC_CONS = &cons_buf;
index 966f70a1b60800012c14a09e7377eeea2414c0d0..ae6ddf00a1aaea8aaaa17d708e4d4eaca4bfe059 100644 (file)
@@ -44,7 +44,7 @@ struct queue_item {
 
 static kmem_cache_t *tipc_queue_item_cache;
 static struct list_head signal_queue_head;
-static spinlock_t qitem_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(qitem_lock);
 static int handler_enabled = 0;
 
 static void process_signal_queue(unsigned long dummy);
index 38571306aba5ab0bb60a86be10a0c8202b28f40a..a6926ff07bcc3e2365d0424e30b721df1e455d21 100644 (file)
@@ -101,7 +101,7 @@ struct name_table {
 
 static struct name_table table = { NULL } ;
 static atomic_t rsv_publ_ok = ATOMIC_INIT(0);
-rwlock_t tipc_nametbl_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(tipc_nametbl_lock);
 
 
 static int hash(int x)
@@ -172,7 +172,7 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea
        }
 
        memset(nseq, 0, sizeof(*nseq));
-       nseq->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&nseq->lock);
        nseq->type = type;
        nseq->sseqs = sseq;
        dbg("tipc_nameseq_create(): nseq = %p, type %u, ssseqs %p, ff: %u\n",
index f7c8223ddf7dd0f3e9ce9c148e2cca1d1915cb3f..e5a359ab49308025f10a1c065cfffa23e7991a5f 100644 (file)
  *     - A local spin_lock protecting the queue of subscriber events.
 */
 
-rwlock_t tipc_net_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(tipc_net_lock);
 struct network tipc_net = { NULL };
 
 struct node *tipc_net_select_remote_node(u32 addr, u32 ref) 
index ce9678efa98a5822b5e205d879fb158b3f8ddb44..861322b935daf1be3aee4ac4e5eca284c4a7c89a 100644 (file)
@@ -77,7 +77,7 @@ struct node *tipc_node_create(u32 addr)
                
        memset(n_ptr, 0, sizeof(*n_ptr));
        n_ptr->addr = addr;
-       n_ptr->lock =  SPIN_LOCK_UNLOCKED;      
+                spin_lock_init(&n_ptr->lock);
        INIT_LIST_HEAD(&n_ptr->nsub);
        n_ptr->owner = c_ptr;
        tipc_cltr_attach_node(c_ptr, n_ptr);
index 47d97404e3ee06a3de6d9f2721af8211a78fd8d3..3251c8d8e53c3bcc401a13e53d6636d410b6b5d0 100644 (file)
@@ -57,8 +57,8 @@
 static struct sk_buff *msg_queue_head = NULL;
 static struct sk_buff *msg_queue_tail = NULL;
 
-spinlock_t tipc_port_list_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(tipc_port_list_lock);
+static DEFINE_SPINLOCK(queue_lock);
 
 static LIST_HEAD(ports);
 static void port_handle_node_down(unsigned long ref);
index d2f0cce10e2046c0e9693b113c6e234b30792f1a..596d3c8ff75006a95545e9f1a9407bd5e6b9d062 100644 (file)
@@ -63,7 +63,7 @@
 
 struct ref_table tipc_ref_table = { NULL };
 
-static rwlock_t ref_table_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(ref_table_lock);
 
 /**
  * tipc_ref_table_init - create reference table for objects
@@ -87,7 +87,7 @@ int tipc_ref_table_init(u32 requested_size, u32 start)
        index_mask = sz - 1;
        for (i = sz - 1; i >= 0; i--) {
                table[i].object = NULL;
-               table[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&table[i].lock);
                table[i].data.next_plus_upper = (start & ~index_mask) + i - 1;
        }
        tipc_ref_table.entries = table;
index fc171875660c5eda665c7674509ab9dc72fac057..e19b4bcd67ec2bf44b6a2e7f4186751984782c4b 100644 (file)
@@ -457,7 +457,7 @@ int tipc_subscr_start(void)
        int res = -1;
 
        memset(&topsrv, 0, sizeof (topsrv));
-       topsrv.lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&topsrv.lock);
        INIT_LIST_HEAD(&topsrv.subscriber_list);
 
        spin_lock_bh(&topsrv.lock);
index 3f3f933976e9dc27603cff2deec0b74150faebc4..1e3ae57c722872f2e2d74d28891ecb39d53d0f21 100644 (file)
@@ -67,7 +67,7 @@ struct tipc_user {
 
 static struct tipc_user *users = NULL;
 static u32 next_free_user = MAX_USERID + 1;
-static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(reg_lock);
 
 /**
  * reg_init - create TIPC user registry (but don't activate it)
diff --git a/scripts/rt-tester/check-all.sh b/scripts/rt-tester/check-all.sh
new file mode 100644 (file)
index 0000000..43098af
--- /dev/null
@@ -0,0 +1,22 @@
+
+
+function testit ()
+{
+ printf "%-30s: " $1
+ ./rt-tester.py $1 | grep Pass
+}
+
+testit t2-l1-2rt-sameprio.tst
+testit t2-l1-pi.tst
+testit t2-l1-signal.tst
+#testit t2-l2-2rt-deadlock.tst
+testit t3-l1-pi-1rt.tst
+testit t3-l1-pi-2rt.tst
+testit t3-l1-pi-3rt.tst
+testit t3-l1-pi-signal.tst
+testit t3-l1-pi-steal.tst
+testit t3-l2-pi.tst
+testit t4-l2-pi-deboost.tst
+testit t5-l4-pi-boost-deboost.tst
+testit t5-l4-pi-boost-deboost-setsched.tst
+
diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py
new file mode 100644 (file)
index 0000000..4c79660
--- /dev/null
@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+#
+# rt-mutex tester
+#
+# (C) 2006 Thomas Gleixner <tglx@linutronix.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+import os
+import sys
+import getopt
+import shutil
+import string
+
+# Globals
+quiet = 0
+test = 0
+comments = 0
+
+sysfsprefix = "/sys/devices/system/rttest/rttest"
+statusfile = "/status"
+commandfile = "/command"
+
+# Command opcodes
+cmd_opcodes = {
+    "schedother"    : "1",
+    "schedfifo"     : "2",
+    "lock"          : "3",
+    "locknowait"    : "4",
+    "lockint"       : "5",
+    "lockintnowait" : "6",
+    "lockcont"      : "7",
+    "unlock"        : "8",
+    "lockbkl"       : "9",
+    "unlockbkl"     : "10",
+    "signal"        : "11",
+    "resetevent"    : "98",
+    "reset"         : "99",
+    }
+
+test_opcodes = {
+    "prioeq"        : ["P" , "eq" , None],
+    "priolt"        : ["P" , "lt" , None],
+    "priogt"        : ["P" , "gt" , None],
+    "nprioeq"       : ["N" , "eq" , None],
+    "npriolt"       : ["N" , "lt" , None],
+    "npriogt"       : ["N" , "gt" , None],
+    "unlocked"      : ["M" , "eq" , 0],
+    "trylock"       : ["M" , "eq" , 1],
+    "blocked"       : ["M" , "eq" , 2],
+    "blockedwake"   : ["M" , "eq" , 3],
+    "locked"        : ["M" , "eq" , 4],
+    "opcodeeq"      : ["O" , "eq" , None],
+    "opcodelt"      : ["O" , "lt" , None],
+    "opcodegt"      : ["O" , "gt" , None],
+    "eventeq"       : ["E" , "eq" , None],
+    "eventlt"       : ["E" , "lt" , None],
+    "eventgt"       : ["E" , "gt" , None],
+    }
+
+# Print usage information
+def usage():
+    print "rt-tester.py <-c -h -q -t> <testfile>"
+    print " -c    display comments after first command"
+    print " -h    help"
+    print " -q    quiet mode"
+    print " -t    test mode (syntax check)"
+    print " testfile: read test specification from testfile"
+    print " otherwise from stdin"
+    return
+
+# Print progress when not in quiet mode
+def progress(str):
+    if not quiet:
+        print str
+
+# Analyse a status value
+def analyse(val, top, arg):
+
+    intval = int(val)
+
+    if top[0] == "M":
+        intval = intval / (10 ** int(arg))
+       intval = intval % 10
+        argval = top[2]
+    elif top[0] == "O":
+        argval = int(cmd_opcodes.get(arg, arg))
+    else:
+        argval = int(arg)
+
+    # progress("%d %s %d" %(intval, top[1], argval))
+
+    if top[1] == "eq" and intval == argval:
+       return 1
+    if top[1] == "lt" and intval < argval:
+        return 1
+    if top[1] == "gt" and intval > argval:
+       return 1
+    return 0
+
+# Parse the commandline
+try:
+    (options, arguments) = getopt.getopt(sys.argv[1:],'chqt')
+except getopt.GetoptError, ex:
+    usage()
+    sys.exit(1)
+
+# Parse commandline options
+for option, value in options:
+    if option == "-c":
+        comments = 1
+    elif option == "-q":
+        quiet = 1
+    elif option == "-t":
+        test = 1
+    elif option == '-h':
+        usage()
+        sys.exit(0)
+
+# Select the input source
+if arguments:
+    try:
+        fd = open(arguments[0])
+    except Exception,ex:
+        sys.stderr.write("File not found %s\n" %(arguments[0]))
+        sys.exit(1)
+else:
+    fd = sys.stdin
+
+linenr = 0
+
+# Read the test patterns
+while 1:
+
+    linenr = linenr + 1
+    line = fd.readline()
+    if not len(line):
+        break
+
+    line = line.strip()
+    parts = line.split(":")
+
+    if not parts or len(parts) < 1:
+        continue
+
+    if len(parts[0]) == 0:
+        continue
+
+    if parts[0].startswith("#"):
+       if comments > 1:
+           progress(line)
+       continue
+
+    if comments == 1:
+       comments = 2
+
+    progress(line)
+
+    cmd = parts[0].strip().lower()
+    opc = parts[1].strip().lower()
+    tid = parts[2].strip()
+    dat = parts[3].strip()
+
+    try:
+        # Test or wait for a status value
+        if cmd == "t" or cmd == "w":
+            testop = test_opcodes[opc]
+
+            fname = "%s%s%s" %(sysfsprefix, tid, statusfile)
+            if test:
+               print fname
+                continue
+
+            while 1:
+                query = 1
+                fsta = open(fname, 'r')
+                status = fsta.readline().strip()
+                fsta.close()
+                stat = status.split(",")
+                for s in stat:
+                   s = s.strip()
+                    if s.startswith(testop[0]):
+                        # Seperate status value
+                        val = s[2:].strip()
+                        query = analyse(val, testop, dat)
+                        break
+                if query or cmd == "t":
+                    break
+
+            progress("   " + status)
+
+            if not query:
+                sys.stderr.write("Test failed in line %d\n" %(linenr))
+               sys.exit(1)
+
+        # Issue a command to the tester
+        elif cmd == "c":
+            cmdnr = cmd_opcodes[opc]
+            # Build command string and sys filename
+            cmdstr = "%s:%s" %(cmdnr, dat)
+            fname = "%s%s%s" %(sysfsprefix, tid, commandfile)
+            if test:
+               print fname
+                continue
+            fcmd = open(fname, 'w')
+            fcmd.write(cmdstr)
+            fcmd.close()
+
+    except Exception,ex:
+       sys.stderr.write(str(ex))
+        sys.stderr.write("\nSyntax error in line %d\n" %(linenr))
+        if not test:
+            fd.close()
+            sys.exit(1)
+
+# Normal exit pass
+print "Pass"
+sys.exit(0)
+
+
diff --git a/scripts/rt-tester/t2-l1-2rt-sameprio.tst b/scripts/rt-tester/t2-l1-2rt-sameprio.tst
new file mode 100644 (file)
index 0000000..8821f27
--- /dev/null
@@ -0,0 +1,99 @@
+#
+# RT-Mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       0
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 2 threads 1 lock
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedfifo:          0:      80
+C: schedfifo:          1:      80
+
+# T0 lock L0
+C: locknowait:         0:      0
+C: locknowait:         1:      0
+W: locked:             0:      0
+W: blocked:            1:      0
+T: prioeq:             0:      80
+
+# T0 unlock L0
+C: unlock:             0:      0
+W: locked:             1:      0
+
+# Verify T0
+W: unlocked:           0:      0
+T: prioeq:             0:      80
+
+# Unlock
+C: unlock:             1:      0
+W: unlocked:           1:      0
+
+# T1,T0 lock L0
+C: locknowait:         1:      0
+C: locknowait:         0:      0
+W: locked:             1:      0
+W: blocked:            0:      0
+T: prioeq:             1:      80
+
+# T1 unlock L0
+C: unlock:             1:      0
+W: locked:             0:      0
+
+# Verify T1
+W: unlocked:           1:      0
+T: prioeq:             1:      80
+
+# Unlock and exit
+C: unlock:             0:      0
+W: unlocked:           0:      0
+
diff --git a/scripts/rt-tester/t2-l1-pi.tst b/scripts/rt-tester/t2-l1-pi.tst
new file mode 100644 (file)
index 0000000..cde1f18
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# RT-Mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       0
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 2 threads 1 lock with priority inversion
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      80
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      80
+
+# T0 unlock L0
+C: unlock:             0:      0
+W: locked:             1:      0
+
+# Verify T1
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+# Unlock and exit
+C: unlock:             1:      0
+W: unlocked:           1:      0
+
diff --git a/scripts/rt-tester/t2-l1-signal.tst b/scripts/rt-tester/t2-l1-signal.tst
new file mode 100644 (file)
index 0000000..3ab0bfc
--- /dev/null
@@ -0,0 +1,77 @@
+#
+# RT-Mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       0
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 2 threads 1 lock with priority inversion
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedother:         1:      0
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: lockintnowait:      1:      0
+W: blocked:            1:      0
+
+# Interrupt T1
+C: signal:             1:      0
+W: unlocked:           1:      0
+T: opcodeeq:           1:      -4
+
+# Unlock and exit
+C: unlock:             0:      0
+W: unlocked:           0:      0
diff --git a/scripts/rt-tester/t2-l2-2rt-deadlock.tst b/scripts/rt-tester/t2-l2-2rt-deadlock.tst
new file mode 100644 (file)
index 0000000..f4b5d5d
--- /dev/null
@@ -0,0 +1,89 @@
+#
+# RT-Mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       0
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 2 threads 2 lock
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedfifo:          0:      80
+C: schedfifo:          1:      80
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L1
+C: locknowait:         1:      1
+W: locked:             1:      1
+
+# T0 lock L1
+C: lockintnowait:      0:      1
+W: blocked:            0:      1
+
+# T1 lock L0
+C: lockintnowait:      1:      0
+W: blocked:            1:      0
+
+# Make deadlock go away
+C: signal:             1:      0
+W: unlocked:           1:      0
+C: signal:             0:      0
+W: unlocked:           0:      1
+
+# Unlock and exit
+C: unlock:             0:      0
+W: unlocked:           0:      0
+C: unlock:             1:      1
+W: unlocked:           1:      1
+
diff --git a/scripts/rt-tester/t3-l1-pi-1rt.tst b/scripts/rt-tester/t3-l1-pi-1rt.tst
new file mode 100644 (file)
index 0000000..63440ca
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 1 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedother:         1:      0
+C: schedfifo:          2:      82
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: priolt:             0:      1
+
+# T2 lock L0
+C: locknowait:         2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      82
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T2 got the lock
+W: locked:             2:      0
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+W: unlocked:           2:      0
+W: locked:             1:      0
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t3-l1-pi-2rt.tst b/scripts/rt-tester/t3-l1-pi-2rt.tst
new file mode 100644 (file)
index 0000000..e5816fe
--- /dev/null
@@ -0,0 +1,93 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 1 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      81
+C: schedfifo:          2:      82
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      81
+
+# T2 lock L0
+C: locknowait:         2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      82
+T: prioeq:             1:      81
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T2 got the lock
+W: locked:             2:      0
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+W: unlocked:           2:      0
+W: locked:             1:      0
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t3-l1-pi-3rt.tst b/scripts/rt-tester/t3-l1-pi-3rt.tst
new file mode 100644 (file)
index 0000000..718b82b
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 1 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedfifo:          0:      80
+C: schedfifo:          1:      81
+C: schedfifo:          2:      82
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      81
+
+# T2 lock L0
+C: locknowait:         2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      82
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T2 got the lock
+W: locked:             2:      0
+W: unlocked:           0:      0
+T: prioeq:             0:      80
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+W: locked:             1:      0
+W: unlocked:           2:      0
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t3-l1-pi-signal.tst b/scripts/rt-tester/t3-l1-pi-signal.tst
new file mode 100644 (file)
index 0000000..c6e2135
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+# Reset event counter
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set priorities
+C: schedother:         0:      0
+C: schedfifo:          1:      80
+C: schedfifo:          2:      81
+
+# T0 lock L0
+C: lock:               0:      0
+W: locked:             0:      0
+
+# T1 lock L0, no wait in the wakeup path
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      80
+T: prioeq:             1:      80
+
+# T2 lock L0 interruptible, no wait in the wakeup path
+C: lockintnowait:      2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      81
+T: prioeq:             1:      80
+
+# Interrupt T2
+C: signal:             2:      2
+W: unlocked:           2:      0
+T: prioeq:             1:      80
+T: prioeq:             0:      80
+
+T: locked:             0:      0
+T: blocked:            1:      0
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T1 has locked L0 and exit
+W: locked:             1:      0
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
+
+
+
diff --git a/scripts/rt-tester/t3-l1-pi-steal.tst b/scripts/rt-tester/t3-l1-pi-steal.tst
new file mode 100644 (file)
index 0000000..f53749d
--- /dev/null
@@ -0,0 +1,96 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 1 lock PI steal pending ownership
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      80
+C: schedfifo:          2:      81
+
+# T0 lock L0
+C: lock:               0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: lock:               1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      80
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T1 is in the wakeup loop
+W: blockedwake:                1:      0
+T: priolt:             0:      1
+
+# T2 lock L0
+C: lock:               2:      0
+# T1 leave wakeup loop
+C: lockcont:           1:      0
+
+# T2 must have the lock and T1 must be blocked
+W: locked:             2:      0
+W: blocked:            1:      0
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+# Wait until T1 is in the wakeup loop and let it run
+W: blockedwake:                1:      0
+C: lockcont:           1:      0
+W: locked:             1:      0
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t3-l2-pi.tst b/scripts/rt-tester/t3-l2-pi.tst
new file mode 100644 (file)
index 0000000..cdc3e4f
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 2 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedother:         1:      0
+C: schedfifo:          2:      82
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: priolt:             0:      1
+
+# T2 lock L0
+C: locknowait:         2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      82
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T2 got the lock
+W: locked:             2:      0
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+W: unlocked:           2:      0
+W: locked:             1:      0
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t4-l2-pi-deboost.tst b/scripts/rt-tester/t4-l2-pi-deboost.tst
new file mode 100644 (file)
index 0000000..baa1413
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 4 threads 2 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedother:         1:      0
+C: schedfifo:          2:      82
+C: schedfifo:          3:      83
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L1
+C: locknowait:         1:      1
+W: locked:             1:      1
+
+# T3 lock L0
+C: lockintnowait:      3:      0
+W: blocked:            3:      0
+T: prioeq:             0:      83
+
+# T0 lock L1
+C: lock:               0:      1
+W: blocked:            0:      1
+T: prioeq:             1:      83
+
+# T1 unlock L1
+C: unlock:             1:      1
+
+# Wait until T0 is in the wakeup code
+W: blockedwake:                0:      1
+
+# Verify that T1 is unboosted
+W: unlocked:           1:      1
+T: priolt:             1:      1
+
+# T2 lock L1 (T0 is boosted and pending owner !)
+C: locknowait:         2:      1
+W: blocked:            2:      1
+T: prioeq:             0:      83
+
+# Interrupt T3 and wait until T3 returned
+C: signal:             3:      0
+W: unlocked:           3:      0
+
+# Verify prio of T0 (still pending owner,
+# but T2 is enqueued due to the previous boost by T3
+T: prioeq:             0:      82
+
+# Let T0 continue
+C: lockcont:           0:      1
+W: locked:             0:      1
+
+# Unlock L1 and let T2 get L1
+C: unlock:             0:      1
+W: locked:             2:      1
+
+# Verify that T0 is unboosted
+W: unlocked:           0:      1
+T: priolt:             0:      1
+
+# Unlock everything and exit
+C: unlock:             2:      1
+W: unlocked:           2:      1
+
+C: unlock:             0:      0
+W: unlocked:           0:      0
+
diff --git a/scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst b/scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst
new file mode 100644 (file)
index 0000000..e6ec0c8
--- /dev/null
@@ -0,0 +1,183 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 5 threads 4 lock PI - modify priority of blocked threads
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      81
+C: schedfifo:          2:      82
+C: schedfifo:          3:      83
+C: schedfifo:          4:      84
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L1
+C: locknowait:         1:      1
+W: locked:             1:      1
+
+# T1 lock L0
+C: lockintnowait:      1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      81
+
+# T2 lock L2
+C: locknowait:         2:      2
+W: locked:             2:      2
+
+# T2 lock L1
+C: lockintnowait:      2:      1
+W: blocked:            2:      1
+T: prioeq:             0:      82
+T: prioeq:             1:      82
+
+# T3 lock L3
+C: locknowait:         3:      3
+W: locked:             3:      3
+
+# T3 lock L2
+C: lockintnowait:      3:      2
+W: blocked:            3:      2
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+
+# T4 lock L3
+C: lockintnowait:      4:      3
+W: blocked:            4:      3
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+
+# Reduce prio of T4
+C: schedfifo:          4:      80
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+T: prioeq:             3:      83
+T: prioeq:             4:      80
+
+# Increase prio of T4
+C: schedfifo:          4:      84
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+T: prioeq:             4:      84
+
+# Reduce prio of T3
+C: schedfifo:          3:      80
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+T: prioeq:             4:      84
+
+# Increase prio of T3
+C: schedfifo:          3:      85
+T: prioeq:             0:      85
+T: prioeq:             1:      85
+T: prioeq:             2:      85
+T: prioeq:             3:      85
+T: prioeq:             4:      84
+
+# Reduce prio of T3
+C: schedfifo:          3:      83
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+T: prioeq:             4:      84
+
+# Signal T4
+C: signal:             4:      0
+W: unlocked:           4:      3
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+T: prioeq:             3:      83
+
+# Signal T3
+C: signal:             3:      0
+W: unlocked:           3:      2
+T: prioeq:             0:      82
+T: prioeq:             1:      82
+T: prioeq:             2:      82
+
+# Signal T2
+C: signal:             2:      0
+W: unlocked:           2:      1
+T: prioeq:             0:      81
+T: prioeq:             1:      81
+
+# Signal T1
+C: signal:             1:      0
+W: unlocked:           1:      0
+T: priolt:             0:      1
+
+# Unlock and exit
+C: unlock:             3:      3
+C: unlock:             2:      2
+C: unlock:             1:      1
+C: unlock:             0:      0
+
+W: unlocked:           3:      3
+W: unlocked:           2:      2
+W: unlocked:           1:      1
+W: unlocked:           0:      0
+
diff --git a/scripts/rt-tester/t5-l4-pi-boost-deboost.tst b/scripts/rt-tester/t5-l4-pi-boost-deboost.tst
new file mode 100644 (file)
index 0000000..ca64f8b
--- /dev/null
@@ -0,0 +1,143 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 5 threads 4 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      81
+C: schedfifo:          2:      82
+C: schedfifo:          3:      83
+C: schedfifo:          4:      84
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L1
+C: locknowait:         1:      1
+W: locked:             1:      1
+
+# T1 lock L0
+C: lockintnowait:      1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      81
+
+# T2 lock L2
+C: locknowait:         2:      2
+W: locked:             2:      2
+
+# T2 lock L1
+C: lockintnowait:      2:      1
+W: blocked:            2:      1
+T: prioeq:             0:      82
+T: prioeq:             1:      82
+
+# T3 lock L3
+C: locknowait:         3:      3
+W: locked:             3:      3
+
+# T3 lock L2
+C: lockintnowait:      3:      2
+W: blocked:            3:      2
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+
+# T4 lock L3
+C: lockintnowait:      4:      3
+W: blocked:            4:      3
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+
+# Signal T4
+C: signal:             4:      0
+W: unlocked:           4:      3
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+T: prioeq:             3:      83
+
+# Signal T3
+C: signal:             3:      0
+W: unlocked:           3:      2
+T: prioeq:             0:      82
+T: prioeq:             1:      82
+T: prioeq:             2:      82
+
+# Signal T2
+C: signal:             2:      0
+W: unlocked:           2:      1
+T: prioeq:             0:      81
+T: prioeq:             1:      81
+
+# Signal T1
+C: signal:             1:      0
+W: unlocked:           1:      0
+T: priolt:             0:      1
+
+# Unlock and exit
+C: unlock:             3:      3
+C: unlock:             2:      2
+C: unlock:             1:      1
+C: unlock:             0:      0
+
+W: unlocked:           3:      3
+W: unlocked:           2:      2
+W: unlocked:           1:      1
+W: unlocked:           0:      0
+
index 3c2877f0663ebc6f60d5a9585ff985df52a502f5..1bb416f4bbcef7aa9315e9efcb59d292389ee8b2 100644 (file)
@@ -99,6 +99,7 @@ extern int install_process_keyring(struct task_struct *tsk);
 extern struct key *request_key_and_link(struct key_type *type,
                                        const char *description,
                                        const char *callout_info,
+                                       void *aux,
                                        struct key *dest_keyring,
                                        unsigned long flags);
 
index 43295ca37b5dcb7b3461dc16645513a6df84ecf8..80de8c3e9cc3ea49c79e6525b0ce17b22076ac3e 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/poison.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/security.h>
@@ -988,7 +989,7 @@ void unregister_key_type(struct key_type *ktype)
                if (key->type == ktype) {
                        if (ktype->destroy)
                                ktype->destroy(key);
-                       memset(&key->payload, 0xbd, sizeof(key->payload));
+                       memset(&key->payload, KEY_DESTROY, sizeof(key->payload));
                }
        }
 
index 329411cf8768ef6e8e90f387e35a65d2f3194782..d9ca15c109ccfaa167cafc8c39dec87f2a3e305d 100644 (file)
@@ -183,7 +183,7 @@ asmlinkage long sys_request_key(const char __user *_type,
        }
 
        /* do the search */
-       key = request_key_and_link(ktype, description, callout_info,
+       key = request_key_and_link(ktype, description, callout_info, NULL,
                                   key_ref_to_ptr(dest_ref),
                                   KEY_ALLOC_IN_QUOTA);
        if (IS_ERR(key)) {
index 58d1efd4fc2c66788788edcc2e5d90bd32e1dc10..f573ac189a0a6595b2184b43a9d54c3b01e0d5a0 100644 (file)
@@ -1,6 +1,6 @@
 /* request_key.c: request a key from userspace
  *
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -33,7 +33,8 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
  */
 static int call_sbin_request_key(struct key *key,
                                 struct key *authkey,
-                                const char *op)
+                                const char *op,
+                                void *aux)
 {
        struct task_struct *tsk = current;
        key_serial_t prkey, sskey;
@@ -127,6 +128,7 @@ error_alloc:
 static struct key *__request_key_construction(struct key_type *type,
                                              const char *description,
                                              const char *callout_info,
+                                             void *aux,
                                              unsigned long flags)
 {
        request_key_actor_t actor;
@@ -164,7 +166,7 @@ static struct key *__request_key_construction(struct key_type *type,
        actor = call_sbin_request_key;
        if (type->request_key)
                actor = type->request_key;
-       ret = actor(key, authkey, "create");
+       ret = actor(key, authkey, "create", aux);
        if (ret < 0)
                goto request_failed;
 
@@ -258,8 +260,9 @@ alloc_failed:
  */
 static struct key *request_key_construction(struct key_type *type,
                                            const char *description,
-                                           struct key_user *user,
                                            const char *callout_info,
+                                           void *aux,
+                                           struct key_user *user,
                                            unsigned long flags)
 {
        struct key_construction *pcons;
@@ -284,7 +287,7 @@ static struct key *request_key_construction(struct key_type *type,
        }
 
        /* see about getting userspace to construct the key */
-       key = __request_key_construction(type, description, callout_info,
+       key = __request_key_construction(type, description, callout_info, aux,
                                         flags);
  error:
        kleave(" = %p", key);
@@ -392,6 +395,7 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
 struct key *request_key_and_link(struct key_type *type,
                                 const char *description,
                                 const char *callout_info,
+                                void *aux,
                                 struct key *dest_keyring,
                                 unsigned long flags)
 {
@@ -399,8 +403,9 @@ struct key *request_key_and_link(struct key_type *type,
        struct key *key;
        key_ref_t key_ref;
 
-       kenter("%s,%s,%s,%p,%lx",
-              type->name, description, callout_info, dest_keyring, flags);
+       kenter("%s,%s,%s,%p,%p,%lx",
+              type->name, description, callout_info, aux,
+              dest_keyring, flags);
 
        /* search all the process keyrings for a key */
        key_ref = search_process_keyrings(type, description, type->match,
@@ -433,8 +438,8 @@ struct key *request_key_and_link(struct key_type *type,
                        /* ask userspace (returns NULL if it waited on a key
                         * being constructed) */
                        key = request_key_construction(type, description,
-                                                      user, callout_info,
-                                                      flags);
+                                                      callout_info, aux,
+                                                      user, flags);
                        if (key)
                                break;
 
@@ -491,8 +496,27 @@ struct key *request_key(struct key_type *type,
                        const char *callout_info)
 {
        return request_key_and_link(type, description, callout_info, NULL,
-                                   KEY_ALLOC_IN_QUOTA);
+                                   NULL, KEY_ALLOC_IN_QUOTA);
 
 } /* end request_key() */
 
 EXPORT_SYMBOL(request_key);
+
+/*****************************************************************************/
+/*
+ * request a key with auxiliary data for the upcaller
+ * - search the process's keyrings
+ * - check the list of keys being created or updated
+ * - call out to userspace for a key if supplementary info was provided
+ */
+struct key *request_key_with_auxdata(struct key_type *type,
+                                    const char *description,
+                                    const char *callout_info,
+                                    void *aux)
+{
+       return request_key_and_link(type, description, callout_info, aux,
+                                   NULL, KEY_ALLOC_IN_QUOTA);
+
+} /* end request_key_with_auxdata() */
+
+EXPORT_SYMBOL(request_key_with_auxdata);
index ac7f2b2e39240024a70cfe06b464e93050447410..28832e689800b9c9250b54cc4c0be918adebb51d 100644 (file)
@@ -1532,8 +1532,9 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        /* Default to the current task SID. */
        bsec->sid = tsec->sid;
 
-       /* Reset create and sockcreate SID on execve. */
+       /* Reset fs, key, and sock SIDs on execve. */
        tsec->create_sid = 0;
+       tsec->keycreate_sid = 0;
        tsec->sockcreate_sid = 0;
 
        if (tsec->exec_sid) {
@@ -2586,9 +2587,10 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
        tsec2->osid = tsec1->osid;
        tsec2->sid = tsec1->sid;
 
-       /* Retain the exec, create, and sock SIDs across fork */
+       /* Retain the exec, fs, key, and sock SIDs across fork */
        tsec2->exec_sid = tsec1->exec_sid;
        tsec2->create_sid = tsec1->create_sid;
+       tsec2->keycreate_sid = tsec1->keycreate_sid;
        tsec2->sockcreate_sid = tsec1->sockcreate_sid;
 
        /* Retain ptracer SID across fork, if any.
index 5f22d70fefc0fa114a7f9b12814f8c7a6b31b41e..6b18225672c7ae6227a8ebb206c9aaf6460cee00 100644 (file)
@@ -779,8 +779,9 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
        strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
        strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
        snprintf(card->longname, sizeof(card->longname),
-                "%s at 0x%08lx, irq %d",
-                card->shortname, dev->res.start, dev->irq[0]);
+                "%s at 0x%016llx, irq %d",
+                card->shortname, (unsigned long long)dev->res.start,
+                dev->irq[0]);
 
        aaci = card->private_data;
        mutex_init(&aaci->ac97_sem);
index d3cbbb04758231940d21f2d43a2caa7bddf164cd..8b80024968be7d32f32e0b15fdfe5c1e6352425e 100644 (file)
@@ -160,8 +160,9 @@ static int __devinit snd_mpu401_pnp(int dev, struct pnp_dev *device,
                return -ENODEV;
        }
        if (pnp_port_len(device, 0) < IO_EXTENT) {
-               snd_printk(KERN_ERR "PnP port length is %ld, expected %d\n",
-                          pnp_port_len(device, 0), IO_EXTENT);
+               snd_printk(KERN_ERR "PnP port length is %llu, expected %d\n",
+                          (unsigned long long)pnp_port_len(device, 0),
+                          IO_EXTENT);
                return -ENODEV;
        }
        port[dev] = pnp_port_start(device, 0);
index e6945db8ed1b8a2fcd4b877712b96db8ff791c98..af60b0bc8115f59986b0be019adc050f8695f0cc 100644 (file)
@@ -2088,7 +2088,8 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
                kfree(cfg);
                return -EAGAIN;
        }
-       snd_printdd("pnp: port=0x%lx\n", pnp_port_start(acard->devc, 0));
+       snd_printdd("pnp: port=0x%llx\n",
+                       (unsigned long long)pnp_port_start(acard->devc, 0));
        /* PnP initialization */
        pdev = acard->dev;
        pnp_init_resource_table(cfg);
index 866300f2acbbd930cda9d0c92217919b1be58faa..c1c86e0fa56df0056b7a18cb2586fc5a7dd13242 100644 (file)
@@ -611,10 +611,10 @@ static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
        if (dma2[dev] >= 0)
                dma2[dev] = pnp_dma(pdev, 1);
        irq[dev] = pnp_irq(pdev, 0);
-       snd_printdd("isapnp IW: sb port=0x%lx, gf1 port=0x%lx, codec port=0x%lx\n",
-                               pnp_port_start(pdev, 0),
-                               pnp_port_start(pdev, 1),
-                               pnp_port_start(pdev, 2));
+       snd_printdd("isapnp IW: sb port=0x%llx, gf1 port=0x%llx, codec port=0x%llx\n",
+                       (unsigned long long)pnp_port_start(pdev, 0),
+                       (unsigned long long)pnp_port_start(pdev, 1),
+                       (unsigned long long)pnp_port_start(pdev, 2));
        snd_printdd("isapnp IW: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
 #ifdef SNDRV_STB
        /* Tone Control initialization */
index 7f7f05fa518afa78cd228b3f9a677215b74a873b..d64e67f2bafa3ef2537c03a703ff800d2b6ac8a8 100644 (file)
@@ -327,7 +327,8 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
                        goto __wt_error; 
                } 
                awe_port[dev] = pnp_port_start(pdev, 0);
-               snd_printdd("pnp SB16: wavetable port=0x%lx\n", pnp_port_start(pdev, 0));
+               snd_printdd("pnp SB16: wavetable port=0x%llx\n",
+                               (unsigned long long)pnp_port_start(pdev, 0));
        } else {
 __wt_error:
                if (pdev) {
index 3b8cdbca263665e53eca3f06b96c353912f6a218..f4980ca5c05c86d9f4cbd8c86c885f2bd35af09c 100644 (file)
@@ -493,6 +493,19 @@ config SOUND_CS4232
          See <file:Documentation/sound/oss/CS4232> for more information on
          configuring this card.
 
+config SOUND_SSCAPE
+       tristate "Ensoniq SoundScape support"
+       depends on SOUND_OSS
+       help
+         Answer Y if you have a sound card based on the Ensoniq SoundScape
+         chipset. Such cards are being manufactured at least by Ensoniq, Spea
+         and Reveal (Reveal makes also other cards).
+
+         If you compile the driver into the kernel, you have to add
+         "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command
+         line.
+
+
 config SOUND_VMIDI
        tristate "Loopback MIDI device support"
        depends on SOUND_OSS
index c7f86f09c28da1979a5c0e6de7cfde38fd1309d5..80f6c08e26e7fa73d40a9a8ee24e818d98e08355 100644 (file)
@@ -405,7 +405,7 @@ static const struct pnp_device_id cs4232_pnp_table[] = {
 
 MODULE_DEVICE_TABLE(pnp, cs4232_pnp_table);
 
-static int cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+static int __init cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
        struct address_info *isapnpcfg;
 
index 0294eec8ad9035ee621f516df74d692bab95faff..44e578098d76e77768ea6a872ff077eb5e89be85 100644 (file)
@@ -2035,8 +2035,9 @@ forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
        
        pci_set_drvdata (pci_dev, chip);
 
-       printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%04lX IRQ %u\n", 
-               chip->iobase, pci_resource_end (pci_dev, 0), chip->irq);
+       printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%16llX IRQ %u\n",
+               chip->iobase, (unsigned long long)pci_resource_end (pci_dev, 0),
+               chip->irq);
 
        /* Power it up */
        if ((ret = forte_chip_init (chip)) == 0)
index 1a921ee71aba2d567c5e48d186343905fa981550..29a6e0cff79f793557f9ee49d7dae200efbf2018 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
+#include <linux/poison.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
@@ -308,7 +309,7 @@ struct via_info {
        unsigned sixchannel: 1; /* 8233/35 with 6 channel support */
        unsigned volume: 1;
 
-       int locked_rate : 1;
+       unsigned locked_rate : 1;
        
        int mixer_vol;          /* 8233/35 volume  - not yet implemented */
 
@@ -3522,7 +3523,7 @@ err_out_have_mixer:
 
 err_out_kfree:
 #ifndef VIA_NDEBUG
-       memset (card, 0xAB, sizeof (*card)); /* poison memory */
+       memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
 #endif
        kfree (card);
 
@@ -3559,7 +3560,7 @@ static void __devexit via_remove_one (struct pci_dev *pdev)
        via_ac97_cleanup (card);
 
 #ifndef VIA_NDEBUG
-       memset (card, 0xAB, sizeof (*card)); /* poison memory */
+       memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
 #endif
        kfree (card);
 
index c33642d8d9a11e37e56e762b3342e4d660b8ae5c..497ed6b200608e8331fb3dd42656ebe05dca6c1d 100644 (file)
@@ -888,8 +888,9 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci,
 
        strcpy(card->driver, "Bt87x");
        sprintf(card->shortname, "Brooktree Bt%x", pci->device);
-       sprintf(card->longname, "%s at %#lx, irq %i",
-               card->shortname, pci_resource_start(pci, 0), chip->irq);
+       sprintf(card->longname, "%s at %#llx, irq %i",
+               card->shortname, (unsigned long long)pci_resource_start(pci, 0),
+               chip->irq);
        strcpy(card->mixername, "Bt87x");
 
        err = snd_card_register(card);
index dcf4029483474bd3790b6ef45e7e71d434491d8b..e5511606af04e9e58ff4b91f26a05aba41d20fba 100644 (file)
@@ -1441,10 +1441,10 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci,
 
        strcpy(card->driver, "SonicVibes");
        strcpy(card->shortname, "S3 SonicVibes");
-       sprintf(card->longname, "%s rev %i at 0x%lx, irq %i",
+       sprintf(card->longname, "%s rev %i at 0x%llx, irq %i",
                card->shortname,
                sonic->revision,
-               pci_resource_start(pci, 1),
+               (unsigned long long)pci_resource_start(pci, 1),
                sonic->irq);
 
        if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) {
index b678814975c9e1dd93297033966a527172ec8b28..be98f63773392af7e9afa04c748acffc5d5c8b94 100644 (file)
@@ -1170,9 +1170,10 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
                                               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);
+                                      " %d (%s: 0x%016lx:%016lx)\n",
+                                      i, rnames[i],
+                                      (unsigned long long)chip->rsrc[i].start,
+                                      (unsigned long long)chip->rsrc[i].end);
                                err = -ENODEV;
                                goto __error;
                        }
@@ -1201,9 +1202,10 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
                                               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);
+                                      " %d (%s: 0x%016llx:%016llx)\n",
+                                      i, rnames[i],
+                                      (unsigned long long)chip->rsrc[i].start,
+                                      (unsigned long long)chip->rsrc[i].end);
                                err = -ENODEV;
                                goto __error;
                        }
diff --git a/sound/ppc/toonie.c b/sound/ppc/toonie.c
deleted file mode 100644 (file)
index e69de29..0000000
index da54d04a3e3a4a9af73dd32d9689c808d77edba3..d9d14c2707dbf922a622b5889b9c2b78af74068b 100644 (file)
@@ -2037,10 +2037,10 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
        if (err)
                return err;
 
-       sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d",
+       sprintf(card->longname, "%s at 0x%02lx:0x%016lx, irq %d",
                card->shortname,
                rp->flags & 0xffL,
-               rp->start,
+               (unsigned long long)rp->start,
                sdev->irqs[0]);
 
        if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) {
index 5eecdd09a79ddd91a3345eb92f7a82303d474a3e..a7489a3dd75ac4f68fc328f128332e760a77a28f 100644 (file)
@@ -2645,9 +2645,9 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
        strcpy(card->driver, "DBRI");
        strcpy(card->shortname, "Sun DBRI");
        rp = &sdev->resource[0];
-       sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d",
+       sprintf(card->longname, "%s at 0x%02lx:0x%016lx, irq %d",
                card->shortname,
-               rp->flags & 0xffL, rp->start, irq.pri);
+               rp->flags & 0xffL, (unsigned long long)rp->start, irq.pri);
 
        if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) {
                snd_card_free(card);